mcp-mesh 0.7.20__tar.gz → 0.8.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 (164) hide show
  1. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/.gitignore +18 -0
  2. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/PKG-INFO +7 -5
  3. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/README.md +4 -4
  4. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/__init__.py +1 -1
  5. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/dependency_injector.py +13 -15
  6. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/http_wrapper.py +69 -10
  7. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/mesh_llm_agent.py +29 -10
  8. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/mesh_llm_agent_injector.py +77 -41
  9. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/provider_handlers/__init__.py +14 -1
  10. mcp_mesh-0.8.0/_mcp_mesh/engine/provider_handlers/base_provider_handler.py +228 -0
  11. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/provider_handlers/claude_handler.py +15 -57
  12. mcp_mesh-0.8.0/_mcp_mesh/engine/provider_handlers/gemini_handler.py +181 -0
  13. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/provider_handlers/openai_handler.py +8 -63
  14. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/provider_handlers/provider_handler_registry.py +16 -10
  15. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/response_parser.py +61 -15
  16. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/signature_analyzer.py +58 -68
  17. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/unified_mcp_proxy.py +19 -35
  18. mcp_mesh-0.8.0/_mcp_mesh/pipeline/__init__.py +35 -0
  19. mcp_mesh-0.8.0/_mcp_mesh/pipeline/api_heartbeat/__init__.py +21 -0
  20. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py +23 -49
  21. mcp_mesh-0.8.0/_mcp_mesh/pipeline/api_heartbeat/rust_api_heartbeat.py +429 -0
  22. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/api_pipeline.py +7 -9
  23. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/api_server_setup.py +91 -70
  24. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/fastapi_discovery.py +22 -23
  25. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/middleware_integration.py +32 -24
  26. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/route_collection.py +2 -4
  27. mcp_mesh-0.8.0/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +13 -0
  28. mcp_mesh-0.8.0/_mcp_mesh/pipeline/mcp_heartbeat/rust_heartbeat.py +710 -0
  29. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/__init__.py +2 -5
  30. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/configuration.py +1 -1
  31. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py +31 -8
  32. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py +6 -7
  33. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py +23 -11
  34. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/startup_pipeline.py +3 -8
  35. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/shared/mesh_pipeline.py +0 -2
  36. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/reload.py +1 -3
  37. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/__init__.py +2 -8
  38. mcp_mesh-0.8.0/_mcp_mesh/shared/config_resolver.py +270 -0
  39. mcp_mesh-0.8.0/_mcp_mesh/shared/defaults.py +139 -0
  40. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/fastapi_middleware_manager.py +149 -91
  41. mcp_mesh-0.8.0/_mcp_mesh/shared/host_resolver.py +48 -0
  42. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/server_discovery.py +115 -86
  43. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/simple_shutdown.py +44 -86
  44. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/execution_tracer.py +2 -6
  45. mcp_mesh-0.8.0/_mcp_mesh/tracing/redis_metadata_publisher.py +84 -0
  46. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/trace_context_helper.py +3 -13
  47. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/utils.py +29 -15
  48. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/utils/fastmcp_schema_extractor.py +5 -4
  49. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/mesh/__init__.py +12 -1
  50. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/mesh/decorators.py +248 -33
  51. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/mesh/helpers.py +52 -0
  52. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/mesh/types.py +40 -13
  53. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/pyproject.toml +7 -4
  54. mcp_mesh-0.7.20/_mcp_mesh/engine/provider_handlers/base_provider_handler.py +0 -122
  55. mcp_mesh-0.7.20/_mcp_mesh/generated/.openapi-generator/FILES +0 -50
  56. mcp_mesh-0.7.20/_mcp_mesh/generated/.openapi-generator/VERSION +0 -1
  57. mcp_mesh-0.7.20/_mcp_mesh/generated/.openapi-generator-ignore +0 -15
  58. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/__init__.py +0 -90
  59. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api/__init__.py +0 -6
  60. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api/agents_api.py +0 -1088
  61. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api/health_api.py +0 -764
  62. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api/tracing_api.py +0 -303
  63. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api_client.py +0 -798
  64. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/api_response.py +0 -21
  65. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/configuration.py +0 -577
  66. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/exceptions.py +0 -217
  67. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/__init__.py +0 -55
  68. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_info.py +0 -158
  69. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata.py +0 -126
  70. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner.py +0 -139
  71. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner_one_of.py +0 -92
  72. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration.py +0 -103
  73. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration_metadata.py +0 -136
  74. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/agents_list_response.py +0 -100
  75. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/capability_info.py +0 -107
  76. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_metadata.py +0 -112
  77. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_request.py +0 -103
  78. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_info.py +0 -105
  79. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_info.py +0 -103
  80. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_resolution_info.py +0 -106
  81. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/error_response.py +0 -91
  82. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/health_response.py +0 -103
  83. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request.py +0 -101
  84. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request_metadata.py +0 -111
  85. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_response.py +0 -117
  86. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider.py +0 -93
  87. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider_resolution_info.py +0 -106
  88. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter.py +0 -109
  89. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner.py +0 -139
  90. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner_one_of.py +0 -91
  91. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_info.py +0 -101
  92. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_resolution_info.py +0 -120
  93. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_register_metadata.py +0 -112
  94. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_registration.py +0 -129
  95. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response.py +0 -153
  96. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response_dependencies_resolved_value_inner.py +0 -101
  97. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_dependency_registration.py +0 -93
  98. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_register_metadata.py +0 -107
  99. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_registration.py +0 -117
  100. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/registration_response.py +0 -119
  101. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/resolved_llm_provider.py +0 -110
  102. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/rich_dependency.py +0 -93
  103. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/root_response.py +0 -92
  104. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py +0 -93
  105. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py +0 -106
  106. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/py.typed +0 -0
  107. mcp_mesh-0.7.20/_mcp_mesh/generated/mcp_mesh_registry_client/rest.py +0 -259
  108. mcp_mesh-0.7.20/_mcp_mesh/pipeline/__init__.py +0 -46
  109. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/__init__.py +0 -16
  110. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +0 -418
  111. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +0 -117
  112. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_health_check.py +0 -140
  113. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py +0 -247
  114. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +0 -311
  115. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py +0 -386
  116. mcp_mesh-0.7.20/_mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py +0 -104
  117. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +0 -25
  118. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py +0 -396
  119. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py +0 -116
  120. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py +0 -311
  121. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py +0 -282
  122. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py +0 -98
  123. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/lifespan_integration.py +0 -84
  124. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py +0 -264
  125. mcp_mesh-0.7.20/_mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py +0 -79
  126. mcp_mesh-0.7.20/_mcp_mesh/pipeline/shared/registry_connection.py +0 -80
  127. mcp_mesh-0.7.20/_mcp_mesh/shared/config_resolver.py +0 -226
  128. mcp_mesh-0.7.20/_mcp_mesh/shared/defaults.py +0 -64
  129. mcp_mesh-0.7.20/_mcp_mesh/shared/host_resolver.py +0 -86
  130. mcp_mesh-0.7.20/_mcp_mesh/shared/registry_client_wrapper.py +0 -515
  131. mcp_mesh-0.7.20/_mcp_mesh/tracing/redis_metadata_publisher.py +0 -139
  132. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/LICENSE +0 -0
  133. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/__init__.py +0 -0
  134. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/async_mcp_client.py +0 -0
  135. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/base_injector.py +0 -0
  136. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/decorator_registry.py +0 -0
  137. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/llm_config.py +0 -0
  138. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/llm_errors.py +0 -0
  139. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/provider_handlers/generic_handler.py +0 -0
  140. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/self_dependency_proxy.py +0 -0
  141. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/session_aware_client.py +0 -0
  142. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/session_manager.py +0 -0
  143. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/tool_executor.py +0 -0
  144. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/engine/tool_schema_builder.py +0 -0
  145. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/__init__.py +0 -0
  146. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/api_startup/route_integration.py +0 -0
  147. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/decorator_collection.py +0 -0
  148. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py +0 -0
  149. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py +0 -0
  150. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/lifespan_factory.py +0 -0
  151. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/mcp_startup/server_discovery.py +0 -0
  152. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/shared/__init__.py +0 -0
  153. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/shared/base_step.py +0 -0
  154. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/pipeline/shared/pipeline_types.py +0 -0
  155. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/reload_runner.py +0 -0
  156. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/content_extractor.py +0 -0
  157. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/fast_heartbeat_status.py +0 -0
  158. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/health_check_manager.py +0 -0
  159. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/logging_config.py +0 -0
  160. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/sse_parser.py +0 -0
  161. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/shared/support_types.py +0 -0
  162. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/agent_context_helper.py +0 -0
  163. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/context.py +0 -0
  164. {mcp_mesh-0.7.20 → mcp_mesh-0.8.0}/_mcp_mesh/tracing/fastapi_tracing_middleware.py +0 -0
@@ -245,3 +245,21 @@ helm/*/charts/*.tgz
245
245
  helm/mcp-mesh-grafana/files/
246
246
  helm/mcp-mesh-tempo/files/
247
247
  *.DS_Store
248
+ rust-core-implementation.org
249
+
250
+ # Claude Code local files
251
+ .claude/memories.json
252
+ *.node
253
+
254
+ # NAPI-RS auto-generated build artifacts
255
+ src/runtime/core/index.js
256
+ src/runtime/core/index.d.ts
257
+ test/
258
+ scaffold-test/
259
+
260
+ # Test suite build outputs
261
+ tests/src-tests/out/
262
+ tests/lib-tests/out/
263
+
264
+ # Allow test suite build artifacts
265
+ !tests/**/build/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-mesh
3
- Version: 0.7.20
3
+ Version: 0.8.0
4
4
  Summary: Kubernetes-native platform for distributed MCP applications
5
5
  Project-URL: Homepage, https://github.com/dhyansraj/mcp-mesh
6
6
  Project-URL: Documentation, https://github.com/dhyansraj/mcp-mesh/tree/main/docs
@@ -18,6 +18,7 @@ Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
21
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
24
  Classifier: Topic :: System :: Distributed Computing
@@ -30,6 +31,7 @@ Requires-Dist: fastmcp<3.0.0,>=2.8.0
30
31
  Requires-Dist: httpx<1.0.0,>=0.25.0
31
32
  Requires-Dist: jinja2>=3.1.0
32
33
  Requires-Dist: litellm>=1.30.0
34
+ Requires-Dist: mcp-mesh-core>=0.8.0
33
35
  Requires-Dist: mcp<2.0.0,>=1.9.0
34
36
  Requires-Dist: prometheus-client<1.0.0,>=0.19.0
35
37
  Requires-Dist: pydantic<3.0.0,>=2.4.0
@@ -77,7 +79,7 @@ pip install mcp-mesh
77
79
  import mesh
78
80
 
79
81
  # Import types from public API
80
- from mesh.types import McpMeshAgent
82
+ from mesh.types import McpMeshTool
81
83
 
82
84
  # Define your agent
83
85
  @mesh.agent(name="hello-world", http_port=9090)
@@ -91,11 +93,11 @@ class HelloWorldAgent:
91
93
  dependencies=["date_service"],
92
94
  description="Greeting function with date dependency injection"
93
95
  )
94
- def greet(name: str = "World", systemDate: McpMeshAgent = None) -> str:
96
+ def greet(name: str = "World", date_tool: McpMeshTool = None) -> str:
95
97
  """Greeting function with automatic dependency injection."""
96
- if systemDate is not None:
98
+ if date_tool is not None:
97
99
  try:
98
- current_date = systemDate()
100
+ current_date = date_tool()
99
101
  return f"Hello, {name}! Today is {current_date}"
100
102
  except Exception:
101
103
  pass
@@ -14,7 +14,7 @@ pip install mcp-mesh
14
14
  import mesh
15
15
 
16
16
  # Import types from public API
17
- from mesh.types import McpMeshAgent
17
+ from mesh.types import McpMeshTool
18
18
 
19
19
  # Define your agent
20
20
  @mesh.agent(name="hello-world", http_port=9090)
@@ -28,11 +28,11 @@ class HelloWorldAgent:
28
28
  dependencies=["date_service"],
29
29
  description="Greeting function with date dependency injection"
30
30
  )
31
- def greet(name: str = "World", systemDate: McpMeshAgent = None) -> str:
31
+ def greet(name: str = "World", date_tool: McpMeshTool = None) -> str:
32
32
  """Greeting function with automatic dependency injection."""
33
- if systemDate is not None:
33
+ if date_tool is not None:
34
34
  try:
35
- current_date = systemDate()
35
+ current_date = date_tool()
36
36
  return f"Hello, {name}! Today is {current_date}"
37
37
  except Exception:
38
38
  pass
@@ -31,7 +31,7 @@ from .engine.decorator_registry import (
31
31
  get_decorator_stats,
32
32
  )
33
33
 
34
- __version__ = "0.7.20"
34
+ __version__ = "0.8.0"
35
35
 
36
36
  # Store reference to runtime processor if initialized
37
37
  _runtime_processor = None
@@ -14,12 +14,10 @@ import weakref
14
14
  from collections.abc import Callable
15
15
  from typing import Any
16
16
 
17
- from ..shared.logging_config import (
18
- format_log_value,
19
- format_result_summary,
20
- get_trace_prefix,
21
- )
22
- from .signature_analyzer import get_mesh_agent_positions, has_llm_agent_parameter
17
+ from ..shared.logging_config import (format_log_value, format_result_summary,
18
+ get_trace_prefix)
19
+ from .signature_analyzer import (get_mesh_agent_positions,
20
+ has_llm_agent_parameter)
23
21
 
24
22
  logger = logging.getLogger(__name__)
25
23
 
@@ -29,8 +27,8 @@ def analyze_injection_strategy(func: Callable, dependencies: list[str]) -> list[
29
27
  Analyze function signature and determine injection strategy.
30
28
 
31
29
  Rules:
32
- 1. Single parameter: inject regardless of typing (with warning if not McpMeshAgent)
33
- 2. Multiple parameters: only inject into McpMeshAgent typed parameters
30
+ 1. Single parameter: inject regardless of typing (with warning if not McpMeshTool)
31
+ 2. Multiple parameters: only inject into McpMeshTool typed parameters
34
32
  3. Log warnings for mismatches and edge cases
35
33
 
36
34
  Args:
@@ -62,17 +60,17 @@ def analyze_injection_strategy(func: Callable, dependencies: list[str]) -> list[
62
60
  logger.warning(
63
61
  f"Single parameter '{param_name}' in function '{func_name}' found, "
64
62
  f"injecting {dependencies[0] if dependencies else 'dependency'} proxy "
65
- f"(consider typing as McpMeshAgent for clarity)"
63
+ f"(consider typing as McpMeshTool for clarity)"
66
64
  )
67
65
  return [0] # Inject into the single parameter
68
66
 
69
- # Multiple parameters rule: only inject into McpMeshAgent typed parameters
67
+ # Multiple parameters rule: only inject into McpMeshTool typed parameters
70
68
  if param_count > 1:
71
69
  if not mesh_positions:
72
70
  logger.warning(
73
71
  f"⚠️ Function '{func_name}' has {param_count} parameters but none are "
74
- f"typed as McpMeshAgent. Skipping injection of {len(dependencies)} dependencies. "
75
- f"Consider typing dependency parameters as McpMeshAgent."
72
+ f"typed as McpMeshTool. Skipping injection of {len(dependencies)} dependencies. "
73
+ f"Consider typing dependency parameters as McpMeshTool."
76
74
  )
77
75
  return []
78
76
 
@@ -82,7 +80,7 @@ def analyze_injection_strategy(func: Callable, dependencies: list[str]) -> list[
82
80
  excess_deps = dependencies[len(mesh_positions) :]
83
81
  logger.warning(
84
82
  f"Function '{func_name}' has {len(dependencies)} dependencies "
85
- f"but only {len(mesh_positions)} McpMeshAgent parameters. "
83
+ f"but only {len(mesh_positions)} McpMeshTool parameters. "
86
84
  f"Dependencies {excess_deps} will not be injected."
87
85
  )
88
86
  else:
@@ -90,7 +88,7 @@ def analyze_injection_strategy(func: Callable, dependencies: list[str]) -> list[
90
88
  params[pos].name for pos in mesh_positions[len(dependencies) :]
91
89
  ]
92
90
  logger.warning(
93
- f"Function '{func_name}' has {len(mesh_positions)} McpMeshAgent parameters "
91
+ f"Function '{func_name}' has {len(mesh_positions)} McpMeshTool parameters "
94
92
  f"but only {len(dependencies)} dependencies declared. "
95
93
  f"Parameters {excess_params} will remain None."
96
94
  )
@@ -106,7 +104,7 @@ class DependencyInjector:
106
104
  Manages dynamic dependency injection for mesh agents.
107
105
 
108
106
  This class:
109
- 1. Maintains a registry of available dependencies (McpMeshAgent)
107
+ 1. Maintains a registry of available dependencies (McpMeshTool)
110
108
  2. Coordinates with MeshLlmAgentInjector for LLM agent injection
111
109
  3. Tracks which functions depend on which services
112
110
  4. Updates function bindings when topology changes
@@ -387,8 +387,13 @@ class HttpMcpWrapper:
387
387
  self.logger = logger
388
388
 
389
389
  async def dispatch(self, request: Request, call_next):
390
- # Extract and set trace context from headers for distributed tracing
390
+ # Read body once for processing
391
+ body = await request.body()
392
+ modified_body = body
393
+
394
+ # Extract and set trace context from headers and arguments
391
395
  try:
396
+ from ..tracing.context import TraceContext
392
397
  from ..tracing.trace_context_helper import TraceContextHelper
393
398
 
394
399
  # DEBUG: Log incoming headers for trace propagation debugging
@@ -399,22 +404,67 @@ class HttpMcpWrapper:
399
404
  f"X-Parent-Span={parent_span_header}, path={request.url.path}"
400
405
  )
401
406
 
402
- # Use helper class for trace context extraction and setup
403
- trace_context = (
404
- await TraceContextHelper.extract_trace_context_from_request(
405
- request
407
+ # Extract trace context from both headers AND arguments
408
+ trace_id = trace_id_header
409
+ parent_span = parent_span_header
410
+
411
+ # Try extracting from JSON-RPC body arguments as fallback
412
+ # Also strip trace fields from arguments to avoid Pydantic validation errors
413
+ if body:
414
+ try:
415
+ payload = json.loads(body.decode("utf-8"))
416
+ if payload.get("method") == "tools/call":
417
+ arguments = payload.get("params", {}).get(
418
+ "arguments", {}
419
+ )
420
+
421
+ # Extract trace context from arguments (TypeScript uses _trace_id/_parent_span)
422
+ if not trace_id and arguments.get("_trace_id"):
423
+ trace_id = arguments.get("_trace_id")
424
+ if not parent_span and arguments.get("_parent_span"):
425
+ parent_span = arguments.get("_parent_span")
426
+
427
+ # Strip trace context fields from arguments before passing to FastMCP
428
+ if (
429
+ "_trace_id" in arguments
430
+ or "_parent_span" in arguments
431
+ ):
432
+ arguments.pop("_trace_id", None)
433
+ arguments.pop("_parent_span", None)
434
+ # Update payload with cleaned arguments
435
+ modified_body = json.dumps(payload).encode("utf-8")
436
+ self.logger.debug(
437
+ f"🔗 Stripped trace fields from arguments, "
438
+ f"trace_id={trace_id[:8] if trace_id else None}..."
439
+ )
440
+ except Exception as e:
441
+ self.logger.debug(
442
+ f"Failed to process body for trace context: {e}"
443
+ )
444
+
445
+ # Setup trace context if we have a trace_id
446
+ if trace_id:
447
+ trace_context = {
448
+ "trace_id": trace_id,
449
+ "parent_span": parent_span,
450
+ }
451
+ TraceContextHelper.setup_request_trace_context(
452
+ trace_context, self.logger
406
453
  )
407
- )
408
- TraceContextHelper.setup_request_trace_context(
409
- trace_context, self.logger
410
- )
411
454
  except Exception as e:
412
455
  # Never fail request due to tracing issues
413
456
  self.logger.warning(f"Failed to set trace context: {e}")
414
457
  pass
415
458
 
459
+ # Create a new request scope with the modified body
460
+ async def receive():
461
+ return {"type": "http.request", "body": modified_body}
462
+
463
+ # Update request with modified receive
464
+ request._receive = receive
465
+
416
466
  # Extract session ID from request
417
- session_id = await self.http_wrapper._extract_session_id(request)
467
+ session_id = await self.http_wrapper._extract_session_id_from_body(body)
418
468
 
419
469
  if session_id:
420
470
  # Check for existing session assignment
@@ -458,6 +508,15 @@ class HttpMcpWrapper:
458
508
  # Try extracting from JSON-RPC body
459
509
  try:
460
510
  body = await request.body()
511
+ return await self._extract_session_id_from_body(body)
512
+ except Exception:
513
+ pass
514
+
515
+ return None
516
+
517
+ async def _extract_session_id_from_body(self, body: bytes) -> str:
518
+ """Extract session ID from already-read request body."""
519
+ try:
461
520
  if body:
462
521
  payload = json.loads(body.decode("utf-8"))
463
522
  if payload.get("method") == "tools/call":
@@ -636,12 +636,14 @@ IMPORTANT TOOL CALLING RULES:
636
636
  # Multi-turn conversation - use provided messages array
637
637
  messages = message.copy()
638
638
 
639
- # Ensure system prompt is prepended if not already present
640
- if not messages or messages[0].get("role") != "system":
641
- messages.insert(0, {"role": "system", "content": system_content})
642
- else:
643
- # Replace existing system message with our constructed one
644
- messages[0] = {"role": "system", "content": system_content}
639
+ # Only add/update system message if we have non-empty content
640
+ # (Claude API rejects empty system messages - though decorator provides default)
641
+ if system_content:
642
+ if not messages or messages[0].get("role") != "system":
643
+ messages.insert(0, {"role": "system", "content": system_content})
644
+ else:
645
+ # Replace existing system message with our constructed one
646
+ messages[0] = {"role": "system", "content": system_content}
645
647
 
646
648
  # Log conversation history
647
649
  logger.info(
@@ -649,10 +651,17 @@ IMPORTANT TOOL CALLING RULES:
649
651
  )
650
652
  else:
651
653
  # Single-turn - build messages array from string
652
- messages = [
653
- {"role": "system", "content": system_content},
654
- {"role": "user", "content": message},
655
- ]
654
+ # Only include system message if non-empty (Claude API rejects empty system messages)
655
+ if system_content:
656
+ messages = [
657
+ {"role": "system", "content": system_content},
658
+ {"role": "user", "content": message},
659
+ ]
660
+ else:
661
+ # Fallback for edge case where system_content is explicitly empty
662
+ messages = [
663
+ {"role": "user", "content": message},
664
+ ]
656
665
 
657
666
  logger.info(f"🚀 Starting agentic loop for message: {message[:100]}...")
658
667
 
@@ -708,6 +717,16 @@ IMPORTANT TOOL CALLING RULES:
708
717
  if self.model:
709
718
  model_params["model"] = self.model
710
719
 
720
+ # Issue #459: Include output_schema for provider to apply vendor-specific handling
721
+ # (e.g., OpenAI needs response_format, not prompt-based JSON instructions)
722
+ if self.output_type is not str and hasattr(
723
+ self.output_type, "model_json_schema"
724
+ ):
725
+ model_params["output_schema"] = (
726
+ self.output_type.model_json_schema()
727
+ )
728
+ model_params["output_type_name"] = self.output_type.__name__
729
+
711
730
  logger.debug(
712
731
  f"📤 Delegating to mesh provider with handler-prepared params: "
713
732
  f"keys={list(model_params.keys())}"
@@ -161,36 +161,70 @@ class MeshLlmAgentInjector(BaseInjector):
161
161
  # Create UnifiedMCPProxy for the provider
162
162
  provider_proxy = self._create_provider_proxy(provider_data)
163
163
 
164
- # Update llm_agents data with provider_proxy and vendor (Phase 2)
165
- if function_id in self._llm_agents:
166
- self._llm_agents[function_id]["provider_proxy"] = provider_proxy
164
+ # Update only provider-related fields, preserving tool data if already set.
165
+ # This avoids race conditions where provider and tools updates can arrive in any order.
166
+ if function_id not in self._llm_agents:
167
+ self._llm_agents[function_id] = {}
167
168
 
168
- # Phase 2: Extract vendor from provider_data for handler selection
169
- vendor = provider_data.get("vendor", "unknown")
170
- self._llm_agents[function_id]["vendor"] = vendor
169
+ # Phase 2: Extract vendor from provider_data for handler selection
170
+ vendor = provider_data.get("vendor", "unknown")
171
171
 
172
+ self._llm_agents[function_id]["provider_proxy"] = provider_proxy
173
+ self._llm_agents[function_id]["vendor"] = vendor
174
+
175
+ logger.info(
176
+ f"✅ Set provider proxy for '{function_id}': {provider_proxy.function_name} at {provider_proxy.endpoint} (vendor={vendor})"
177
+ )
178
+
179
+ # Re-create and update MeshLlmAgent with new provider
180
+ # Get the function wrapper and metadata from DecoratorRegistry
181
+ llm_agents = DecoratorRegistry.get_mesh_llm_agents()
182
+ wrapper = None
183
+ llm_metadata = None
184
+ for agent_func_id, metadata in llm_agents.items():
185
+ if metadata.function_id == function_id:
186
+ wrapper = metadata.function
187
+ llm_metadata = metadata
188
+ break
189
+
190
+ # Check if tools are required (filter is specified)
191
+ has_filter = False
192
+ if llm_metadata and llm_metadata.config:
193
+ filter_config = llm_metadata.config.get("filter")
194
+ has_filter = filter_config is not None and len(filter_config) > 0
195
+
196
+ # If no filter specified, initialize empty tools data so we can create LLM agent without tools
197
+ # This supports simple LLM calls (text generation) that don't need tool calling
198
+ if not has_filter and "tools_metadata" not in self._llm_agents[function_id]:
199
+ self._llm_agents[function_id].update(
200
+ {
201
+ "config": llm_metadata.config if llm_metadata else {},
202
+ "output_type": llm_metadata.output_type if llm_metadata else None,
203
+ "param_name": llm_metadata.param_name if llm_metadata else "llm",
204
+ "tools_metadata": [], # No tools for simple LLM calls
205
+ "tools_proxies": {}, # No tool proxies needed
206
+ "function": llm_metadata.function if llm_metadata else None,
207
+ }
208
+ )
172
209
  logger.info(
173
- f"✅ Set provider proxy for '{function_id}': {provider_proxy.function_name} at {provider_proxy.endpoint} (vendor={vendor})"
210
+ f"✅ Initialized empty tools for '{function_id}' (no filter specified - simple LLM mode)"
174
211
  )
175
212
 
176
- # Re-create and update MeshLlmAgent with new provider
177
- # Get the function wrapper from DecoratorRegistry
178
- llm_agents = DecoratorRegistry.get_mesh_llm_agents()
179
- wrapper = None
180
- for agent_func_id, metadata in llm_agents.items():
181
- if metadata.function_id == function_id:
182
- wrapper = metadata.function
183
- break
184
-
185
- if wrapper and hasattr(wrapper, "_mesh_update_llm_agent"):
186
- llm_agent = self._create_llm_agent(function_id)
187
- wrapper._mesh_update_llm_agent(llm_agent)
188
- logger.info(
189
- f"🔄 Updated wrapper with new MeshLlmAgent (with provider) for '{function_id}'"
190
- )
191
- else:
192
- logger.warning(
193
- f"⚠️ Function '{function_id}' not found in _llm_agents, cannot set provider proxy"
213
+ # Update wrapper if we have tools data (either from filter matching or initialized empty)
214
+ if (
215
+ wrapper
216
+ and hasattr(wrapper, "_mesh_update_llm_agent")
217
+ and "tools_metadata" in self._llm_agents[function_id]
218
+ ):
219
+ llm_agent = self._create_llm_agent(function_id)
220
+ wrapper._mesh_update_llm_agent(llm_agent)
221
+ logger.info(
222
+ f"🔄 Updated wrapper with MeshLlmAgent for '{function_id}'"
223
+ + (" (with tools)" if has_filter else " (simple LLM mode)")
224
+ )
225
+ elif wrapper and hasattr(wrapper, "_mesh_update_llm_agent") and has_filter:
226
+ logger.debug(
227
+ f"⏳ Provider set for '{function_id}', waiting for tools before updating wrapper"
194
228
  )
195
229
 
196
230
  def _create_provider_proxy(self, provider_data: dict[str, Any]) -> UnifiedMCPProxy:
@@ -273,21 +307,23 @@ class MeshLlmAgentInjector(BaseInjector):
273
307
  logger.error(f"❌ Error creating proxy for tool {tool_name}: {e}")
274
308
  # Continue processing other tools
275
309
 
276
- # Provider proxy will be set separately via process_llm_providers()
277
- # (v0.6.1 - providers come from llm_providers field, not dependencies)
278
- provider_proxy = None
279
-
280
- # Store LLM agent data with both metadata and proxies
281
- # Keep original tool metadata for schema building
282
- self._llm_agents[function_id] = {
283
- "config": llm_metadata.config,
284
- "output_type": llm_metadata.output_type,
285
- "param_name": llm_metadata.param_name,
286
- "tools_metadata": tools, # Original metadata for schema building
287
- "tools_proxies": tool_proxies_map, # Proxies for execution
288
- "function": llm_metadata.function,
289
- "provider_proxy": provider_proxy, # Provider proxy for mesh delegation
290
- }
310
+ # Update only tool-related fields, preserving provider_proxy if already set.
311
+ # Provider proxy is managed separately by process_llm_providers().
312
+ # This avoids race conditions where tools update wipes out provider resolution.
313
+ if function_id not in self._llm_agents:
314
+ self._llm_agents[function_id] = {}
315
+
316
+ self._llm_agents[function_id].update(
317
+ {
318
+ "config": llm_metadata.config,
319
+ "output_type": llm_metadata.output_type,
320
+ "param_name": llm_metadata.param_name,
321
+ "tools_metadata": tools, # Original metadata for schema building
322
+ "tools_proxies": tool_proxies_map, # Proxies for execution
323
+ "function": llm_metadata.function,
324
+ # Note: provider_proxy is NOT set here - managed by _process_function_provider
325
+ }
326
+ )
291
327
 
292
328
  logger.info(
293
329
  f"✅ Processed {len(tool_proxies_map)} tools for LLM function '{function_id}'"
@@ -380,7 +416,7 @@ class MeshLlmAgentInjector(BaseInjector):
380
416
  """
381
417
  Create wrapper that injects MeshLlmAgent into function parameters.
382
418
 
383
- Like McpMeshAgent injection, this creates a wrapper at decorator time with llm_agent=None,
419
+ Like McpMeshTool injection, this creates a wrapper at decorator time with llm_agent=None,
384
420
  which gets updated during heartbeat when tools arrive from registry.
385
421
 
386
422
  Args:
@@ -5,15 +5,28 @@ This package provides vendor-specific customization for different LLM providers
5
5
  (Claude, OpenAI, Gemini, etc.) to optimize API calls and response handling.
6
6
  """
7
7
 
8
- from .base_provider_handler import BaseProviderHandler
8
+ from .base_provider_handler import (
9
+ BASE_TOOL_INSTRUCTIONS,
10
+ CLAUDE_ANTI_XML_INSTRUCTION,
11
+ BaseProviderHandler,
12
+ make_schema_strict,
13
+ )
9
14
  from .claude_handler import ClaudeHandler
15
+ from .gemini_handler import GeminiHandler
10
16
  from .generic_handler import GenericHandler
11
17
  from .openai_handler import OpenAIHandler
12
18
  from .provider_handler_registry import ProviderHandlerRegistry
13
19
 
14
20
  __all__ = [
21
+ # Constants
22
+ "BASE_TOOL_INSTRUCTIONS",
23
+ "CLAUDE_ANTI_XML_INSTRUCTION",
24
+ # Utilities
25
+ "make_schema_strict",
26
+ # Handlers
15
27
  "BaseProviderHandler",
16
28
  "ClaudeHandler",
29
+ "GeminiHandler",
17
30
  "OpenAIHandler",
18
31
  "GenericHandler",
19
32
  "ProviderHandlerRegistry",