mcp-proxy-adapter 2.0.1__tar.gz → 2.1.0__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.
Files changed (84) hide show
  1. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/MANIFEST.in +0 -1
  2. {mcp_proxy_adapter-2.0.1/src/mcp_proxy_adapter.egg-info → mcp_proxy_adapter-2.1.0}/PKG-INFO +47 -13
  3. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/README.md +43 -8
  4. mcp_proxy_adapter-2.1.0/examples/docstring_and_schema_example.py +60 -0
  5. mcp_proxy_adapter-2.1.0/examples/extension_example.py +60 -0
  6. mcp_proxy_adapter-2.1.0/examples/help_best_practices.py +67 -0
  7. mcp_proxy_adapter-2.1.0/examples/help_usage.py +64 -0
  8. mcp_proxy_adapter-2.1.0/examples/project_structure_example.py +47 -0
  9. mcp_proxy_adapter-2.1.0/examples/testing_example.py +53 -0
  10. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/pyproject.toml +11 -12
  11. mcp_proxy_adapter-2.1.0/requirements.txt +5 -0
  12. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/setup.py +6 -6
  13. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0/src/mcp_proxy_adapter.egg-info}/PKG-INFO +47 -13
  14. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/mcp_proxy_adapter.egg-info/SOURCES.txt +7 -5
  15. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/mcp_proxy_adapter.egg-info/requires.txt +1 -1
  16. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/mcp_proxy_adapter.egg-info/top_level.txt +1 -1
  17. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_adapter.py +10 -12
  18. mcp_proxy_adapter-2.1.0/tests/test_examples.py +32 -0
  19. mcp_proxy_adapter-2.1.0/tests/test_mcp_proxy_adapter.py +568 -0
  20. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_mcp_proxy_adapter_basic.py +13 -3
  21. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_part2.py +12 -2
  22. mcp_proxy_adapter-2.0.1/requirements.txt +0 -10
  23. mcp_proxy_adapter-2.0.1/src/__init__.py +0 -17
  24. mcp_proxy_adapter-2.0.1/src/adapter.py +0 -697
  25. mcp_proxy_adapter-2.0.1/src/models.py +0 -47
  26. mcp_proxy_adapter-2.0.1/src/registry.py +0 -439
  27. mcp_proxy_adapter-2.0.1/src/schema.py +0 -257
  28. mcp_proxy_adapter-2.0.1/tests/test_mcp_proxy_adapter.py +0 -320
  29. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/LICENSE +0 -0
  30. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/code_index.yaml +0 -0
  31. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/README.md +0 -0
  32. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/README_ru.md +0 -0
  33. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/architecture.md +0 -0
  34. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/architecture_ru.md +0 -0
  35. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/command_development.md +0 -0
  36. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/command_development_ru.md +0 -0
  37. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/deployment.md +0 -0
  38. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/deployment_ru.md +0 -0
  39. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/examples.md +0 -0
  40. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/examples_ru.md +0 -0
  41. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/mcp_proxy_adapter.md +0 -0
  42. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/mcp_proxy_adapter_ru.md +0 -0
  43. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/quickstart.md +0 -0
  44. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/quickstart_ru.md +0 -0
  45. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/testing.md +0 -0
  46. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/testing_ru.md +0 -0
  47. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/docs/validation_ru.md +0 -0
  48. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/examples/analyze_config.py +0 -0
  49. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/examples/basic_integration.py +0 -0
  50. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/examples/mcp_proxy_client.py +0 -0
  51. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/examples/mcp_proxy_config.json +0 -0
  52. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/examples/openapi_server.py +0 -0
  53. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/setup.cfg +0 -0
  54. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/adapters/__init__.py +0 -0
  55. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/analyzers/__init__.py +0 -0
  56. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/analyzers/docstring_analyzer.py +0 -0
  57. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/analyzers/type_analyzer.py +0 -0
  58. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/cli/__init__.py +0 -0
  59. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/cli/__main__.py +0 -0
  60. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/cli/command_runner.py +0 -0
  61. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/dispatchers/__init__.py +0 -0
  62. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/dispatchers/base_dispatcher.py +0 -0
  63. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/dispatchers/json_rpc_dispatcher.py +0 -0
  64. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/generators/__init__.py +0 -0
  65. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/generators/endpoint_generator.py +0 -0
  66. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/generators/openapi_generator.py +0 -0
  67. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/generators/rest_api_generator.py +0 -0
  68. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/mcp_proxy_adapter.egg-info/dependency_links.txt +0 -0
  69. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/openapi_schema/__init__.py +0 -0
  70. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/openapi_schema/command_registry.py +0 -0
  71. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/openapi_schema/rest_schema.py +0 -0
  72. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/openapi_schema/rpc_generator.py +0 -0
  73. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/openapi_schema/rpc_schema.py +0 -0
  74. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/validators/__init__.py +0 -0
  75. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/validators/base_validator.py +0 -0
  76. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/validators/docstring_validator.py +0 -0
  77. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/src/validators/metadata_validator.py +0 -0
  78. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/conftest.py +0 -0
  79. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_adapter_coverage.py +0 -0
  80. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_basic_dispatcher.py +0 -0
  81. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_command_registry.py +0 -0
  82. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_part1.py +0 -0
  83. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_schema.py +0 -0
  84. {mcp_proxy_adapter-2.0.1 → mcp_proxy_adapter-2.1.0}/tests/test_simple_adapter.py +0 -0
@@ -6,7 +6,6 @@ include code_index.yaml
6
6
  recursive-include docs *.md
7
7
  recursive-include examples *.py *.json
8
8
  recursive-include tests *.py
9
- recursive-include src *
10
9
  global-exclude __pycache__
11
10
  global-exclude *.py[cod]
12
11
  global-exclude *.so
@@ -1,15 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 2.0.1
3
+ Version: 2.1.0
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: BugTracker, https://github.com/vasilyvz/mcp-proxy-adapter/issues
11
- Project-URL: Documentation, https://github.com/vasilyvz/mcp_proxy_adapter#readme
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<3.0.0,>=2.0.0
24
+ Requires-Dist: pydantic<2.0.0,>=1.10.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
- ## CI/CD & PyPI automation
266
-
267
- This project uses GitHub Actions for continuous integration and automated publishing to PyPI.
268
-
269
- - All tests are run on every push and pull request.
270
- - On push of a new tag (vX.Y.Z), the package is built and published to PyPI automatically.
271
-
272
- See `.github/workflows/publish.yml` for details.
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
- ## CI/CD & PyPI automation
233
-
234
- This project uses GitHub Actions for continuous integration and automated publishing to PyPI.
235
-
236
- - All tests are run on every push and pull request.
237
- - On push of a new tag (vX.Y.Z), the package is built and published to PyPI automatically.
238
-
239
- See `.github/workflows/publish.yml` for details.
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 src.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 src.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 src.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 src.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"))
@@ -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 src.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 src.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.")
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["setuptools", "wheel"]
2
+ requires = ["setuptools>=42", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcp-proxy-adapter"
7
- version = "2.0.1"
7
+ version = "2.1.0"
8
8
  description = "Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -24,17 +24,16 @@ classifiers = [
24
24
  ]
25
25
  dependencies = [
26
26
  "fastapi>=0.95.0,<1.0.0",
27
- "pydantic>=2.0.0,<3.0.0",
27
+ "pydantic>=1.10.0,<2.0.0",
28
28
  "uvicorn>=0.22.0,<1.0.0",
29
29
  "docstring-parser>=0.15,<1.0.0",
30
30
  "typing-extensions>=4.5.0,<5.0.0",
31
31
  ]
32
32
 
33
33
  [project.urls]
34
- Homepage = "https://github.com/vasilyvz/mcp-proxy-adapter"
35
- BugTracker = "https://github.com/vasilyvz/mcp-proxy-adapter/issues"
36
- Documentation = "https://github.com/vasilyvz/mcp_proxy_adapter#readme"
37
- Source = "https://github.com/vasilyvz/mcp_proxy_adapter"
34
+ "Homepage" = "https://github.com/vasilyvz/mcp-proxy-adapter"
35
+ "Bug Tracker" = "https://github.com/vasilyvz/mcp-proxy-adapter/issues"
36
+ "Documentation" = "https://github.com/vasilyvz/mcp-proxy-adapter/tree/main/docs"
38
37
 
39
38
  [tool.setuptools]
40
39
  package-dir = {"" = "src"}
@@ -42,9 +41,9 @@ package-dir = {"" = "src"}
42
41
  [tool.setuptools.packages.find]
43
42
  where = ["src"]
44
43
 
44
+ [tool.setuptools.package-data]
45
+ "examples" = ["*.py", "*.json"]
46
+
45
47
  [tool.pytest.ini_options]
46
- addopts = "-ra -q"
47
- filterwarnings = [
48
- "ignore::DeprecationWarning",
49
- "ignore::PendingDeprecationWarning"
50
- ]
48
+ asyncio_mode = "strict"
49
+ asyncio_default_fixture_loop_scope = "function"
@@ -0,0 +1,5 @@
1
+ fastapi>=0.95.0,<1.0.0
2
+ pydantic>=1.10.0,<2.0.0
3
+ uvicorn>=0.22.0,<1.0.0
4
+ docstring-parser>=0.15,<1.0.0
5
+ typing-extensions>=4.5.0,<5.0.0
@@ -10,14 +10,11 @@ with open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
10
10
 
11
11
  # Read requirements.txt
12
12
  with open(os.path.join(here, 'requirements.txt'), encoding='utf-8') as f:
13
- requirements = [
14
- line.replace('pydantic>=1.10.0,<2.0.0', 'pydantic>=2.0.0,<3.0.0')
15
- for line in f.read().splitlines()
16
- ]
13
+ requirements = f.read().splitlines()
17
14
 
18
15
  setup(
19
16
  name="mcp-proxy-adapter",
20
- version="2.0.0",
17
+ version="2.1.0",
21
18
  description="Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.",
22
19
  long_description=long_description,
23
20
  long_description_content_type="text/markdown",
@@ -42,6 +39,9 @@ setup(
42
39
  project_urls={
43
40
  "Bug Reports": "https://github.com/vasilyvz/mcp-proxy-adapter/issues",
44
41
  "Source": "https://github.com/vasilyvz/mcp-proxy-adapter",
45
- "Documentation": "https://github.com/vasilyvz/mcp_proxy_adapter#readme",
42
+ },
43
+ include_package_data=True,
44
+ package_data={
45
+ "examples": ["*.py", "*.json"],
46
46
  },
47
47
  )