mcp-proxy-adapter 3.1.5__py3-none-any.whl → 4.0.0__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.
- mcp_proxy_adapter/api/app.py +86 -27
- mcp_proxy_adapter/api/handlers.py +1 -1
- mcp_proxy_adapter/api/middleware/error_handling.py +11 -10
- mcp_proxy_adapter/api/tool_integration.py +5 -2
- mcp_proxy_adapter/api/tools.py +3 -3
- mcp_proxy_adapter/commands/base.py +19 -1
- mcp_proxy_adapter/commands/command_registry.py +258 -6
- mcp_proxy_adapter/commands/help_command.py +54 -65
- mcp_proxy_adapter/commands/hooks.py +260 -0
- mcp_proxy_adapter/commands/reload_command.py +211 -0
- mcp_proxy_adapter/commands/reload_settings_command.py +125 -0
- mcp_proxy_adapter/commands/settings_command.py +189 -0
- mcp_proxy_adapter/config.py +16 -1
- mcp_proxy_adapter/core/__init__.py +44 -0
- mcp_proxy_adapter/core/logging.py +87 -34
- mcp_proxy_adapter/core/settings.py +376 -0
- mcp_proxy_adapter/core/utils.py +2 -2
- mcp_proxy_adapter/custom_openapi.py +81 -2
- mcp_proxy_adapter/examples/README.md +124 -0
- mcp_proxy_adapter/examples/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_server/README.md +60 -0
- mcp_proxy_adapter/examples/basic_server/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +39 -0
- mcp_proxy_adapter/examples/basic_server/config.json +35 -0
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +238 -0
- mcp_proxy_adapter/examples/basic_server/server.py +98 -0
- mcp_proxy_adapter/examples/custom_commands/README.md +127 -0
- mcp_proxy_adapter/examples/custom_commands/__init__.py +27 -0
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +250 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +6 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +111 -0
- mcp_proxy_adapter/examples/custom_commands/config.json +62 -0
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +169 -0
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +215 -0
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +76 -0
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +96 -0
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +241 -0
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +135 -0
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +122 -0
- mcp_proxy_adapter/examples/custom_commands/hooks.py +230 -0
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +123 -0
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/server.py +223 -0
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +176 -0
- mcp_proxy_adapter/examples/deployment/README.md +49 -0
- mcp_proxy_adapter/examples/deployment/__init__.py +7 -0
- mcp_proxy_adapter/examples/deployment/config.development.json +8 -0
- {examples/basic_example → mcp_proxy_adapter/examples/deployment}/config.json +11 -7
- mcp_proxy_adapter/examples/deployment/config.production.json +12 -0
- mcp_proxy_adapter/examples/deployment/config.staging.json +11 -0
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +31 -0
- mcp_proxy_adapter/examples/deployment/run.sh +43 -0
- mcp_proxy_adapter/examples/deployment/run_docker.sh +84 -0
- mcp_proxy_adapter/openapi.py +3 -2
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +617 -0
- mcp_proxy_adapter/tests/api/test_handlers.py +522 -0
- mcp_proxy_adapter/tests/api/test_schemas.py +546 -0
- mcp_proxy_adapter/tests/api/test_tool_integration.py +531 -0
- mcp_proxy_adapter/tests/commands/test_help_command.py +8 -5
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +4 -5
- mcp_proxy_adapter/tests/test_command_registry.py +37 -1
- mcp_proxy_adapter/tests/unit/test_base_command.py +391 -85
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-4.0.0.dist-info/RECORD +110 -0
- {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/WHEEL +1 -1
- {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/top_level.txt +0 -1
- examples/__init__.py +0 -19
- examples/anti_patterns/README.md +0 -51
- examples/anti_patterns/__init__.py +0 -9
- examples/anti_patterns/bad_design/README.md +0 -72
- examples/anti_patterns/bad_design/global_state.py +0 -170
- examples/anti_patterns/bad_design/monolithic_command.py +0 -272
- examples/basic_example/README.md +0 -245
- examples/basic_example/__init__.py +0 -8
- examples/basic_example/commands/__init__.py +0 -5
- examples/basic_example/commands/echo_command.py +0 -95
- examples/basic_example/commands/math_command.py +0 -151
- examples/basic_example/commands/time_command.py +0 -152
- examples/basic_example/docs/EN/README.md +0 -177
- examples/basic_example/docs/RU/README.md +0 -177
- examples/basic_example/server.py +0 -151
- examples/basic_example/tests/conftest.py +0 -243
- examples/check_vstl_schema.py +0 -106
- examples/commands/echo_command.py +0 -52
- examples/commands/echo_command_di.py +0 -152
- examples/commands/echo_result.py +0 -65
- examples/commands/get_date_command.py +0 -98
- examples/commands/new_uuid4_command.py +0 -91
- examples/complete_example/Dockerfile +0 -24
- examples/complete_example/README.md +0 -92
- examples/complete_example/__init__.py +0 -8
- examples/complete_example/commands/__init__.py +0 -5
- examples/complete_example/commands/system_command.py +0 -328
- examples/complete_example/config.json +0 -41
- examples/complete_example/configs/config.dev.yaml +0 -40
- examples/complete_example/configs/config.docker.yaml +0 -40
- examples/complete_example/docker-compose.yml +0 -35
- examples/complete_example/requirements.txt +0 -20
- examples/complete_example/server.py +0 -113
- examples/di_example/.pytest_cache/README.md +0 -8
- examples/di_example/server.py +0 -249
- examples/fix_vstl_help.py +0 -123
- examples/minimal_example/README.md +0 -65
- examples/minimal_example/__init__.py +0 -8
- examples/minimal_example/config.json +0 -14
- examples/minimal_example/main.py +0 -136
- examples/minimal_example/simple_server.py +0 -163
- examples/minimal_example/tests/conftest.py +0 -171
- examples/minimal_example/tests/test_hello_command.py +0 -111
- examples/minimal_example/tests/test_integration.py +0 -181
- examples/patch_vstl_service.py +0 -105
- examples/patch_vstl_service_mcp.py +0 -108
- examples/server.py +0 -69
- examples/simple_server.py +0 -128
- examples/test_package_3.1.4.py +0 -177
- examples/test_server.py +0 -134
- examples/tool_description_example.py +0 -82
- mcp_proxy_adapter/py.typed +0 -0
- mcp_proxy_adapter-3.1.5.dist-info/RECORD +0 -118
- {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,376 @@
|
|
1
|
+
"""
|
2
|
+
Settings management for the MCP Proxy Adapter framework.
|
3
|
+
Provides utilities for reading and managing framework settings from configuration.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from typing import Any, Dict, Optional, Union
|
7
|
+
from mcp_proxy_adapter.config import config
|
8
|
+
|
9
|
+
|
10
|
+
class Settings:
|
11
|
+
"""
|
12
|
+
Settings management class for the framework.
|
13
|
+
Provides easy access to configuration values with type conversion and validation.
|
14
|
+
"""
|
15
|
+
|
16
|
+
# Store custom settings as a class variable
|
17
|
+
_custom_settings: Dict[str, Any] = {}
|
18
|
+
|
19
|
+
@classmethod
|
20
|
+
def add_custom_settings(cls, settings: Dict[str, Any]) -> None:
|
21
|
+
"""
|
22
|
+
Add custom settings to the settings manager.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
settings: Dictionary with custom settings
|
26
|
+
"""
|
27
|
+
cls._custom_settings.update(settings)
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
def get_custom_settings(cls) -> Dict[str, Any]:
|
31
|
+
"""
|
32
|
+
Get all custom settings.
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
Dictionary with all custom settings
|
36
|
+
"""
|
37
|
+
return cls._custom_settings.copy()
|
38
|
+
|
39
|
+
@classmethod
|
40
|
+
def get_custom_setting_value(cls, key: str, default: Any = None) -> Any:
|
41
|
+
"""
|
42
|
+
Get custom setting value.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
key: Setting key
|
46
|
+
default: Default value if key not found
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
Setting value
|
50
|
+
"""
|
51
|
+
return cls._custom_settings.get(key, default)
|
52
|
+
|
53
|
+
@classmethod
|
54
|
+
def set_custom_setting_value(cls, key: str, value: Any) -> None:
|
55
|
+
"""
|
56
|
+
Set custom setting value.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
key: Setting key
|
60
|
+
value: Value to set
|
61
|
+
"""
|
62
|
+
cls._custom_settings[key] = value
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def clear_custom_settings(cls) -> None:
|
66
|
+
"""
|
67
|
+
Clear all custom settings.
|
68
|
+
"""
|
69
|
+
cls._custom_settings.clear()
|
70
|
+
|
71
|
+
@staticmethod
|
72
|
+
def get_server_settings() -> Dict[str, Any]:
|
73
|
+
"""
|
74
|
+
Get server configuration settings.
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
Dictionary with server settings
|
78
|
+
"""
|
79
|
+
return {
|
80
|
+
"host": config.get("server.host", "0.0.0.0"),
|
81
|
+
"port": config.get("server.port", 8000),
|
82
|
+
"debug": config.get("server.debug", False),
|
83
|
+
"log_level": config.get("server.log_level", "INFO")
|
84
|
+
}
|
85
|
+
|
86
|
+
@staticmethod
|
87
|
+
def get_logging_settings() -> Dict[str, Any]:
|
88
|
+
"""
|
89
|
+
Get logging configuration settings.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Dictionary with logging settings
|
93
|
+
"""
|
94
|
+
return {
|
95
|
+
"level": config.get("logging.level", "INFO"),
|
96
|
+
"file": config.get("logging.file"),
|
97
|
+
"log_dir": config.get("logging.log_dir", "./logs"),
|
98
|
+
"log_file": config.get("logging.log_file", "mcp_proxy_adapter.log"),
|
99
|
+
"error_log_file": config.get("logging.error_log_file", "mcp_proxy_adapter_error.log"),
|
100
|
+
"access_log_file": config.get("logging.access_log_file", "mcp_proxy_adapter_access.log"),
|
101
|
+
"max_file_size": config.get("logging.max_file_size", "10MB"),
|
102
|
+
"backup_count": config.get("logging.backup_count", 5),
|
103
|
+
"format": config.get("logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"),
|
104
|
+
"date_format": config.get("logging.date_format", "%Y-%m-%d %H:%M:%S"),
|
105
|
+
"console_output": config.get("logging.console_output", True),
|
106
|
+
"file_output": config.get("logging.file_output", True)
|
107
|
+
}
|
108
|
+
|
109
|
+
@staticmethod
|
110
|
+
def get_commands_settings() -> Dict[str, Any]:
|
111
|
+
"""
|
112
|
+
Get commands configuration settings.
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
Dictionary with commands settings
|
116
|
+
"""
|
117
|
+
return {
|
118
|
+
"auto_discovery": config.get("commands.auto_discovery", True),
|
119
|
+
"discovery_path": config.get("commands.discovery_path", "mcp_proxy_adapter.commands"),
|
120
|
+
"custom_commands_path": config.get("commands.custom_commands_path")
|
121
|
+
}
|
122
|
+
|
123
|
+
@staticmethod
|
124
|
+
def get_custom_setting(key: str, default: Any = None) -> Any:
|
125
|
+
"""
|
126
|
+
Get custom setting from configuration.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
key: Configuration key in dot notation (e.g., "custom.feature_enabled")
|
130
|
+
default: Default value if key not found
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
Configuration value
|
134
|
+
"""
|
135
|
+
return config.get(key, default)
|
136
|
+
|
137
|
+
@staticmethod
|
138
|
+
def get_all_settings() -> Dict[str, Any]:
|
139
|
+
"""
|
140
|
+
Get all configuration settings including custom settings.
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
Dictionary with all configuration settings
|
144
|
+
"""
|
145
|
+
all_settings = config.get_all()
|
146
|
+
all_settings['custom_settings'] = Settings._custom_settings
|
147
|
+
return all_settings
|
148
|
+
|
149
|
+
@staticmethod
|
150
|
+
def set_custom_setting(key: str, value: Any) -> None:
|
151
|
+
"""
|
152
|
+
Set custom setting in configuration.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
key: Configuration key in dot notation
|
156
|
+
value: Value to set
|
157
|
+
"""
|
158
|
+
config.set(key, value)
|
159
|
+
|
160
|
+
@staticmethod
|
161
|
+
def reload_config() -> None:
|
162
|
+
"""
|
163
|
+
Reload configuration from file and environment variables.
|
164
|
+
"""
|
165
|
+
config.load_config()
|
166
|
+
|
167
|
+
|
168
|
+
class ServerSettings:
|
169
|
+
"""
|
170
|
+
Server-specific settings helper.
|
171
|
+
"""
|
172
|
+
|
173
|
+
@staticmethod
|
174
|
+
def get_host() -> str:
|
175
|
+
"""Get server host."""
|
176
|
+
return config.get("server.host", "0.0.0.0")
|
177
|
+
|
178
|
+
@staticmethod
|
179
|
+
def get_port() -> int:
|
180
|
+
"""Get server port."""
|
181
|
+
return config.get("server.port", 8000)
|
182
|
+
|
183
|
+
@staticmethod
|
184
|
+
def get_debug() -> bool:
|
185
|
+
"""Get debug mode."""
|
186
|
+
return config.get("server.debug", False)
|
187
|
+
|
188
|
+
@staticmethod
|
189
|
+
def get_log_level() -> str:
|
190
|
+
"""Get log level."""
|
191
|
+
return config.get("server.log_level", "INFO")
|
192
|
+
|
193
|
+
|
194
|
+
class LoggingSettings:
|
195
|
+
"""
|
196
|
+
Logging-specific settings helper.
|
197
|
+
"""
|
198
|
+
|
199
|
+
@staticmethod
|
200
|
+
def get_level() -> str:
|
201
|
+
"""Get logging level."""
|
202
|
+
return config.get("logging.level", "INFO")
|
203
|
+
|
204
|
+
@staticmethod
|
205
|
+
def get_log_dir() -> str:
|
206
|
+
"""Get log directory."""
|
207
|
+
return config.get("logging.log_dir", "./logs")
|
208
|
+
|
209
|
+
@staticmethod
|
210
|
+
def get_log_file() -> Optional[str]:
|
211
|
+
"""Get main log file name."""
|
212
|
+
return config.get("logging.log_file", "mcp_proxy_adapter.log")
|
213
|
+
|
214
|
+
@staticmethod
|
215
|
+
def get_error_log_file() -> Optional[str]:
|
216
|
+
"""Get error log file name."""
|
217
|
+
return config.get("logging.error_log_file", "mcp_proxy_adapter_error.log")
|
218
|
+
|
219
|
+
@staticmethod
|
220
|
+
def get_access_log_file() -> Optional[str]:
|
221
|
+
"""Get access log file name."""
|
222
|
+
return config.get("logging.access_log_file", "mcp_proxy_adapter_access.log")
|
223
|
+
|
224
|
+
@staticmethod
|
225
|
+
def get_max_file_size() -> str:
|
226
|
+
"""Get max file size."""
|
227
|
+
return config.get("logging.max_file_size", "10MB")
|
228
|
+
|
229
|
+
@staticmethod
|
230
|
+
def get_backup_count() -> int:
|
231
|
+
"""Get backup count."""
|
232
|
+
return config.get("logging.backup_count", 5)
|
233
|
+
|
234
|
+
@staticmethod
|
235
|
+
def get_format() -> str:
|
236
|
+
"""Get log format."""
|
237
|
+
return config.get("logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
238
|
+
|
239
|
+
@staticmethod
|
240
|
+
def get_date_format() -> str:
|
241
|
+
"""Get date format."""
|
242
|
+
return config.get("logging.date_format", "%Y-%m-%d %H:%M:%S")
|
243
|
+
|
244
|
+
@staticmethod
|
245
|
+
def get_console_output() -> bool:
|
246
|
+
"""Get console output setting."""
|
247
|
+
return config.get("logging.console_output", True)
|
248
|
+
|
249
|
+
@staticmethod
|
250
|
+
def get_file_output() -> bool:
|
251
|
+
"""Get file output setting."""
|
252
|
+
return config.get("logging.file_output", True)
|
253
|
+
|
254
|
+
|
255
|
+
class CommandsSettings:
|
256
|
+
"""
|
257
|
+
Commands-specific settings helper.
|
258
|
+
"""
|
259
|
+
|
260
|
+
@staticmethod
|
261
|
+
def get_auto_discovery() -> bool:
|
262
|
+
"""Get auto discovery setting."""
|
263
|
+
return config.get("commands.auto_discovery", True)
|
264
|
+
|
265
|
+
@staticmethod
|
266
|
+
def get_discovery_path() -> str:
|
267
|
+
"""Get discovery path."""
|
268
|
+
return config.get("commands.discovery_path", "mcp_proxy_adapter.commands")
|
269
|
+
|
270
|
+
@staticmethod
|
271
|
+
def get_custom_commands_path() -> Optional[str]:
|
272
|
+
"""Get custom commands path."""
|
273
|
+
return config.get("commands.custom_commands_path")
|
274
|
+
|
275
|
+
|
276
|
+
# Convenience functions for easy access
|
277
|
+
def get_server_host() -> str:
|
278
|
+
"""Get server host."""
|
279
|
+
return ServerSettings.get_host()
|
280
|
+
|
281
|
+
|
282
|
+
def get_server_port() -> int:
|
283
|
+
"""Get server port."""
|
284
|
+
return ServerSettings.get_port()
|
285
|
+
|
286
|
+
|
287
|
+
def get_server_debug() -> bool:
|
288
|
+
"""Get server debug mode."""
|
289
|
+
return ServerSettings.get_debug()
|
290
|
+
|
291
|
+
|
292
|
+
def get_logging_level() -> str:
|
293
|
+
"""Get logging level."""
|
294
|
+
return LoggingSettings.get_level()
|
295
|
+
|
296
|
+
|
297
|
+
def get_logging_dir() -> str:
|
298
|
+
"""Get logging directory."""
|
299
|
+
return LoggingSettings.get_log_dir()
|
300
|
+
|
301
|
+
|
302
|
+
def get_auto_discovery() -> bool:
|
303
|
+
"""Get auto discovery setting."""
|
304
|
+
return CommandsSettings.get_auto_discovery()
|
305
|
+
|
306
|
+
|
307
|
+
def get_discovery_path() -> str:
|
308
|
+
"""Get discovery path."""
|
309
|
+
return CommandsSettings.get_discovery_path()
|
310
|
+
|
311
|
+
|
312
|
+
def get_setting(key: str, default: Any = None) -> Any:
|
313
|
+
"""Get any setting by key."""
|
314
|
+
return Settings.get_custom_setting(key, default)
|
315
|
+
|
316
|
+
|
317
|
+
def set_setting(key: str, value: Any) -> None:
|
318
|
+
"""Set any setting by key."""
|
319
|
+
Settings.set_custom_setting(key, value)
|
320
|
+
|
321
|
+
|
322
|
+
def reload_settings() -> None:
|
323
|
+
"""Reload all settings from configuration."""
|
324
|
+
Settings.reload_config()
|
325
|
+
|
326
|
+
|
327
|
+
def add_custom_settings(settings: Dict[str, Any]) -> None:
|
328
|
+
"""
|
329
|
+
Add custom settings to the settings manager.
|
330
|
+
|
331
|
+
Args:
|
332
|
+
settings: Dictionary with custom settings
|
333
|
+
"""
|
334
|
+
Settings.add_custom_settings(settings)
|
335
|
+
|
336
|
+
|
337
|
+
def get_custom_settings() -> Dict[str, Any]:
|
338
|
+
"""
|
339
|
+
Get all custom settings.
|
340
|
+
|
341
|
+
Returns:
|
342
|
+
Dictionary with all custom settings
|
343
|
+
"""
|
344
|
+
return Settings.get_custom_settings()
|
345
|
+
|
346
|
+
|
347
|
+
def get_custom_setting_value(key: str, default: Any = None) -> Any:
|
348
|
+
"""
|
349
|
+
Get custom setting value.
|
350
|
+
|
351
|
+
Args:
|
352
|
+
key: Setting key
|
353
|
+
default: Default value if key not found
|
354
|
+
|
355
|
+
Returns:
|
356
|
+
Setting value
|
357
|
+
"""
|
358
|
+
return Settings.get_custom_setting_value(key, default)
|
359
|
+
|
360
|
+
|
361
|
+
def set_custom_setting_value(key: str, value: Any) -> None:
|
362
|
+
"""
|
363
|
+
Set custom setting value.
|
364
|
+
|
365
|
+
Args:
|
366
|
+
key: Setting key
|
367
|
+
value: Value to set
|
368
|
+
"""
|
369
|
+
Settings.set_custom_setting_value(key, value)
|
370
|
+
|
371
|
+
|
372
|
+
def clear_custom_settings() -> None:
|
373
|
+
"""
|
374
|
+
Clear all custom settings.
|
375
|
+
"""
|
376
|
+
Settings.clear_custom_settings()
|
mcp_proxy_adapter/core/utils.py
CHANGED
@@ -8,7 +8,7 @@ import os
|
|
8
8
|
import sys
|
9
9
|
import time
|
10
10
|
import uuid
|
11
|
-
from datetime import datetime
|
11
|
+
from datetime import datetime, timezone
|
12
12
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
13
13
|
|
14
14
|
from mcp_proxy_adapter.core.logging import logger
|
@@ -45,7 +45,7 @@ def format_datetime(dt: Optional[datetime] = None, format_str: str = "%Y-%m-%dT%
|
|
45
45
|
Returns:
|
46
46
|
Formatted date/time string.
|
47
47
|
"""
|
48
|
-
dt = dt or datetime.
|
48
|
+
dt = dt or datetime.now(timezone.utc)
|
49
49
|
return dt.strftime(format_str)
|
50
50
|
|
51
51
|
|
@@ -4,7 +4,7 @@ Custom OpenAPI schema generator for MCP Microservice compatible with MCP-Proxy.
|
|
4
4
|
import json
|
5
5
|
from copy import deepcopy
|
6
6
|
from pathlib import Path
|
7
|
-
from typing import Any, Dict, List, Optional, Set, Type
|
7
|
+
from typing import Any, Dict, List, Optional, Set, Type, Callable
|
8
8
|
|
9
9
|
from fastapi import FastAPI
|
10
10
|
from fastapi.openapi.utils import get_openapi
|
@@ -55,6 +55,15 @@ class CustomOpenAPIGenerator:
|
|
55
55
|
# Get all commands from the registry
|
56
56
|
commands = registry.get_all_commands()
|
57
57
|
|
58
|
+
# Ensure CommandRequest exists in schemas
|
59
|
+
if "CommandRequest" not in schema["components"]["schemas"]:
|
60
|
+
schema["components"]["schemas"]["CommandRequest"] = {
|
61
|
+
"properties": {
|
62
|
+
"command": {"type": "string", "enum": []},
|
63
|
+
"params": {"type": "object", "oneOf": []}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
58
67
|
# Add command names to the CommandRequest enum
|
59
68
|
schema["components"]["schemas"]["CommandRequest"]["properties"]["command"]["enum"] = [
|
60
69
|
cmd for cmd in commands.keys()
|
@@ -284,4 +293,74 @@ def custom_openapi(app: FastAPI) -> Dict[str, Any]:
|
|
284
293
|
# Cache the schema
|
285
294
|
app.openapi_schema = openapi_schema
|
286
295
|
|
287
|
-
return openapi_schema
|
296
|
+
return openapi_schema
|
297
|
+
|
298
|
+
|
299
|
+
# Registry for custom OpenAPI generators
|
300
|
+
_openapi_generators: Dict[str, Callable] = {}
|
301
|
+
|
302
|
+
|
303
|
+
def register_openapi_generator(name: str, generator_func: Callable[[FastAPI], Dict[str, Any]]) -> None:
|
304
|
+
"""
|
305
|
+
Register a custom OpenAPI generator.
|
306
|
+
|
307
|
+
Args:
|
308
|
+
name: Generator name.
|
309
|
+
generator_func: Function that generates OpenAPI schema.
|
310
|
+
"""
|
311
|
+
_openapi_generators[name] = generator_func
|
312
|
+
logger.info(f"Registered custom OpenAPI generator: {name}")
|
313
|
+
|
314
|
+
|
315
|
+
def get_openapi_generator(name: str) -> Optional[Callable[[FastAPI], Dict[str, Any]]]:
|
316
|
+
"""
|
317
|
+
Get a custom OpenAPI generator by name.
|
318
|
+
|
319
|
+
Args:
|
320
|
+
name: Generator name.
|
321
|
+
|
322
|
+
Returns:
|
323
|
+
Generator function or None if not found.
|
324
|
+
"""
|
325
|
+
return _openapi_generators.get(name)
|
326
|
+
|
327
|
+
|
328
|
+
def list_openapi_generators() -> List[str]:
|
329
|
+
"""
|
330
|
+
Get list of registered OpenAPI generators.
|
331
|
+
|
332
|
+
Returns:
|
333
|
+
List of generator names.
|
334
|
+
"""
|
335
|
+
return list(_openapi_generators.keys())
|
336
|
+
|
337
|
+
|
338
|
+
def custom_openapi_with_fallback(app: FastAPI) -> Dict[str, Any]:
|
339
|
+
"""
|
340
|
+
EN:
|
341
|
+
Create a custom OpenAPI schema for the FastAPI application.
|
342
|
+
Checks for custom generators first, then falls back to default generator.
|
343
|
+
Passes app's title, description, and version to the generator.
|
344
|
+
|
345
|
+
RU:
|
346
|
+
Создаёт кастомную OpenAPI-схему для FastAPI-приложения.
|
347
|
+
Сначала проверяет наличие кастомных генераторов, затем использует встроенный генератор.
|
348
|
+
Передаёт параметры title, description и version из приложения в генератор схемы.
|
349
|
+
|
350
|
+
Args:
|
351
|
+
app: The FastAPI application / FastAPI-приложение
|
352
|
+
|
353
|
+
Returns:
|
354
|
+
Dict containing the custom OpenAPI schema / Словарь с кастомной OpenAPI-схемой
|
355
|
+
"""
|
356
|
+
# Check if there are any custom generators
|
357
|
+
if _openapi_generators:
|
358
|
+
# Use the first registered generator
|
359
|
+
generator_name = list(_openapi_generators.keys())[0]
|
360
|
+
generator_func = _openapi_generators[generator_name]
|
361
|
+
logger.info(f"Using custom OpenAPI generator: {generator_name}")
|
362
|
+
return generator_func(app)
|
363
|
+
|
364
|
+
# Fall back to default generator
|
365
|
+
logger.info("Using default OpenAPI generator")
|
366
|
+
return custom_openapi(app)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# MCP Proxy Adapter Examples
|
2
|
+
|
3
|
+
This directory contains examples demonstrating different usage patterns of the MCP Proxy Adapter framework.
|
4
|
+
|
5
|
+
## Examples Overview
|
6
|
+
|
7
|
+
### 1. Basic Server (`basic_server/`)
|
8
|
+
Minimal server example with only built-in commands. Demonstrates:
|
9
|
+
- Basic framework setup
|
10
|
+
- Built-in command discovery
|
11
|
+
- Standard JSON-RPC API
|
12
|
+
- Backward compatibility with property setting
|
13
|
+
|
14
|
+
### 2. Custom Commands Server (`custom_commands/`)
|
15
|
+
Advanced server example with custom commands and hooks. Demonstrates:
|
16
|
+
- Custom command registration
|
17
|
+
- Basic hooks (before/after execution)
|
18
|
+
- Global hooks
|
19
|
+
- Performance and security monitoring
|
20
|
+
- Advanced hooks with data transformation and command interception
|
21
|
+
|
22
|
+
## Setting Application Title and Description
|
23
|
+
|
24
|
+
The framework supports two ways to set application properties:
|
25
|
+
|
26
|
+
### Method 1: During Creation (Recommended)
|
27
|
+
```python
|
28
|
+
from mcp_proxy_adapter import create_app
|
29
|
+
|
30
|
+
app = create_app(
|
31
|
+
title="My Custom Server",
|
32
|
+
description="My custom server description",
|
33
|
+
version="2.0.0"
|
34
|
+
)
|
35
|
+
```
|
36
|
+
|
37
|
+
### Method 2: After Creation (Backward Compatible)
|
38
|
+
```python
|
39
|
+
from mcp_proxy_adapter import create_app
|
40
|
+
|
41
|
+
app = create_app()
|
42
|
+
|
43
|
+
# Set properties after creation
|
44
|
+
app.set_properties(
|
45
|
+
new_title="My Custom Server",
|
46
|
+
new_description="My custom server description",
|
47
|
+
new_version="2.0.0"
|
48
|
+
)
|
49
|
+
```
|
50
|
+
|
51
|
+
## Running Examples
|
52
|
+
|
53
|
+
### Basic Server
|
54
|
+
```bash
|
55
|
+
cd mcp_proxy_adapter/examples/basic_server
|
56
|
+
python server.py
|
57
|
+
```
|
58
|
+
|
59
|
+
### Custom Commands Server
|
60
|
+
```bash
|
61
|
+
cd mcp_proxy_adapter/examples/custom_commands
|
62
|
+
python server.py
|
63
|
+
```
|
64
|
+
|
65
|
+
## Testing Examples
|
66
|
+
|
67
|
+
### Basic Server Commands
|
68
|
+
```bash
|
69
|
+
# Get help
|
70
|
+
curl -X POST http://localhost:8000/cmd \
|
71
|
+
-H "Content-Type: application/json" \
|
72
|
+
-d '{"jsonrpc": "2.0", "method": "help", "id": 1}'
|
73
|
+
|
74
|
+
# Get health
|
75
|
+
curl -X POST http://localhost:8000/cmd \
|
76
|
+
-H "Content-Type: application/json" \
|
77
|
+
-d '{"jsonrpc": "2.0", "method": "health", "id": 2}'
|
78
|
+
```
|
79
|
+
|
80
|
+
### Custom Commands Server Commands
|
81
|
+
```bash
|
82
|
+
# Test echo command
|
83
|
+
curl -X POST http://localhost:8000/cmd \
|
84
|
+
-H "Content-Type: application/json" \
|
85
|
+
-d '{"jsonrpc": "2.0", "method": "echo", "params": {"message": "Hello!"}, "id": 1}'
|
86
|
+
|
87
|
+
# Test data transformation
|
88
|
+
curl -X POST http://localhost:8000/cmd \
|
89
|
+
-H "Content-Type: application/json" \
|
90
|
+
-d '{"jsonrpc": "2.0", "method": "data_transform", "params": {"data": {"name": "test", "value": 123}}, "id": 2}'
|
91
|
+
|
92
|
+
# Test command interception (bypass_flag=0)
|
93
|
+
curl -X POST http://localhost:8000/cmd \
|
94
|
+
-H "Content-Type: application/json" \
|
95
|
+
-d '{"jsonrpc": "2.0", "method": "intercept", "params": {"bypass_flag": 0}, "id": 3}'
|
96
|
+
|
97
|
+
# Test command execution (bypass_flag=1)
|
98
|
+
curl -X POST http://localhost:8000/cmd \
|
99
|
+
-H "Content-Type: application/json" \
|
100
|
+
-d '{"jsonrpc": "2.0", "method": "intercept", "params": {"bypass_flag": 1}, "id": 4}'
|
101
|
+
```
|
102
|
+
|
103
|
+
## Features Demonstrated
|
104
|
+
|
105
|
+
### Basic Server
|
106
|
+
- ✅ Standard JSON-RPC API
|
107
|
+
- ✅ Built-in command discovery
|
108
|
+
- ✅ Basic logging
|
109
|
+
- ✅ OpenAPI schema generation
|
110
|
+
- ✅ Backward compatibility
|
111
|
+
|
112
|
+
### Custom Commands Server
|
113
|
+
- ✅ Custom command registration
|
114
|
+
- ✅ Command override with priority
|
115
|
+
- ✅ Basic hooks (before/after)
|
116
|
+
- ✅ Global hooks
|
117
|
+
- ✅ Performance monitoring
|
118
|
+
- ✅ Security monitoring
|
119
|
+
- ✅ Data transformation hooks
|
120
|
+
- ✅ Command interception hooks
|
121
|
+
- ✅ Conditional processing
|
122
|
+
- ✅ Smart interception
|
123
|
+
- ✅ Centralized logging
|
124
|
+
- ✅ Advanced error handling
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Basic Server Example
|
2
|
+
|
3
|
+
A minimal example of MCP Proxy Adapter server without additional commands.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
This example demonstrates:
|
8
|
+
- Basic server setup
|
9
|
+
- Built-in commands only (help, health)
|
10
|
+
- Default configuration
|
11
|
+
- No custom commands
|
12
|
+
|
13
|
+
## Available Commands
|
14
|
+
|
15
|
+
- `help` - Get information about available commands
|
16
|
+
- `health` - Get server health status
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### Run the server
|
21
|
+
|
22
|
+
```bash
|
23
|
+
python server.py
|
24
|
+
```
|
25
|
+
|
26
|
+
### Test the server
|
27
|
+
|
28
|
+
```bash
|
29
|
+
# Get help
|
30
|
+
curl -X POST http://localhost:8000/cmd \
|
31
|
+
-H "Content-Type: application/json" \
|
32
|
+
-d '{"command": "help"}'
|
33
|
+
|
34
|
+
# Get health status
|
35
|
+
curl -X POST http://localhost:8000/cmd \
|
36
|
+
-H "Content-Type: application/json" \
|
37
|
+
-d '{"command": "health"}'
|
38
|
+
```
|
39
|
+
|
40
|
+
## API Endpoints
|
41
|
+
|
42
|
+
- `POST /cmd` - Execute commands
|
43
|
+
- `GET /health` - Health check
|
44
|
+
- `GET /commands` - List available commands
|
45
|
+
- `GET /docs` - API documentation
|
46
|
+
|
47
|
+
## Configuration
|
48
|
+
|
49
|
+
The server uses default configuration. You can customize it by:
|
50
|
+
|
51
|
+
1. Creating a `config.json` file
|
52
|
+
2. Setting environment variables
|
53
|
+
3. Passing configuration to `create_app()`
|
54
|
+
|
55
|
+
## Notes
|
56
|
+
|
57
|
+
- This is the simplest possible setup
|
58
|
+
- No custom commands are registered
|
59
|
+
- Uses framework defaults
|
60
|
+
- Good starting point for understanding the framework
|