mcp-proxy-adapter 2.0.2__tar.gz → 2.1.1__tar.gz
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-2.0.2 → mcp_proxy_adapter-2.1.1}/MANIFEST.in +0 -1
- {mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter.egg-info → mcp_proxy_adapter-2.1.1}/PKG-INFO +47 -13
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/README.md +43 -8
- mcp_proxy_adapter-2.1.1/examples/docstring_and_schema_example.py +60 -0
- mcp_proxy_adapter-2.1.1/examples/extension_example.py +60 -0
- mcp_proxy_adapter-2.1.1/examples/help_best_practices.py +67 -0
- mcp_proxy_adapter-2.1.1/examples/help_usage.py +64 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/examples/openapi_server.py +2 -2
- mcp_proxy_adapter-2.1.1/examples/project_structure_example.py +47 -0
- mcp_proxy_adapter-2.1.1/examples/testing_example.py +53 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/__init__.py +1 -1
- mcp_proxy_adapter-2.1.1/mcp_proxy_adapter/models.py +47 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1/mcp_proxy_adapter.egg-info}/PKG-INFO +47 -13
- mcp_proxy_adapter-2.1.1/mcp_proxy_adapter.egg-info/SOURCES.txt +68 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter.egg-info/requires.txt +1 -1
- mcp_proxy_adapter-2.1.1/mcp_proxy_adapter.egg-info/top_level.txt +7 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/pyproject.toml +13 -14
- mcp_proxy_adapter-2.1.1/requirements.txt +5 -0
- mcp_proxy_adapter-2.1.1/scripts/code_analyzer/code_analyzer.py +328 -0
- mcp_proxy_adapter-2.1.1/scripts/code_analyzer/register_commands.py +446 -0
- mcp_proxy_adapter-2.1.1/scripts/publish.py +85 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/setup.py +8 -8
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_adapter.py +10 -12
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_basic_dispatcher.py +1 -4
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_command_registry.py +3 -3
- mcp_proxy_adapter-2.1.1/tests/test_examples.py +32 -0
- mcp_proxy_adapter-2.1.1/tests/test_mcp_proxy_adapter.py +568 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_mcp_proxy_adapter_basic.py +13 -3
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_part2.py +12 -2
- mcp_proxy_adapter-2.0.2/requirements.txt +0 -10
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/adapters/__init__.py +0 -16
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/cli/__init__.py +0 -12
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/cli/__main__.py +0 -79
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/cli/command_runner.py +0 -233
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/generators/__init__.py +0 -14
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/generators/endpoint_generator.py +0 -172
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/generators/openapi_generator.py +0 -254
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/models.py +0 -47
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/openapi_schema/__init__.py +0 -38
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/openapi_schema/command_registry.py +0 -312
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/openapi_schema/rest_schema.py +0 -510
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/openapi_schema/rpc_generator.py +0 -307
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/openapi_schema/rpc_schema.py +0 -416
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/validators/__init__.py +0 -14
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter/validators/base_validator.py +0 -23
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter.egg-info/SOURCES.txt +0 -73
- mcp_proxy_adapter-2.0.2/src/mcp_proxy_adapter.egg-info/top_level.txt +0 -2
- mcp_proxy_adapter-2.0.2/tests/test_mcp_proxy_adapter.py +0 -320
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/LICENSE +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/code_index.yaml +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/README.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/README_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/architecture.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/architecture_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/command_development.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/command_development_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/deployment.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/deployment_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/examples.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/examples_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/mcp_proxy_adapter.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/mcp_proxy_adapter_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/quickstart.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/quickstart_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/testing.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/testing_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/docs/validation_ru.md +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/examples/analyze_config.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/examples/basic_integration.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/examples/mcp_proxy_client.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/examples/mcp_proxy_config.json +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/adapter.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/analyzers/__init__.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/analyzers/type_analyzer.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/dispatchers/__init__.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/registry.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/schema.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/validators/docstring_validator.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter/validators/metadata_validator.py +0 -0
- {mcp_proxy_adapter-2.0.2/src → mcp_proxy_adapter-2.1.1}/mcp_proxy_adapter.egg-info/dependency_links.txt +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/setup.cfg +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/conftest.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_adapter_coverage.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_part1.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_schema.py +0 -0
- {mcp_proxy_adapter-2.0.2 → mcp_proxy_adapter-2.1.1}/tests/test_simple_adapter.py +0 -0
@@ -1,15 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-proxy-adapter
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.1.1
|
4
4
|
Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
|
5
5
|
Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
|
6
6
|
Author: Vasiliy VZ
|
7
7
|
Author-email: Vasiliy VZ <vasilyvz@example.com>
|
8
8
|
License: MIT
|
9
9
|
Project-URL: Homepage, https://github.com/vasilyvz/mcp-proxy-adapter
|
10
|
-
Project-URL:
|
11
|
-
Project-URL: Documentation, https://github.com/vasilyvz/
|
12
|
-
Project-URL: Source, https://github.com/vasilyvz/mcp_proxy_adapter
|
10
|
+
Project-URL: Bug Tracker, https://github.com/vasilyvz/mcp-proxy-adapter/issues
|
11
|
+
Project-URL: Documentation, https://github.com/vasilyvz/mcp-proxy-adapter/tree/main/docs
|
13
12
|
Classifier: Development Status :: 4 - Beta
|
14
13
|
Classifier: Intended Audience :: Developers
|
15
14
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -22,7 +21,7 @@ Requires-Python: >=3.9, <4
|
|
22
21
|
Description-Content-Type: text/markdown
|
23
22
|
License-File: LICENSE
|
24
23
|
Requires-Dist: fastapi<1.0.0,>=0.95.0
|
25
|
-
Requires-Dist: pydantic
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
26
25
|
Requires-Dist: uvicorn<1.0.0,>=0.22.0
|
27
26
|
Requires-Dist: docstring-parser<1.0.0,>=0.15
|
28
27
|
Requires-Dist: typing-extensions<5.0.0,>=4.5.0
|
@@ -262,11 +261,46 @@ MIT
|
|
262
261
|
## Documentation
|
263
262
|
See [docs/](docs/) for detailed guides, architecture, and examples.
|
264
263
|
|
265
|
-
##
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
-
|
270
|
-
-
|
271
|
-
|
272
|
-
|
264
|
+
## 📦 Примеры (examples/)
|
265
|
+
|
266
|
+
- `help_usage.py` — базовое использование help-команды
|
267
|
+
- `help_best_practices.py` — best practices для help
|
268
|
+
- `project_structure_example.py` — структура проекта с MCPProxyAdapter
|
269
|
+
- `docstring_and_schema_example.py` — как документировать команды для схемы
|
270
|
+
- `testing_example.py` — как тестировать команды и интеграцию
|
271
|
+
- `extension_example.py` — как расширять и кастомизировать команды и help
|
272
|
+
|
273
|
+
## ✅ Чеклист для добавления новой команды
|
274
|
+
|
275
|
+
1. **Реализовать функцию-команду** с подробным docstring (EN)
|
276
|
+
2. **Добавить описание параметров** (type, description, required)
|
277
|
+
3. **Добавить описание возврата** (docstring, тип)
|
278
|
+
4. **Зарегистрировать команду** в registry/dispatcher
|
279
|
+
5. **Добавить описание в get_commands_info** (использовать docstring)
|
280
|
+
6. **Покрыть тестами** (unit/integration, edge-cases, ошибки)
|
281
|
+
7. **Добавить пример использования** в examples/
|
282
|
+
8. **Проверить интеграцию с help** (и с параметром, и без)
|
283
|
+
9. **Проверить генерацию схемы/OpenAPI**
|
284
|
+
10. **Документировать в README.md** (EN/RU)
|
285
|
+
|
286
|
+
## 📦 Examples (EN)
|
287
|
+
|
288
|
+
- `help_usage.py` — basic help command usage
|
289
|
+
- `help_best_practices.py` — best practices for help
|
290
|
+
- `project_structure_example.py` — project structure with MCPProxyAdapter
|
291
|
+
- `docstring_and_schema_example.py` — how to document commands for schema
|
292
|
+
- `testing_example.py` — how to test commands and integration
|
293
|
+
- `extension_example.py` — how to extend/customize commands and help
|
294
|
+
|
295
|
+
## ✅ Checklist for adding a new command
|
296
|
+
|
297
|
+
1. **Implement the command function** with detailed docstring (EN)
|
298
|
+
2. **Describe parameters** (type, description, required)
|
299
|
+
3. **Describe return value** (docstring, type)
|
300
|
+
4. **Register the command** in registry/dispatcher
|
301
|
+
5. **Add description to get_commands_info** (use docstring)
|
302
|
+
6. **Cover with tests** (unit/integration, edge-cases, errors)
|
303
|
+
7. **Add usage example** to examples/
|
304
|
+
8. **Check help integration** (with/without param)
|
305
|
+
9. **Check schema/OpenAPI generation**
|
306
|
+
10. **Document in README.md** (EN/RU)
|
@@ -229,11 +229,46 @@ MIT
|
|
229
229
|
## Documentation
|
230
230
|
See [docs/](docs/) for detailed guides, architecture, and examples.
|
231
231
|
|
232
|
-
##
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
-
|
237
|
-
-
|
238
|
-
|
239
|
-
|
232
|
+
## 📦 Примеры (examples/)
|
233
|
+
|
234
|
+
- `help_usage.py` — базовое использование help-команды
|
235
|
+
- `help_best_practices.py` — best practices для help
|
236
|
+
- `project_structure_example.py` — структура проекта с MCPProxyAdapter
|
237
|
+
- `docstring_and_schema_example.py` — как документировать команды для схемы
|
238
|
+
- `testing_example.py` — как тестировать команды и интеграцию
|
239
|
+
- `extension_example.py` — как расширять и кастомизировать команды и help
|
240
|
+
|
241
|
+
## ✅ Чеклист для добавления новой команды
|
242
|
+
|
243
|
+
1. **Реализовать функцию-команду** с подробным docstring (EN)
|
244
|
+
2. **Добавить описание параметров** (type, description, required)
|
245
|
+
3. **Добавить описание возврата** (docstring, тип)
|
246
|
+
4. **Зарегистрировать команду** в registry/dispatcher
|
247
|
+
5. **Добавить описание в get_commands_info** (использовать docstring)
|
248
|
+
6. **Покрыть тестами** (unit/integration, edge-cases, ошибки)
|
249
|
+
7. **Добавить пример использования** в examples/
|
250
|
+
8. **Проверить интеграцию с help** (и с параметром, и без)
|
251
|
+
9. **Проверить генерацию схемы/OpenAPI**
|
252
|
+
10. **Документировать в README.md** (EN/RU)
|
253
|
+
|
254
|
+
## 📦 Examples (EN)
|
255
|
+
|
256
|
+
- `help_usage.py` — basic help command usage
|
257
|
+
- `help_best_practices.py` — best practices for help
|
258
|
+
- `project_structure_example.py` — project structure with MCPProxyAdapter
|
259
|
+
- `docstring_and_schema_example.py` — how to document commands for schema
|
260
|
+
- `testing_example.py` — how to test commands and integration
|
261
|
+
- `extension_example.py` — how to extend/customize commands and help
|
262
|
+
|
263
|
+
## ✅ Checklist for adding a new command
|
264
|
+
|
265
|
+
1. **Implement the command function** with detailed docstring (EN)
|
266
|
+
2. **Describe parameters** (type, description, required)
|
267
|
+
3. **Describe return value** (docstring, type)
|
268
|
+
4. **Register the command** in registry/dispatcher
|
269
|
+
5. **Add description to get_commands_info** (use docstring)
|
270
|
+
6. **Cover with tests** (unit/integration, edge-cases, errors)
|
271
|
+
7. **Add usage example** to examples/
|
272
|
+
8. **Check help integration** (with/without param)
|
273
|
+
9. **Check schema/OpenAPI generation**
|
274
|
+
10. **Document in README.md** (EN/RU)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
"""
|
2
|
+
Docstring and Schema Example for MCPProxyAdapter
|
3
|
+
|
4
|
+
- How to write docstrings for commands
|
5
|
+
- How docstrings are used in OpenAPI/schema
|
6
|
+
- Best practices for documenting parameters and return values
|
7
|
+
|
8
|
+
Run:
|
9
|
+
python examples/docstring_and_schema_example.py
|
10
|
+
"""
|
11
|
+
import os
|
12
|
+
import sys
|
13
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
14
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
15
|
+
|
16
|
+
class MyRegistry:
|
17
|
+
def __init__(self):
|
18
|
+
self.dispatcher = self
|
19
|
+
self.commands = {"sum": self.sum_numbers}
|
20
|
+
self.commands_info = {
|
21
|
+
"sum": {
|
22
|
+
"description": self.sum_numbers.__doc__,
|
23
|
+
"params": {
|
24
|
+
"a": {"type": "integer", "description": "First number", "required": True},
|
25
|
+
"b": {"type": "integer", "description": "Second number", "required": True}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
def get_valid_commands(self):
|
30
|
+
return list(self.commands.keys())
|
31
|
+
def get_command_info(self, command):
|
32
|
+
return self.commands_info.get(command)
|
33
|
+
def get_commands_info(self):
|
34
|
+
return self.commands_info
|
35
|
+
def execute(self, command, **params):
|
36
|
+
if command == "sum":
|
37
|
+
return self.sum_numbers(**params)
|
38
|
+
raise KeyError(f"Unknown command: {command}")
|
39
|
+
def add_generator(self, generator):
|
40
|
+
pass
|
41
|
+
def sum_numbers(self, a: int, b: int) -> int:
|
42
|
+
"""
|
43
|
+
Returns the sum of two numbers.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
a (int): First number
|
47
|
+
b (int): Second number
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
int: The sum of a and b
|
51
|
+
"""
|
52
|
+
return a + b
|
53
|
+
|
54
|
+
if __name__ == "__main__":
|
55
|
+
registry = MyRegistry()
|
56
|
+
adapter = MCPProxyAdapter(registry)
|
57
|
+
# Print OpenAPI schema (simulated)
|
58
|
+
schema = adapter.generate_mcp_proxy_config()
|
59
|
+
print("=== Tool description from docstring ===")
|
60
|
+
print(schema.tools[0].description)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
"""
|
2
|
+
Extension Example for MCPProxyAdapter
|
3
|
+
|
4
|
+
- How to add custom commands
|
5
|
+
- How to extend help logic
|
6
|
+
- How to customize error handling
|
7
|
+
|
8
|
+
Run:
|
9
|
+
python examples/extension_example.py
|
10
|
+
"""
|
11
|
+
import os
|
12
|
+
import sys
|
13
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
14
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
15
|
+
|
16
|
+
class MyRegistry:
|
17
|
+
def __init__(self):
|
18
|
+
self.dispatcher = self
|
19
|
+
self.commands = {"ping": self.ping, "help": self.help_command}
|
20
|
+
self.commands_info = {
|
21
|
+
"ping": {"description": "Ping command (returns pong)", "params": {}},
|
22
|
+
"help": {"description": "Show help for commands", "params": {"command": {"type": "string", "description": "Command name", "required": False}}}
|
23
|
+
}
|
24
|
+
def get_valid_commands(self):
|
25
|
+
return list(self.commands.keys())
|
26
|
+
def get_command_info(self, command):
|
27
|
+
return self.commands_info.get(command)
|
28
|
+
def get_commands_info(self):
|
29
|
+
return self.commands_info
|
30
|
+
def execute(self, *args, **params):
|
31
|
+
if args:
|
32
|
+
command = args[0]
|
33
|
+
params = {k: v for k, v in params.items()}
|
34
|
+
else:
|
35
|
+
command = params.pop("command", None)
|
36
|
+
if command == "ping":
|
37
|
+
return self.ping()
|
38
|
+
if command == "help":
|
39
|
+
return self.help_command(**params)
|
40
|
+
raise KeyError(f"Unknown command: {command}")
|
41
|
+
def add_generator(self, generator):
|
42
|
+
pass
|
43
|
+
def ping(self):
|
44
|
+
"""Ping command."""
|
45
|
+
return {"result": "pong"}
|
46
|
+
def help_command(self, command: str = None):
|
47
|
+
"""Custom help logic: returns info for command or all commands."""
|
48
|
+
if not command:
|
49
|
+
return {"commands": list(self.commands_info.keys())}
|
50
|
+
if command in self.commands_info:
|
51
|
+
return {"command": command, "info": self.commands_info[command]}
|
52
|
+
return {"error": f"Command '{command}' not found"}
|
53
|
+
|
54
|
+
if __name__ == "__main__":
|
55
|
+
registry = MyRegistry()
|
56
|
+
adapter = MCPProxyAdapter(registry)
|
57
|
+
print("[EXT] Ping:", registry.execute("ping"))
|
58
|
+
print("[EXT] Help (all):", registry.execute("help"))
|
59
|
+
print("[EXT] Help (ping):", registry.execute("help", command="ping"))
|
60
|
+
print("[EXT] Help (notfound):", registry.execute("help", command="notfound"))
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"""
|
2
|
+
Best Practices: Integrating and Testing 'help' Command in MCPProxyAdapter
|
3
|
+
|
4
|
+
This example demonstrates:
|
5
|
+
- How to robustly integrate a project-level 'help' command
|
6
|
+
- How to extend help with custom logic
|
7
|
+
- How to test help scenarios (including fallback and error cases)
|
8
|
+
- How to avoid common mistakes
|
9
|
+
|
10
|
+
Run:
|
11
|
+
python examples/help_best_practices.py
|
12
|
+
"""
|
13
|
+
import os
|
14
|
+
import sys
|
15
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
16
|
+
from typing import Any, Dict
|
17
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
18
|
+
from tests.test_mcp_proxy_adapter import MockRegistry
|
19
|
+
|
20
|
+
# --- Setup registry and adapter ---
|
21
|
+
registry = MockRegistry()
|
22
|
+
adapter = MCPProxyAdapter(registry)
|
23
|
+
|
24
|
+
def robust_help(command: str = None) -> Dict[str, Any]:
|
25
|
+
"""
|
26
|
+
Best practice: always check for project help, handle errors, fallback to adapter help.
|
27
|
+
"""
|
28
|
+
dispatcher = registry.dispatcher
|
29
|
+
if "help" in dispatcher.get_valid_commands():
|
30
|
+
try:
|
31
|
+
if command:
|
32
|
+
return dispatcher.help_command(command=command)
|
33
|
+
return dispatcher.help_command()
|
34
|
+
except Exception as e:
|
35
|
+
# Log error, fallback to adapter help
|
36
|
+
print(f"[WARN] Project help failed: {e}. Fallback to adapter help.")
|
37
|
+
return fallback_adapter_help(command)
|
38
|
+
else:
|
39
|
+
return fallback_adapter_help(command)
|
40
|
+
|
41
|
+
def fallback_adapter_help(command: str = None) -> Dict[str, Any]:
|
42
|
+
"""
|
43
|
+
Fallback: call adapter's help (simulate REST/JSON-RPC call).
|
44
|
+
"""
|
45
|
+
dispatcher = registry.dispatcher
|
46
|
+
if not command:
|
47
|
+
return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
|
48
|
+
if command in dispatcher.get_valid_commands():
|
49
|
+
return {"source": "adapter", "command": command, "info": {"description": "Adapter help for command"}}
|
50
|
+
return {"source": "adapter", "error": f"Command '{command}' not found (adapter)", "available_commands": dispatcher.get_valid_commands()}
|
51
|
+
|
52
|
+
# --- Example test cases ---
|
53
|
+
def test_help():
|
54
|
+
"""Test all help scenarios."""
|
55
|
+
print("[TEST] Project help (no param):", robust_help())
|
56
|
+
print("[TEST] Project help (existing command):", robust_help("success"))
|
57
|
+
print("[TEST] Project help (nonexistent command, triggers fallback):", robust_help("not_a_command"))
|
58
|
+
# Simulate registry without help
|
59
|
+
registry_no_help = MockRegistry()
|
60
|
+
if "help" in registry_no_help.dispatcher.commands:
|
61
|
+
del registry_no_help.dispatcher.commands["help"]
|
62
|
+
global registry
|
63
|
+
registry = registry_no_help
|
64
|
+
print("[TEST] Adapter help (no project help present):", robust_help("success"))
|
65
|
+
|
66
|
+
if __name__ == "__main__":
|
67
|
+
test_help()
|
@@ -0,0 +1,64 @@
|
|
1
|
+
"""
|
2
|
+
Example: Using 'help' command with MCPProxyAdapter
|
3
|
+
|
4
|
+
This script demonstrates how to:
|
5
|
+
- Call the 'help' command (if present in the project)
|
6
|
+
- Call 'help' with a parameter (for a specific command)
|
7
|
+
- Handle errors and fallback to adapter help
|
8
|
+
- Best practices for integrating and extending help
|
9
|
+
|
10
|
+
Run:
|
11
|
+
python examples/help_usage.py
|
12
|
+
"""
|
13
|
+
import os
|
14
|
+
import sys
|
15
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
16
|
+
from typing import Any, Dict
|
17
|
+
|
18
|
+
# Assume MCPProxyAdapter and MockRegistry are available from src and tests
|
19
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
20
|
+
from tests.test_mcp_proxy_adapter import MockRegistry
|
21
|
+
|
22
|
+
# --- Setup registry and adapter ---
|
23
|
+
registry = MockRegistry()
|
24
|
+
adapter = MCPProxyAdapter(registry)
|
25
|
+
|
26
|
+
# --- Best practice: always check if 'help' is in commands ---
|
27
|
+
def call_help(command: str = None) -> Dict[str, Any]:
|
28
|
+
"""Call help command with or without parameter."""
|
29
|
+
dispatcher = registry.dispatcher
|
30
|
+
if "help" in dispatcher.get_valid_commands():
|
31
|
+
if command:
|
32
|
+
try:
|
33
|
+
return dispatcher.help_command(command=command)
|
34
|
+
except Exception as e:
|
35
|
+
print(f"Project help failed: {e}. Fallback to adapter help.")
|
36
|
+
return adapter_help(command)
|
37
|
+
else:
|
38
|
+
return dispatcher.help_command()
|
39
|
+
else:
|
40
|
+
return adapter_help(command)
|
41
|
+
|
42
|
+
def adapter_help(command: str = None) -> Dict[str, Any]:
|
43
|
+
"""Fallback: call adapter's help (simulate)."""
|
44
|
+
dispatcher = registry.dispatcher
|
45
|
+
if not command:
|
46
|
+
return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
|
47
|
+
if command in dispatcher.get_valid_commands():
|
48
|
+
return {"source": "adapter", "command": command, "info": {"description": "Adapter help for command"}}
|
49
|
+
return {"source": "adapter", "error": f"Command '{command}' not found (adapter)", "available_commands": dispatcher.get_valid_commands()}
|
50
|
+
|
51
|
+
if __name__ == "__main__":
|
52
|
+
print("=== Project help (no param) ===")
|
53
|
+
print(call_help())
|
54
|
+
print("\n=== Project help (existing command) ===")
|
55
|
+
print(call_help("success"))
|
56
|
+
print("\n=== Project help (nonexistent command, triggers fallback) ===")
|
57
|
+
print(call_help("not_a_command"))
|
58
|
+
print("\n=== Adapter help (no project help present) ===")
|
59
|
+
# Simulate registry without help
|
60
|
+
registry_no_help = MockRegistry()
|
61
|
+
if "help" in registry_no_help.dispatcher.commands:
|
62
|
+
del registry_no_help.dispatcher.commands["help"]
|
63
|
+
adapter_no_help = MCPProxyAdapter(registry_no_help)
|
64
|
+
print(adapter_help("success"))
|
@@ -19,10 +19,10 @@ from pydantic import BaseModel, Field
|
|
19
19
|
import uvicorn
|
20
20
|
|
21
21
|
# Import MCP Proxy Adapter
|
22
|
-
from
|
22
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
23
23
|
|
24
24
|
# Import models for JSON-RPC
|
25
|
-
from
|
25
|
+
from mcp_proxy_adapter.models import JsonRpcRequest, JsonRpcResponse
|
26
26
|
|
27
27
|
# Import MockRegistry from tests for example
|
28
28
|
# (in a real project, CommandRegistry would be used)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"""
|
2
|
+
Project Structure Example for MCPProxyAdapter
|
3
|
+
|
4
|
+
- How to organize your project for clean integration
|
5
|
+
- Where to place registry, commands, adapter
|
6
|
+
- How to register endpoints in FastAPI
|
7
|
+
|
8
|
+
Run:
|
9
|
+
python examples/project_structure_example.py
|
10
|
+
"""
|
11
|
+
import os
|
12
|
+
import sys
|
13
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
14
|
+
from fastapi import FastAPI
|
15
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
16
|
+
|
17
|
+
# --- Command registry and commands ---
|
18
|
+
class MyRegistry:
|
19
|
+
def __init__(self):
|
20
|
+
self.dispatcher = self
|
21
|
+
self.commands = {"hello": self.hello}
|
22
|
+
self.commands_info = {"hello": {"description": "Say hello", "params": {}}}
|
23
|
+
def get_valid_commands(self):
|
24
|
+
return list(self.commands.keys())
|
25
|
+
def get_command_info(self, command):
|
26
|
+
return self.commands_info.get(command)
|
27
|
+
def get_commands_info(self):
|
28
|
+
return self.commands_info
|
29
|
+
def execute(self, command, **params):
|
30
|
+
if command == "hello":
|
31
|
+
return {"message": "Hello, world!"}
|
32
|
+
raise KeyError(f"Unknown command: {command}")
|
33
|
+
def add_generator(self, generator):
|
34
|
+
pass
|
35
|
+
def hello(self):
|
36
|
+
"""Say hello."""
|
37
|
+
return {"message": "Hello, world!"}
|
38
|
+
|
39
|
+
# --- FastAPI app and adapter ---
|
40
|
+
app = FastAPI()
|
41
|
+
registry = MyRegistry()
|
42
|
+
adapter = MCPProxyAdapter(registry)
|
43
|
+
adapter.register_endpoints(app)
|
44
|
+
|
45
|
+
if __name__ == "__main__":
|
46
|
+
import uvicorn
|
47
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
"""
|
2
|
+
Testing Example for MCPProxyAdapter
|
3
|
+
|
4
|
+
- How to write unit and integration tests for commands
|
5
|
+
- How to test help and error handling
|
6
|
+
- Best practices for test structure
|
7
|
+
|
8
|
+
Run:
|
9
|
+
python examples/testing_example.py
|
10
|
+
"""
|
11
|
+
import os
|
12
|
+
import sys
|
13
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
14
|
+
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
15
|
+
|
16
|
+
class MyRegistry:
|
17
|
+
def __init__(self):
|
18
|
+
self.dispatcher = self
|
19
|
+
self.commands = {"echo": self.echo}
|
20
|
+
self.commands_info = {"echo": {"description": "Echo input string", "params": {"text": {"type": "string", "description": "Text to echo", "required": True}}}}
|
21
|
+
def get_valid_commands(self):
|
22
|
+
return list(self.commands.keys())
|
23
|
+
def get_command_info(self, command):
|
24
|
+
return self.commands_info.get(command)
|
25
|
+
def get_commands_info(self):
|
26
|
+
return self.commands_info
|
27
|
+
def execute(self, command, **params):
|
28
|
+
if command == "echo":
|
29
|
+
return self.echo(**params)
|
30
|
+
raise KeyError(f"Unknown command: {command}")
|
31
|
+
def add_generator(self, generator):
|
32
|
+
pass
|
33
|
+
def echo(self, text: str) -> str:
|
34
|
+
"""Echo input string."""
|
35
|
+
return text
|
36
|
+
|
37
|
+
def test_echo():
|
38
|
+
registry = MyRegistry()
|
39
|
+
adapter = MCPProxyAdapter(registry)
|
40
|
+
# Unit test
|
41
|
+
assert registry.execute("echo", text="hi") == "hi"
|
42
|
+
# Integration test (simulate JSON-RPC)
|
43
|
+
class Request:
|
44
|
+
method = "echo"
|
45
|
+
params = {"text": "hello"}
|
46
|
+
id = 1
|
47
|
+
response = adapter.router.routes[0].endpoint(Request())
|
48
|
+
# Not a real FastAPI call, just for illustration
|
49
|
+
print("[TEST] Echo command passed.")
|
50
|
+
|
51
|
+
if __name__ == "__main__":
|
52
|
+
test_echo()
|
53
|
+
print("All tests passed.")
|
@@ -0,0 +1,47 @@
|
|
1
|
+
"""
|
2
|
+
Data models for MCP Proxy Adapter.
|
3
|
+
"""
|
4
|
+
from typing import Dict, Any, List, Optional, Union
|
5
|
+
from pydantic import BaseModel, Field
|
6
|
+
|
7
|
+
class JsonRpcRequest(BaseModel):
|
8
|
+
"""Base model for JSON-RPC requests."""
|
9
|
+
jsonrpc: str = Field("2.0", description="JSON-RPC version")
|
10
|
+
method: str = Field(..., description="Method name to call")
|
11
|
+
params: Dict[str, Any] = Field({}, description="Method parameters")
|
12
|
+
id: Optional[Union[str, int]] = Field(None, description="Request identifier")
|
13
|
+
|
14
|
+
class JsonRpcResponse(BaseModel):
|
15
|
+
"""Base model for JSON-RPC responses."""
|
16
|
+
jsonrpc: str = Field("2.0", description="JSON-RPC version")
|
17
|
+
result: Optional[Any] = Field(None, description="Method execution result")
|
18
|
+
error: Optional[Dict[str, Any]] = Field(None, description="Error information")
|
19
|
+
id: Optional[Union[str, int]] = Field(None, description="Request identifier")
|
20
|
+
|
21
|
+
class CommandInfo(BaseModel):
|
22
|
+
"""Command information model."""
|
23
|
+
name: str = Field(..., description="Command name")
|
24
|
+
description: str = Field("", description="Command description")
|
25
|
+
summary: Optional[str] = Field(None, description="Brief description")
|
26
|
+
parameters: Dict[str, Dict[str, Any]] = Field({}, description="Command parameters")
|
27
|
+
returns: Optional[Dict[str, Any]] = Field(None, description="Return value information")
|
28
|
+
|
29
|
+
class CommandParameter(BaseModel):
|
30
|
+
"""Command parameter model."""
|
31
|
+
type: str = Field(..., description="Parameter type")
|
32
|
+
description: str = Field("", description="Parameter description")
|
33
|
+
required: bool = Field(False, description="Whether the parameter is required")
|
34
|
+
default: Optional[Any] = Field(None, description="Default value")
|
35
|
+
enum: Optional[List[Any]] = Field(None, description="Possible values for enumeration")
|
36
|
+
|
37
|
+
class MCPProxyTool(BaseModel):
|
38
|
+
"""Tool model for MCPProxy."""
|
39
|
+
name: str = Field(..., description="Tool name")
|
40
|
+
description: str = Field("", description="Tool description")
|
41
|
+
parameters: Dict[str, Any] = Field(..., description="Tool parameters schema")
|
42
|
+
|
43
|
+
class MCPProxyConfig(BaseModel):
|
44
|
+
"""Configuration model for MCPProxy."""
|
45
|
+
version: str = Field("1.0", description="Configuration version")
|
46
|
+
tools: List[MCPProxyTool] = Field([], description="List of tools")
|
47
|
+
routes: List[Dict[str, Any]] = Field([], description="Routes configuration")
|
@@ -1,15 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-proxy-adapter
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.1.1
|
4
4
|
Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
|
5
5
|
Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
|
6
6
|
Author: Vasiliy VZ
|
7
7
|
Author-email: Vasiliy VZ <vasilyvz@example.com>
|
8
8
|
License: MIT
|
9
9
|
Project-URL: Homepage, https://github.com/vasilyvz/mcp-proxy-adapter
|
10
|
-
Project-URL:
|
11
|
-
Project-URL: Documentation, https://github.com/vasilyvz/
|
12
|
-
Project-URL: Source, https://github.com/vasilyvz/mcp_proxy_adapter
|
10
|
+
Project-URL: Bug Tracker, https://github.com/vasilyvz/mcp-proxy-adapter/issues
|
11
|
+
Project-URL: Documentation, https://github.com/vasilyvz/mcp-proxy-adapter/tree/main/docs
|
13
12
|
Classifier: Development Status :: 4 - Beta
|
14
13
|
Classifier: Intended Audience :: Developers
|
15
14
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -22,7 +21,7 @@ Requires-Python: >=3.9, <4
|
|
22
21
|
Description-Content-Type: text/markdown
|
23
22
|
License-File: LICENSE
|
24
23
|
Requires-Dist: fastapi<1.0.0,>=0.95.0
|
25
|
-
Requires-Dist: pydantic
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
26
25
|
Requires-Dist: uvicorn<1.0.0,>=0.22.0
|
27
26
|
Requires-Dist: docstring-parser<1.0.0,>=0.15
|
28
27
|
Requires-Dist: typing-extensions<5.0.0,>=4.5.0
|
@@ -262,11 +261,46 @@ MIT
|
|
262
261
|
## Documentation
|
263
262
|
See [docs/](docs/) for detailed guides, architecture, and examples.
|
264
263
|
|
265
|
-
##
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
-
|
270
|
-
-
|
271
|
-
|
272
|
-
|
264
|
+
## 📦 Примеры (examples/)
|
265
|
+
|
266
|
+
- `help_usage.py` — базовое использование help-команды
|
267
|
+
- `help_best_practices.py` — best practices для help
|
268
|
+
- `project_structure_example.py` — структура проекта с MCPProxyAdapter
|
269
|
+
- `docstring_and_schema_example.py` — как документировать команды для схемы
|
270
|
+
- `testing_example.py` — как тестировать команды и интеграцию
|
271
|
+
- `extension_example.py` — как расширять и кастомизировать команды и help
|
272
|
+
|
273
|
+
## ✅ Чеклист для добавления новой команды
|
274
|
+
|
275
|
+
1. **Реализовать функцию-команду** с подробным docstring (EN)
|
276
|
+
2. **Добавить описание параметров** (type, description, required)
|
277
|
+
3. **Добавить описание возврата** (docstring, тип)
|
278
|
+
4. **Зарегистрировать команду** в registry/dispatcher
|
279
|
+
5. **Добавить описание в get_commands_info** (использовать docstring)
|
280
|
+
6. **Покрыть тестами** (unit/integration, edge-cases, ошибки)
|
281
|
+
7. **Добавить пример использования** в examples/
|
282
|
+
8. **Проверить интеграцию с help** (и с параметром, и без)
|
283
|
+
9. **Проверить генерацию схемы/OpenAPI**
|
284
|
+
10. **Документировать в README.md** (EN/RU)
|
285
|
+
|
286
|
+
## 📦 Examples (EN)
|
287
|
+
|
288
|
+
- `help_usage.py` — basic help command usage
|
289
|
+
- `help_best_practices.py` — best practices for help
|
290
|
+
- `project_structure_example.py` — project structure with MCPProxyAdapter
|
291
|
+
- `docstring_and_schema_example.py` — how to document commands for schema
|
292
|
+
- `testing_example.py` — how to test commands and integration
|
293
|
+
- `extension_example.py` — how to extend/customize commands and help
|
294
|
+
|
295
|
+
## ✅ Checklist for adding a new command
|
296
|
+
|
297
|
+
1. **Implement the command function** with detailed docstring (EN)
|
298
|
+
2. **Describe parameters** (type, description, required)
|
299
|
+
3. **Describe return value** (docstring, type)
|
300
|
+
4. **Register the command** in registry/dispatcher
|
301
|
+
5. **Add description to get_commands_info** (use docstring)
|
302
|
+
6. **Cover with tests** (unit/integration, edge-cases, errors)
|
303
|
+
7. **Add usage example** to examples/
|
304
|
+
8. **Check help integration** (with/without param)
|
305
|
+
9. **Check schema/OpenAPI generation**
|
306
|
+
10. **Document in README.md** (EN/RU)
|