helping-geek-mcp 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- helping_geek_mcp/__init__.py +11 -0
- helping_geek_mcp/config/README.md +12 -0
- helping_geek_mcp/config/__init__.py +7 -0
- helping_geek_mcp/config/config_manager.py +79 -0
- helping_geek_mcp/config/sample_config.json +18 -0
- helping_geek_mcp/prompts/__init__.py +5 -0
- helping_geek_mcp/prompts/errors.py +28 -0
- helping_geek_mcp/py.typed +0 -0
- helping_geek_mcp/server.py +197 -0
- helping_geek_mcp/services/__init__.py +5 -0
- helping_geek_mcp/services/basic_service.py +43 -0
- helping_geek_mcp/static/templates/sample.txt +10 -0
- helping_geek_mcp/tools/__init__.py +5 -0
- helping_geek_mcp/utils/__init__.py +9 -0
- helping_geek_mcp/utils/constants.py +46 -0
- helping_geek_mcp/utils/data_processor.py +115 -0
- helping_geek_mcp/utils/string_helper.py +73 -0
- helping_geek_mcp/utils/template_manager.py +88 -0
- helping_geek_mcp-0.0.1.dist-info/METADATA +154 -0
- helping_geek_mcp-0.0.1.dist-info/RECORD +23 -0
- helping_geek_mcp-0.0.1.dist-info/WHEEL +5 -0
- helping_geek_mcp-0.0.1.dist-info/entry_points.txt +2 -0
- helping_geek_mcp-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Configuration Files
|
|
2
|
+
|
|
3
|
+
This directory contains configuration files for the Helping Geek MCP server.
|
|
4
|
+
|
|
5
|
+
## Files
|
|
6
|
+
|
|
7
|
+
- `config_manager.py`: Main configuration management class
|
|
8
|
+
- `sample_config.json`: Sample configuration with default settings
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
The configuration manager provides basic key-value storage for server settings.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic configuration manager for sample MCP server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConfigManager:
|
|
11
|
+
"""
|
|
12
|
+
Manages configuration settings for the MCP server.
|
|
13
|
+
This is a simplified demonstration version.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, base_dir: Optional[Path] = None):
|
|
17
|
+
"""
|
|
18
|
+
Initialize the configuration manager.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
base_dir: Base directory for configuration files
|
|
22
|
+
"""
|
|
23
|
+
self.base_dir = base_dir or Path.home() / ".helping_geek_mcp"
|
|
24
|
+
self.config_file = self.base_dir / "config" / "settings.json"
|
|
25
|
+
self._config = self._load_default_config()
|
|
26
|
+
|
|
27
|
+
def _load_default_config(self) -> dict:
|
|
28
|
+
"""Load default configuration."""
|
|
29
|
+
return {
|
|
30
|
+
"version": "0.0.1",
|
|
31
|
+
"server_name": "Helping Geek MCP",
|
|
32
|
+
"author": "helpinggeek1234@gmail.com",
|
|
33
|
+
"timeout": 60,
|
|
34
|
+
"max_retries": 3
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
38
|
+
"""
|
|
39
|
+
Get a configuration value.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
key: Configuration key
|
|
43
|
+
default: Default value if key not found
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Configuration value
|
|
47
|
+
"""
|
|
48
|
+
return self._config.get(key, default)
|
|
49
|
+
|
|
50
|
+
def set(self, key: str, value: Any) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Set a configuration value.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
key: Configuration key
|
|
56
|
+
value: Configuration value
|
|
57
|
+
"""
|
|
58
|
+
self._config[key] = value
|
|
59
|
+
|
|
60
|
+
def get_all_settings(self) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Get all settings as JSON string.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
JSON string of all settings
|
|
66
|
+
"""
|
|
67
|
+
return json.dumps(self._config, indent=2)
|
|
68
|
+
|
|
69
|
+
def save(self) -> None:
|
|
70
|
+
"""Save configuration to file."""
|
|
71
|
+
self.config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
with open(self.config_file, 'w') as f:
|
|
73
|
+
json.dump(self._config, f, indent=2)
|
|
74
|
+
|
|
75
|
+
def load(self) -> None:
|
|
76
|
+
"""Load configuration from file."""
|
|
77
|
+
if self.config_file.exists():
|
|
78
|
+
with open(self.config_file, 'r') as f:
|
|
79
|
+
self._config = json.load(f)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"name": "Helping Geek MCP",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"author": "helpinggeek1234@gmail.com"
|
|
6
|
+
},
|
|
7
|
+
"settings": {
|
|
8
|
+
"timeout": 60,
|
|
9
|
+
"max_retries": 3,
|
|
10
|
+
"cache_enabled": true,
|
|
11
|
+
"log_level": "INFO"
|
|
12
|
+
},
|
|
13
|
+
"features": {
|
|
14
|
+
"text_processing": true,
|
|
15
|
+
"data_transformation": true,
|
|
16
|
+
"template_support": true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sample error definitions for the MCP server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ServerError(Exception):
|
|
7
|
+
"""Base exception for server errors."""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConfigurationError(ServerError):
|
|
12
|
+
"""Configuration-related errors."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProcessingError(ServerError):
|
|
17
|
+
"""Data processing errors."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TemplateError(ServerError):
|
|
22
|
+
"""Template-related errors."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ValidationError(ServerError):
|
|
27
|
+
"""Input validation errors."""
|
|
28
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
MCP Python Server - Basic Sample Implementation
|
|
4
|
+
|
|
5
|
+
This is a sample server demonstrating the Model Context Protocol (MCP) structure.
|
|
6
|
+
It contains basic functions and utilities for educational purposes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from mcp.server.fastmcp import FastMCP
|
|
14
|
+
|
|
15
|
+
# Import basic utilities
|
|
16
|
+
from helping_geek_mcp.utils.string_helper import StringHelper
|
|
17
|
+
from helping_geek_mcp.utils.data_processor import DataProcessor
|
|
18
|
+
from helping_geek_mcp.utils.template_manager import TemplateManager
|
|
19
|
+
from helping_geek_mcp.config import ConfigManager
|
|
20
|
+
|
|
21
|
+
# Module-level logger
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
# Base directory for data files
|
|
25
|
+
BASE_DIR: Optional[Path] = None
|
|
26
|
+
LOGGING_ENABLED: bool = False
|
|
27
|
+
|
|
28
|
+
# Manager instances
|
|
29
|
+
string_helper = StringHelper()
|
|
30
|
+
data_processor = DataProcessor()
|
|
31
|
+
template_manager = TemplateManager()
|
|
32
|
+
config_manager = ConfigManager()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def initialize_components():
|
|
36
|
+
"""
|
|
37
|
+
Initialize all components with BASE_DIR.
|
|
38
|
+
Sets up logging and creates all instances.
|
|
39
|
+
"""
|
|
40
|
+
global BASE_DIR, LOGGING_ENABLED, string_helper, data_processor, template_manager, config_manager
|
|
41
|
+
|
|
42
|
+
if LOGGING_ENABLED:
|
|
43
|
+
logger.info(f"Initializing components with BASE_DIR: {BASE_DIR}")
|
|
44
|
+
|
|
45
|
+
# Re-initialize with BASE_DIR if needed
|
|
46
|
+
string_helper = StringHelper()
|
|
47
|
+
data_processor = DataProcessor(base_dir=BASE_DIR)
|
|
48
|
+
template_manager = TemplateManager(base_dir=BASE_DIR)
|
|
49
|
+
config_manager = ConfigManager(base_dir=BASE_DIR)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def setup_logging(log_level: str = "INFO"):
|
|
53
|
+
"""
|
|
54
|
+
Configure logging for the server.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
|
|
58
|
+
"""
|
|
59
|
+
logging.basicConfig(
|
|
60
|
+
level=getattr(logging, log_level.upper()),
|
|
61
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
62
|
+
handlers=[
|
|
63
|
+
logging.StreamHandler(sys.stderr)
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Create FastMCP server instance
|
|
69
|
+
mcp = FastMCP("Helping Geek MCP")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@mcp.tool()
|
|
73
|
+
def process_text(text: str, operation: str = "uppercase") -> str:
|
|
74
|
+
"""
|
|
75
|
+
Process text with basic string operations.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
text: Input text to process
|
|
79
|
+
operation: Operation to perform (uppercase, lowercase, reverse, capitalize)
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Processed text string
|
|
83
|
+
"""
|
|
84
|
+
if not LOGGING_ENABLED:
|
|
85
|
+
initialize_components()
|
|
86
|
+
|
|
87
|
+
logger.info(f"Processing text with operation: {operation}")
|
|
88
|
+
return string_helper.process(text, operation)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@mcp.tool()
|
|
92
|
+
def transform_data(data: dict, format_type: str = "json") -> str:
|
|
93
|
+
"""
|
|
94
|
+
Transform data between different formats.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
data: Input data dictionary
|
|
98
|
+
format_type: Output format (json, xml, yaml)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Formatted data string
|
|
102
|
+
"""
|
|
103
|
+
if not LOGGING_ENABLED:
|
|
104
|
+
initialize_components()
|
|
105
|
+
|
|
106
|
+
logger.info(f"Transforming data to format: {format_type}")
|
|
107
|
+
return data_processor.transform(data, format_type)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@mcp.tool()
|
|
111
|
+
def get_template(template_name: str, variables: dict = None) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Get a template and optionally fill it with variables.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
template_name: Name of the template
|
|
117
|
+
variables: Variables to substitute in template
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Template content with variables substituted
|
|
121
|
+
"""
|
|
122
|
+
if not LOGGING_ENABLED:
|
|
123
|
+
initialize_components()
|
|
124
|
+
|
|
125
|
+
logger.info(f"Getting template: {template_name}")
|
|
126
|
+
return template_manager.get_template(template_name, variables or {})
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@mcp.tool()
|
|
130
|
+
def get_config(key: str) -> str:
|
|
131
|
+
"""
|
|
132
|
+
Get configuration value by key.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
key: Configuration key
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Configuration value
|
|
139
|
+
"""
|
|
140
|
+
if not LOGGING_ENABLED:
|
|
141
|
+
initialize_components()
|
|
142
|
+
|
|
143
|
+
logger.info(f"Getting config for key: {key}")
|
|
144
|
+
return config_manager.get(key)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@mcp.resource("config://settings")
|
|
148
|
+
def get_settings() -> str:
|
|
149
|
+
"""
|
|
150
|
+
Get current server settings.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Server settings as JSON string
|
|
154
|
+
"""
|
|
155
|
+
if not LOGGING_ENABLED:
|
|
156
|
+
initialize_components()
|
|
157
|
+
|
|
158
|
+
return config_manager.get_all_settings()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def main():
|
|
162
|
+
"""
|
|
163
|
+
Main entry point for the server.
|
|
164
|
+
"""
|
|
165
|
+
import argparse
|
|
166
|
+
|
|
167
|
+
parser = argparse.ArgumentParser(description="Helping Geek MCP Server")
|
|
168
|
+
parser.add_argument("command", nargs="?", default="start", help="Command to run")
|
|
169
|
+
parser.add_argument("--base-dir", type=str, help="Base directory for data files")
|
|
170
|
+
parser.add_argument("--log-level", type=str, default="INFO", help="Logging level")
|
|
171
|
+
parser.add_argument("--enable-logging", action="store_true", help="Enable logging")
|
|
172
|
+
|
|
173
|
+
args = parser.parse_args()
|
|
174
|
+
|
|
175
|
+
global BASE_DIR, LOGGING_ENABLED
|
|
176
|
+
|
|
177
|
+
if args.base_dir:
|
|
178
|
+
BASE_DIR = Path(args.base_dir)
|
|
179
|
+
|
|
180
|
+
LOGGING_ENABLED = args.enable_logging
|
|
181
|
+
|
|
182
|
+
if LOGGING_ENABLED:
|
|
183
|
+
setup_logging(args.log_level)
|
|
184
|
+
logger.info("Starting Helping Geek MCP Server")
|
|
185
|
+
|
|
186
|
+
if args.command == "start":
|
|
187
|
+
# Initialize components before starting server
|
|
188
|
+
initialize_components()
|
|
189
|
+
# Run the MCP server
|
|
190
|
+
mcp.run()
|
|
191
|
+
else:
|
|
192
|
+
print(f"Unknown command: {args.command}")
|
|
193
|
+
sys.exit(1)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if __name__ == "__main__":
|
|
197
|
+
main()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sample service for basic operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BasicService:
|
|
9
|
+
"""
|
|
10
|
+
A basic service demonstrating service structure.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
"""Initialize the service."""
|
|
15
|
+
self.name = "BasicService"
|
|
16
|
+
self.version = "0.0.1"
|
|
17
|
+
|
|
18
|
+
def execute(self, operation: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
19
|
+
"""
|
|
20
|
+
Execute a service operation.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
operation: Operation name
|
|
24
|
+
params: Operation parameters
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Operation result
|
|
28
|
+
"""
|
|
29
|
+
if operation == "echo":
|
|
30
|
+
return {"status": "success", "data": params}
|
|
31
|
+
elif operation == "status":
|
|
32
|
+
return {"status": "running", "service": self.name, "version": self.version}
|
|
33
|
+
else:
|
|
34
|
+
return {"status": "error", "message": f"Unknown operation: {operation}"}
|
|
35
|
+
|
|
36
|
+
def health_check(self) -> bool:
|
|
37
|
+
"""
|
|
38
|
+
Check service health.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
True if healthy
|
|
42
|
+
"""
|
|
43
|
+
return True
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility modules for Helping Geek MCP.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from helping_geek_mcp.utils.string_helper import StringHelper
|
|
6
|
+
from helping_geek_mcp.utils.data_processor import DataProcessor
|
|
7
|
+
from helping_geek_mcp.utils.template_manager import TemplateManager
|
|
8
|
+
|
|
9
|
+
__all__ = ["StringHelper", "DataProcessor", "TemplateManager"]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic constants for the MCP server.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ServerConstants:
|
|
9
|
+
"""Server-level constants."""
|
|
10
|
+
|
|
11
|
+
SERVER_NAME = "Helping Geek MCP"
|
|
12
|
+
VERSION = "0.0.1"
|
|
13
|
+
AUTHOR = "helpinggeek1234@gmail.com"
|
|
14
|
+
|
|
15
|
+
DEFAULT_TIMEOUT = 60
|
|
16
|
+
MAX_RETRIES = 3
|
|
17
|
+
|
|
18
|
+
# Default directories
|
|
19
|
+
DEFAULT_BASE_DIR = Path.home() / ".helping_geek_mcp"
|
|
20
|
+
CONFIG_DIR = "config"
|
|
21
|
+
STATIC_DIR = "static"
|
|
22
|
+
TEMPLATES_DIR = "static/templates"
|
|
23
|
+
LOGS_DIR = "logs"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ProcessingConstants:
|
|
27
|
+
"""Data processing constants."""
|
|
28
|
+
|
|
29
|
+
MAX_TEXT_LENGTH = 10000
|
|
30
|
+
DEFAULT_DELIMITER = " "
|
|
31
|
+
DEFAULT_SEPARATOR = " "
|
|
32
|
+
TRUNCATE_SUFFIX = "..."
|
|
33
|
+
|
|
34
|
+
SUPPORTED_FORMATS = ["json", "xml", "yaml"]
|
|
35
|
+
DEFAULT_FORMAT = "json"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TemplateConstants:
|
|
39
|
+
"""Template-related constants."""
|
|
40
|
+
|
|
41
|
+
DEFAULT_TEMPLATES = [
|
|
42
|
+
"greeting",
|
|
43
|
+
"notification",
|
|
44
|
+
"summary",
|
|
45
|
+
"error"
|
|
46
|
+
]
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic data processing utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DataProcessor:
|
|
11
|
+
"""
|
|
12
|
+
Simple data transformation helper for demonstration.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, base_dir: Optional[Path] = None):
|
|
16
|
+
"""
|
|
17
|
+
Initialize data processor.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
base_dir: Base directory for data files
|
|
21
|
+
"""
|
|
22
|
+
self.base_dir = base_dir or Path.home() / ".helping_geek_mcp"
|
|
23
|
+
|
|
24
|
+
def transform(self, data: dict, format_type: str = "json") -> str:
|
|
25
|
+
"""
|
|
26
|
+
Transform data to different format.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
data: Input data dictionary
|
|
30
|
+
format_type: Output format (json, xml, yaml)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Formatted data string
|
|
34
|
+
"""
|
|
35
|
+
if format_type == "json":
|
|
36
|
+
return self.to_json(data)
|
|
37
|
+
elif format_type == "xml":
|
|
38
|
+
return self.to_xml(data)
|
|
39
|
+
elif format_type == "yaml":
|
|
40
|
+
return self.to_yaml(data)
|
|
41
|
+
else:
|
|
42
|
+
return str(data)
|
|
43
|
+
|
|
44
|
+
def to_json(self, data: dict, indent: int = 2) -> str:
|
|
45
|
+
"""
|
|
46
|
+
Convert data to JSON.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
data: Input data
|
|
50
|
+
indent: Indentation spaces
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
JSON string
|
|
54
|
+
"""
|
|
55
|
+
return json.dumps(data, indent=indent)
|
|
56
|
+
|
|
57
|
+
def to_xml(self, data: dict, root_tag: str = "root") -> str:
|
|
58
|
+
"""
|
|
59
|
+
Convert data to simple XML format.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
data: Input data
|
|
63
|
+
root_tag: Root XML tag
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
XML string
|
|
67
|
+
"""
|
|
68
|
+
xml_parts = [f"<{root_tag}>"]
|
|
69
|
+
for key, value in data.items():
|
|
70
|
+
xml_parts.append(f" <{key}>{value}</{key}>")
|
|
71
|
+
xml_parts.append(f"</{root_tag}>")
|
|
72
|
+
return "\n".join(xml_parts)
|
|
73
|
+
|
|
74
|
+
def to_yaml(self, data: dict) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Convert data to simple YAML format.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
data: Input data
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
YAML-like string
|
|
83
|
+
"""
|
|
84
|
+
yaml_parts = []
|
|
85
|
+
for key, value in data.items():
|
|
86
|
+
yaml_parts.append(f"{key}: {value}")
|
|
87
|
+
return "\n".join(yaml_parts)
|
|
88
|
+
|
|
89
|
+
def filter_data(self, data: list, key: str, value: Any) -> list:
|
|
90
|
+
"""
|
|
91
|
+
Filter list of dictionaries by key-value pair.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
data: List of dictionaries
|
|
95
|
+
key: Key to filter by
|
|
96
|
+
value: Value to match
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Filtered list
|
|
100
|
+
"""
|
|
101
|
+
return [item for item in data if item.get(key) == value]
|
|
102
|
+
|
|
103
|
+
def sort_data(self, data: list, key: str, reverse: bool = False) -> list:
|
|
104
|
+
"""
|
|
105
|
+
Sort list of dictionaries by key.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
data: List of dictionaries
|
|
109
|
+
key: Key to sort by
|
|
110
|
+
reverse: Sort in reverse order
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Sorted list
|
|
114
|
+
"""
|
|
115
|
+
return sorted(data, key=lambda x: x.get(key, ""), reverse=reverse)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic string manipulation utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StringHelper:
|
|
7
|
+
"""
|
|
8
|
+
Simple string processing helper for demonstration.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def process(self, text: str, operation: str = "uppercase") -> str:
|
|
12
|
+
"""
|
|
13
|
+
Process text with basic operations.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
text: Input text
|
|
17
|
+
operation: Operation type (uppercase, lowercase, reverse, capitalize)
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Processed text
|
|
21
|
+
"""
|
|
22
|
+
if operation == "uppercase":
|
|
23
|
+
return text.upper()
|
|
24
|
+
elif operation == "lowercase":
|
|
25
|
+
return text.lower()
|
|
26
|
+
elif operation == "reverse":
|
|
27
|
+
return text[::-1]
|
|
28
|
+
elif operation == "capitalize":
|
|
29
|
+
return text.capitalize()
|
|
30
|
+
else:
|
|
31
|
+
return text
|
|
32
|
+
|
|
33
|
+
def split_text(self, text: str, delimiter: str = " ") -> list:
|
|
34
|
+
"""
|
|
35
|
+
Split text by delimiter.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
text: Input text
|
|
39
|
+
delimiter: Delimiter character
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of text segments
|
|
43
|
+
"""
|
|
44
|
+
return text.split(delimiter)
|
|
45
|
+
|
|
46
|
+
def join_text(self, segments: list, separator: str = " ") -> str:
|
|
47
|
+
"""
|
|
48
|
+
Join text segments.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
segments: List of text segments
|
|
52
|
+
separator: Separator character
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Joined text
|
|
56
|
+
"""
|
|
57
|
+
return separator.join(str(s) for s in segments)
|
|
58
|
+
|
|
59
|
+
def truncate(self, text: str, max_length: int = 100, suffix: str = "...") -> str:
|
|
60
|
+
"""
|
|
61
|
+
Truncate text to maximum length.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
text: Input text
|
|
65
|
+
max_length: Maximum length
|
|
66
|
+
suffix: Suffix to add when truncated
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Truncated text
|
|
70
|
+
"""
|
|
71
|
+
if len(text) <= max_length:
|
|
72
|
+
return text
|
|
73
|
+
return text[:max_length - len(suffix)] + suffix
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic template management utilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TemplateManager:
|
|
10
|
+
"""
|
|
11
|
+
Simple template manager for demonstration.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, base_dir: Optional[Path] = None):
|
|
15
|
+
"""
|
|
16
|
+
Initialize template manager.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
base_dir: Base directory for template files
|
|
20
|
+
"""
|
|
21
|
+
self.base_dir = base_dir or Path.home() / ".helping_geek_mcp"
|
|
22
|
+
self.templates_dir = self.base_dir / "static" / "templates"
|
|
23
|
+
self._templates = self._load_default_templates()
|
|
24
|
+
|
|
25
|
+
def _load_default_templates(self) -> Dict[str, str]:
|
|
26
|
+
"""Load default templates."""
|
|
27
|
+
return {
|
|
28
|
+
"greeting": "Hello, {name}! Welcome to {service}.",
|
|
29
|
+
"notification": "You have {count} new {item_type}.",
|
|
30
|
+
"summary": "Summary: {title}\nDate: {date}\nStatus: {status}",
|
|
31
|
+
"error": "Error occurred: {error_message}\nCode: {error_code}",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def get_template(self, template_name: str, variables: Dict[str, str] = None) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Get template and fill with variables.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
template_name: Name of the template
|
|
40
|
+
variables: Variables to substitute
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Filled template string
|
|
44
|
+
"""
|
|
45
|
+
template = self._templates.get(template_name, "Template not found: {template_name}")
|
|
46
|
+
|
|
47
|
+
if variables:
|
|
48
|
+
try:
|
|
49
|
+
return template.format(**variables)
|
|
50
|
+
except KeyError as e:
|
|
51
|
+
return f"Missing variable in template: {e}"
|
|
52
|
+
|
|
53
|
+
return template
|
|
54
|
+
|
|
55
|
+
def add_template(self, name: str, content: str) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Add a new template.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
name: Template name
|
|
61
|
+
content: Template content
|
|
62
|
+
"""
|
|
63
|
+
self._templates[name] = content
|
|
64
|
+
|
|
65
|
+
def list_templates(self) -> list:
|
|
66
|
+
"""
|
|
67
|
+
List all available templates.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
List of template names
|
|
71
|
+
"""
|
|
72
|
+
return list(self._templates.keys())
|
|
73
|
+
|
|
74
|
+
def render(self, content: str, variables: Dict[str, str]) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Render content with variables.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
content: Template content
|
|
80
|
+
variables: Variables to substitute
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Rendered content
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
return content.format(**variables)
|
|
87
|
+
except KeyError as e:
|
|
88
|
+
return f"Missing variable: {e}"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: helping-geek-mcp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Model Context Protocol (MCP) server providing basic demonstration of MCP tools and utilities
|
|
5
|
+
Author-email: Helping Geek <helpinggeek1234@gmail.com>
|
|
6
|
+
Maintainer-email: Helping Geek <helpinggeek1234@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/helpinggeek1234-droid/helping-geek-mcp
|
|
9
|
+
Project-URL: Documentation, https://github.com/helpinggeek1234-droid/helping-geek-mcp/blob/main/README.md
|
|
10
|
+
Project-URL: Repository, https://github.com/helpinggeek1234-droid/helping-geek-mcp
|
|
11
|
+
Project-URL: Issues, https://github.com/helpinggeek1234-droid/helping-geek-mcp/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/helpinggeek1234-droid/helping-geek-mcp/blob/main/python-server/CHANGELOG.md
|
|
13
|
+
Keywords: mcp,model-context-protocol,sample,demo,utilities
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: mcp>=1.0.0
|
|
26
|
+
Requires-Dist: requests>=2.31.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
32
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
33
|
+
Provides-Extra: test
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
|
|
37
|
+
|
|
38
|
+
# Helping Geek MCP Server
|
|
39
|
+
|
|
40
|
+
A sample Model Context Protocol (MCP) server demonstrating basic utilities and tools for educational purposes.
|
|
41
|
+
|
|
42
|
+
## What is This?
|
|
43
|
+
|
|
44
|
+
This is a demonstration MCP (Model Context Protocol) server created as a proof-of-concept for publishing Python packages to PyPI. It showcases the basic structure and components needed for an MCP server without containing production-level functionality.
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- **Basic String Operations**: Simple text manipulation utilities
|
|
49
|
+
- **Data Processing**: Basic data transformation functions
|
|
50
|
+
- **Template Management**: Simple template handling demonstrations
|
|
51
|
+
- **Configuration**: Example configuration management
|
|
52
|
+
|
|
53
|
+
This is a sample project designed for learning and testing the PyPI publishing workflow.
|
|
54
|
+
|
|
55
|
+
## Quick Setup
|
|
56
|
+
|
|
57
|
+
### 1. Install the Server
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install helping-geek-mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Configure Your AI Assistant
|
|
64
|
+
|
|
65
|
+
#### For Cline (VS Code Extension)
|
|
66
|
+
|
|
67
|
+
Add this to your Cline MCP settings:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"helping-geek-mcp": {
|
|
73
|
+
"timeout": 60,
|
|
74
|
+
"command": "helping-geek-mcp",
|
|
75
|
+
"args": ["start"],
|
|
76
|
+
"env": {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### For Claude Desktop
|
|
83
|
+
|
|
84
|
+
Add to `claude_desktop_config.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"helping-geek-mcp": {
|
|
90
|
+
"command": "helping-geek-mcp",
|
|
91
|
+
"args": ["start"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Development
|
|
98
|
+
|
|
99
|
+
### Install for Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/helpinggeek/helping-geek-mcp.git
|
|
103
|
+
cd helping-geek-mcp
|
|
104
|
+
pip install -e ".[dev]"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Run Tests
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pytest
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Build Package
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python -m build
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Publish to PyPI
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
twine upload dist/*
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Project Structure
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
python-server/
|
|
129
|
+
├── src/
|
|
130
|
+
│ └── helping_geek_mcp/
|
|
131
|
+
│ ├── server.py
|
|
132
|
+
│ ├── config/
|
|
133
|
+
│ ├── prompts/
|
|
134
|
+
│ ├── services/
|
|
135
|
+
│ ├── tools/
|
|
136
|
+
│ └── utils/
|
|
137
|
+
├── tests/
|
|
138
|
+
├── docs/
|
|
139
|
+
├── pyproject.toml
|
|
140
|
+
├── README.md
|
|
141
|
+
└── LICENSE
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT License - See LICENSE file for details
|
|
147
|
+
|
|
148
|
+
## Contact
|
|
149
|
+
|
|
150
|
+
For questions or feedback, reach out to helpinggeek1234@gmail.com
|
|
151
|
+
|
|
152
|
+
## Disclaimer
|
|
153
|
+
|
|
154
|
+
This is a sample project for educational purposes and PyPI publishing demonstration. Not intended for production use.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
helping_geek_mcp/__init__.py,sha256=X80RyKGR-VfR-HybpPaZ7gNHA21jvxEjzZmwp6-M3HY,226
|
|
2
|
+
helping_geek_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
helping_geek_mcp/server.py,sha256=8nS3iw3atGzm8X58V9GPxaAl7QxxXaTgWqoG2QrJIQk,5254
|
|
4
|
+
helping_geek_mcp/config/README.md,sha256=PMsfseUs8-xY4gIS6a_I35qZou9YQ1L8ze6MiomjiP0,328
|
|
5
|
+
helping_geek_mcp/config/__init__.py,sha256=qrx6vNnbGzLoQvqbyWUHHtPM7bbI_B9gKPPCm0tjXR4,146
|
|
6
|
+
helping_geek_mcp/config/config_manager.py,sha256=-g_rZlLNyFRxvKoLVW8Pv_HmtJwXD1P73DY07IunhJA,2235
|
|
7
|
+
helping_geek_mcp/config/sample_config.json,sha256=fN0Cagyp3yH_nqQXoMdg3a9QTKDaFLyv-NweTBcCIko,345
|
|
8
|
+
helping_geek_mcp/prompts/__init__.py,sha256=ljTXIqWz18uDAYUbHImJC1r30NZL4GNTA5T2kKu3xXc,59
|
|
9
|
+
helping_geek_mcp/prompts/errors.py,sha256=u1TFb73whYVuuIWOPKKSV1htkpem3wx2kR75Fd3mnMk,471
|
|
10
|
+
helping_geek_mcp/services/__init__.py,sha256=4KwoG1oNQu-esw1tQzoHCMQ5dsatWgK5QvdOLU2PEPs,60
|
|
11
|
+
helping_geek_mcp/services/basic_service.py,sha256=hB8wGnvntv0miP1h13zibXYK2tzOnoX2apX8UR9sj5s,1084
|
|
12
|
+
helping_geek_mcp/static/templates/sample.txt,sha256=fD0ZeV1o0tRFII3TCVF--hZJOcT_bhFBaC5i8usDx0A,169
|
|
13
|
+
helping_geek_mcp/tools/__init__.py,sha256=N2Bty0CSQ1PJyy8DJyvEA5OZRd2sp23MHqtK7GZco64,57
|
|
14
|
+
helping_geek_mcp/utils/__init__.py,sha256=23c036BT_QTMI6X5xiWmJq_6xyT_kq3Y1rn7ceHtMJc,305
|
|
15
|
+
helping_geek_mcp/utils/constants.py,sha256=2OY_JSI_2cgHlypaSx_ihw-Nzy9lpYPiCV4q6-qc6_s,930
|
|
16
|
+
helping_geek_mcp/utils/data_processor.py,sha256=L4bYVlGYRdnBhaSPEeK9J63I_P56d9_plARAcJPynmQ,3036
|
|
17
|
+
helping_geek_mcp/utils/string_helper.py,sha256=KiLEnYorrPeUey4tOjikMZ9uQmBVQGUQV1sViT7O8l8,1920
|
|
18
|
+
helping_geek_mcp/utils/template_manager.py,sha256=XKU1JnckY-lJ1xYWGaRdMvHEAQyChsL1RDrXH61fVsA,2556
|
|
19
|
+
helping_geek_mcp-0.0.1.dist-info/METADATA,sha256=wd7V18qIwRnuX5QiyrNDRYqpHHS1qVPXkF9UvQTsKVw,4091
|
|
20
|
+
helping_geek_mcp-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
21
|
+
helping_geek_mcp-0.0.1.dist-info/entry_points.txt,sha256=Ez5EyLKOgbpUNLTHBBQH8CATZ-TSoiNlbxdkFiXvcmo,66
|
|
22
|
+
helping_geek_mcp-0.0.1.dist-info/top_level.txt,sha256=wmRUAcn_-G8daG-y2-SlFZtsFeEzgRa8sHDR3Xj7UvE,17
|
|
23
|
+
helping_geek_mcp-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
helping_geek_mcp
|