mcp-mesh 0.6.4__tar.gz → 0.7.15__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 (155) hide show
  1. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/.gitignore +11 -2
  2. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/PKG-INFO +1 -1
  3. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/__init__.py +1 -1
  4. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/__init__.py +1 -22
  5. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/async_mcp_client.py +88 -25
  6. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/decorator_registry.py +60 -20
  7. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/dependency_injector.py +64 -53
  8. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/http_wrapper.py +10 -2
  9. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/mesh_llm_agent.py +217 -11
  10. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/mesh_llm_agent_injector.py +30 -0
  11. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/generic_handler.py +28 -22
  12. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/openai_handler.py +39 -24
  13. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/session_aware_client.py +3 -3
  14. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/unified_mcp_proxy.py +157 -105
  15. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/.openapi-generator/FILES +2 -0
  16. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/.openapi-generator-ignore +1 -0
  17. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/__init__.py +19 -1
  18. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api/__init__.py +0 -1
  19. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api/agents_api.py +13 -15
  20. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api/health_api.py +10 -12
  21. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api/tracing_api.py +5 -7
  22. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api_client.py +1 -1
  23. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/configuration.py +1 -1
  24. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/exceptions.py +8 -8
  25. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/__init__.py +3 -1
  26. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_info.py +22 -4
  27. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata.py +1 -3
  28. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner.py +1 -3
  29. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner_one_of.py +1 -3
  30. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration.py +1 -3
  31. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration_metadata.py +1 -3
  32. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agents_list_response.py +1 -3
  33. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/capability_info.py +15 -5
  34. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_metadata.py +1 -3
  35. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_request.py +2 -4
  36. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_info.py +1 -3
  37. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_info.py +1 -3
  38. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_resolution_info.py +1 -3
  39. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/error_response.py +1 -3
  40. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/health_response.py +1 -3
  41. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request.py +1 -3
  42. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request_metadata.py +1 -3
  43. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_response.py +1 -3
  44. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider.py +2 -4
  45. mcp_mesh-0.7.15/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider_resolution_info.py +106 -0
  46. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter.py +2 -4
  47. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner.py +1 -3
  48. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner_one_of.py +1 -3
  49. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_info.py +2 -4
  50. mcp_mesh-0.7.15/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_resolution_info.py +120 -0
  51. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_register_metadata.py +1 -3
  52. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_registration.py +2 -4
  53. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response.py +1 -3
  54. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response_dependencies_resolved_value_inner.py +1 -3
  55. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_dependency_registration.py +1 -3
  56. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_register_metadata.py +1 -3
  57. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_registration.py +1 -3
  58. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/registration_response.py +1 -3
  59. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/resolved_llm_provider.py +2 -4
  60. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/rich_dependency.py +1 -3
  61. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/root_response.py +1 -3
  62. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py +1 -3
  63. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py +1 -3
  64. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/rest.py +1 -1
  65. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +76 -183
  66. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +3 -3
  67. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +30 -28
  68. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py +150 -96
  69. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/route_integration.py +91 -92
  70. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py +16 -18
  71. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py +5 -5
  72. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py +3 -3
  73. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py +6 -6
  74. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py +1 -1
  75. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py +15 -11
  76. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py +3 -3
  77. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py +44 -268
  78. mcp_mesh-0.7.15/_mcp_mesh/pipeline/mcp_startup/lifespan_factory.py +142 -0
  79. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py +57 -93
  80. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/shared/registry_connection.py +1 -1
  81. mcp_mesh-0.7.15/_mcp_mesh/shared/health_check_manager.py +313 -0
  82. mcp_mesh-0.7.15/_mcp_mesh/shared/logging_config.py +277 -0
  83. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/registry_client_wrapper.py +8 -8
  84. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/sse_parser.py +19 -17
  85. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/execution_tracer.py +66 -13
  86. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/fastapi_tracing_middleware.py +3 -4
  87. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/trace_context_helper.py +25 -6
  88. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/mesh/__init__.py +3 -1
  89. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/mesh/decorators.py +114 -33
  90. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/mesh/helpers.py +80 -5
  91. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/mesh/types.py +48 -4
  92. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/pyproject.toml +4 -4
  93. mcp_mesh-0.6.4/_mcp_mesh/engine/full_mcp_proxy.py +0 -641
  94. mcp_mesh-0.6.4/_mcp_mesh/engine/mcp_client_proxy.py +0 -457
  95. mcp_mesh-0.6.4/_mcp_mesh/shared/health_check_cache.py +0 -246
  96. mcp_mesh-0.6.4/_mcp_mesh/shared/logging_config.py +0 -81
  97. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/LICENSE +0 -0
  98. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/README.md +0 -0
  99. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/base_injector.py +0 -0
  100. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/llm_config.py +0 -0
  101. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/llm_errors.py +0 -0
  102. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/__init__.py +0 -0
  103. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/base_provider_handler.py +0 -0
  104. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/claude_handler.py +0 -0
  105. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/provider_handlers/provider_handler_registry.py +0 -0
  106. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/response_parser.py +0 -0
  107. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/self_dependency_proxy.py +0 -0
  108. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/session_manager.py +0 -0
  109. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/signature_analyzer.py +0 -0
  110. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/tool_executor.py +0 -0
  111. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/engine/tool_schema_builder.py +0 -0
  112. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/.openapi-generator/VERSION +0 -0
  113. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/api_response.py +0 -0
  114. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/generated/mcp_mesh_registry_client/py.typed +0 -0
  115. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/__init__.py +0 -0
  116. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/__init__.py +0 -0
  117. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_health_check.py +0 -0
  118. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py +0 -0
  119. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py +0 -0
  120. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py +0 -0
  121. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/__init__.py +0 -0
  122. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/api_pipeline.py +0 -0
  123. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/api_server_setup.py +0 -0
  124. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/fastapi_discovery.py +0 -0
  125. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/middleware_integration.py +0 -0
  126. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/api_startup/route_collection.py +0 -0
  127. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +0 -0
  128. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_heartbeat/lifespan_integration.py +0 -0
  129. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/__init__.py +0 -0
  130. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/configuration.py +0 -0
  131. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/decorator_collection.py +0 -0
  132. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py +0 -0
  133. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py +0 -0
  134. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py +0 -0
  135. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/server_discovery.py +0 -0
  136. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/mcp_startup/startup_pipeline.py +0 -0
  137. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/shared/__init__.py +0 -0
  138. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/shared/base_step.py +0 -0
  139. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/shared/mesh_pipeline.py +0 -0
  140. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/pipeline/shared/pipeline_types.py +0 -0
  141. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/__init__.py +0 -0
  142. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/config_resolver.py +0 -0
  143. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/content_extractor.py +0 -0
  144. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/defaults.py +0 -0
  145. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/fast_heartbeat_status.py +0 -0
  146. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/fastapi_middleware_manager.py +0 -0
  147. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/host_resolver.py +0 -0
  148. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/server_discovery.py +0 -0
  149. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/simple_shutdown.py +0 -0
  150. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/shared/support_types.py +0 -0
  151. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/agent_context_helper.py +0 -0
  152. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/context.py +0 -0
  153. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/redis_metadata_publisher.py +0 -0
  154. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/tracing/utils.py +0 -0
  155. {mcp_mesh-0.6.4 → mcp_mesh-0.7.15}/_mcp_mesh/utils/fastmcp_schema_extractor.py +0 -0
@@ -174,14 +174,15 @@ cython_debug/
174
174
  logs/
175
175
  .logs/
176
176
  capability_store/
177
+ prompts/
177
178
  *.db
178
179
  *.pid
179
180
 
180
181
  # Go binaries
181
182
  mcp-mesh-dev
182
183
  /mcp-mesh-registry
183
- meshctl
184
- bin/meshctl
184
+ /meshctl
185
+ bin/
185
186
  *.exe
186
187
  *.dll
187
188
  *.dylib
@@ -236,3 +237,11 @@ packaging/pypi/README.md
236
237
  packaging/pypi/LICENSE
237
238
  packaging/pypi/dist/
238
239
  MEDIUM-POST-MULTI-AGENT-POC.md
240
+
241
+ # Helm chart dependency packages (regenerate with: helm dependency update)
242
+ helm/*/charts/*.tgz
243
+
244
+ # Helm chart files copied during release (generated from observability/)
245
+ helm/mcp-mesh-grafana/files/
246
+ helm/mcp-mesh-tempo/files/
247
+ *.DS_Store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-mesh
3
- Version: 0.6.4
3
+ Version: 0.7.15
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
@@ -31,7 +31,7 @@ from .engine.decorator_registry import (
31
31
  get_decorator_stats,
32
32
  )
33
33
 
34
- __version__ = "0.6.4"
34
+ __version__ = "0.7.15"
35
35
 
36
36
  # Store reference to runtime processor if initialized
37
37
  _runtime_processor = None
@@ -17,13 +17,8 @@ __all__ = [
17
17
  # Dependency injection
18
18
  "DependencyInjector",
19
19
  "get_global_injector",
20
- # MCP client proxies (legacy)
21
- "MCPClientProxy",
22
- "EnhancedMCPClientProxy",
23
- "FullMCPProxy",
24
- "EnhancedFullMCPProxy",
20
+ # MCP client proxies
25
21
  "AsyncMCPClient",
26
- # Unified MCP proxy (recommended)
27
22
  "UnifiedMCPProxy",
28
23
  "EnhancedUnifiedMCPProxy",
29
24
  # Self-dependency proxy
@@ -59,22 +54,6 @@ def __getattr__(name):
59
54
 
60
55
  return get_global_injector
61
56
  # MCP client proxies
62
- elif name == "MCPClientProxy":
63
- from .mcp_client_proxy import MCPClientProxy
64
-
65
- return MCPClientProxy
66
- elif name == "EnhancedMCPClientProxy":
67
- from .mcp_client_proxy import EnhancedMCPClientProxy
68
-
69
- return EnhancedMCPClientProxy
70
- elif name == "FullMCPProxy":
71
- from .full_mcp_proxy import FullMCPProxy
72
-
73
- return FullMCPProxy
74
- elif name == "EnhancedFullMCPProxy":
75
- from .full_mcp_proxy import EnhancedFullMCPProxy
76
-
77
- return EnhancedFullMCPProxy
78
57
  elif name == "AsyncMCPClient":
79
58
  from .async_mcp_client import AsyncMCPClient
80
59
 
@@ -1,10 +1,12 @@
1
1
  """Async HTTP client for MCP JSON-RPC protocol."""
2
2
 
3
+ import asyncio
4
+ import atexit
3
5
  import json
4
6
  import logging
5
7
  import urllib.error
6
8
  import urllib.request
7
- from typing import Any
9
+ from typing import Any, ClassVar, Optional
8
10
 
9
11
  from ..shared.sse_parser import SSEParser
10
12
 
@@ -12,13 +14,67 @@ logger = logging.getLogger(__name__)
12
14
 
13
15
 
14
16
  class AsyncMCPClient:
15
- """Async HTTP client for MCP JSON-RPC protocol."""
17
+ """Async HTTP client for MCP JSON-RPC protocol.
18
+
19
+ Uses connection pooling to reuse HTTP connections across requests,
20
+ reducing TCP/SSL handshake overhead and preventing port exhaustion.
21
+ """
22
+
23
+ # Class-level connection pool (shared across instances for same endpoint)
24
+ _client_pool: ClassVar[dict[str, "httpx.AsyncClient"]] = {}
25
+ _pool_lock: ClassVar[Optional[asyncio.Lock]] = None
26
+
27
+ # Default connection limits for pooling
28
+ DEFAULT_MAX_CONNECTIONS = 100
29
+ DEFAULT_MAX_KEEPALIVE_CONNECTIONS = 20
16
30
 
17
31
  def __init__(self, endpoint: str, timeout: float = 30.0):
18
32
  self.endpoint = endpoint
19
33
  self.timeout = timeout
20
34
  self.logger = logger.getChild(f"client.{endpoint}")
21
35
 
36
+ @classmethod
37
+ def _get_lock(cls) -> asyncio.Lock:
38
+ """Get or create the class-level lock (handles event loop creation)."""
39
+ if cls._pool_lock is None:
40
+ cls._pool_lock = asyncio.Lock()
41
+ return cls._pool_lock
42
+
43
+ @classmethod
44
+ async def _get_pooled_client(
45
+ cls, endpoint: str, timeout: float
46
+ ) -> "httpx.AsyncClient":
47
+ """Get or create a pooled httpx client for the endpoint.
48
+
49
+ This enables connection reuse across multiple requests to the same endpoint,
50
+ significantly reducing overhead from TCP connection establishment and SSL handshakes.
51
+ """
52
+ import httpx
53
+
54
+ async with cls._get_lock():
55
+ if endpoint not in cls._client_pool:
56
+ cls._client_pool[endpoint] = httpx.AsyncClient(
57
+ timeout=timeout,
58
+ limits=httpx.Limits(
59
+ max_connections=cls.DEFAULT_MAX_CONNECTIONS,
60
+ max_keepalive_connections=cls.DEFAULT_MAX_KEEPALIVE_CONNECTIONS,
61
+ ),
62
+ )
63
+ logger.debug(f"Created pooled client for endpoint: {endpoint}")
64
+ return cls._client_pool[endpoint]
65
+
66
+ @classmethod
67
+ async def close_all_clients(cls) -> None:
68
+ """Close all pooled clients. Call during application shutdown."""
69
+ async with cls._get_lock():
70
+ for endpoint, client in list(cls._client_pool.items()):
71
+ try:
72
+ await client.aclose()
73
+ logger.debug(f"Closed pooled client for: {endpoint}")
74
+ except Exception as e:
75
+ logger.warning(f"Error closing client for {endpoint}: {e}")
76
+ cls._client_pool.clear()
77
+
22
78
  async def call_tool(self, tool_name: str, arguments: dict) -> Any:
23
79
  """Call remote tool using MCP JSON-RPC protocol."""
24
80
  payload = {
@@ -38,37 +94,39 @@ class AsyncMCPClient:
38
94
  raise
39
95
 
40
96
  async def _make_request(self, payload: dict) -> dict:
41
- """Make async HTTP request to MCP endpoint."""
97
+ """Make async HTTP request to MCP endpoint using pooled connections."""
42
98
  url = f"{self.endpoint}/mcp"
43
99
 
44
100
  try:
45
- # Use httpx for proper async HTTP requests (better threading support than aiohttp)
101
+ # Use httpx with connection pooling for better resource management
46
102
  import httpx
47
103
 
48
- async with httpx.AsyncClient(timeout=self.timeout) as client:
49
- response = await client.post(
50
- url,
51
- json=payload,
52
- headers={
53
- "Content-Type": "application/json",
54
- "Accept": "application/json, text/event-stream",
55
- },
56
- )
104
+ # Get pooled client (reuses connections across requests)
105
+ client = await self._get_pooled_client(self.endpoint, self.timeout)
57
106
 
58
- if response.status_code == 404:
59
- raise RuntimeError(f"MCP endpoint not found at {url}")
60
- elif response.status_code >= 400:
61
- raise RuntimeError(
62
- f"HTTP error {response.status_code}: {response.reason_phrase}"
63
- )
107
+ response = await client.post(
108
+ url,
109
+ json=payload,
110
+ headers={
111
+ "Content-Type": "application/json",
112
+ "Accept": "application/json, text/event-stream",
113
+ },
114
+ )
64
115
 
65
- response_text = response.text
66
-
67
- # Use shared SSE parser
68
- data = SSEParser.parse_sse_response(
69
- response_text, f"AsyncMCPClient.{self.endpoint}"
116
+ if response.status_code == 404:
117
+ raise RuntimeError(f"MCP endpoint not found at {url}")
118
+ elif response.status_code >= 400:
119
+ raise RuntimeError(
120
+ f"HTTP error {response.status_code}: {response.reason_phrase}"
70
121
  )
71
122
 
123
+ response_text = response.text
124
+
125
+ # Use shared SSE parser
126
+ data = SSEParser.parse_sse_response(
127
+ response_text, f"AsyncMCPClient.{self.endpoint}"
128
+ )
129
+
72
130
  # Check for JSON-RPC error
73
131
  if "error" in data:
74
132
  error = data["error"]
@@ -169,5 +227,10 @@ class AsyncMCPClient:
169
227
  return result
170
228
 
171
229
  async def close(self):
172
- """Close client (no persistent connection to close)."""
230
+ """Close client instance (no-op as connections are pooled at class level).
231
+
232
+ Connection pooling is managed at the class level for efficiency.
233
+ To close all pooled connections during shutdown, use:
234
+ await AsyncMCPClient.close_all_clients()
235
+ """
173
236
  pass
@@ -38,7 +38,7 @@ class LLMAgentMetadata:
38
38
 
39
39
  function: Callable
40
40
  config: dict[str, Any] # LLM configuration (provider, model, filter, etc.)
41
- output_type: Optional[type] # Pydantic model type from return annotation
41
+ output_type: type | None # Pydantic model type from return annotation
42
42
  param_name: str # Name of MeshLlmAgent parameter
43
43
  function_id: str # Unique function ID for registry
44
44
  registered_at: datetime
@@ -70,16 +70,55 @@ class DecoratorRegistry:
70
70
  _custom_decorators: dict[str, dict[str, DecoratedFunction]] = {}
71
71
 
72
72
  # Immediate uvicorn server storage (for preventing shutdown state)
73
- _immediate_uvicorn_server: Optional[dict[str, Any]] = None
73
+ _immediate_uvicorn_server: dict[str, Any] | None = None
74
74
 
75
75
  # FastMCP lifespan storage (for proper integration with FastAPI)
76
- _fastmcp_lifespan: Optional[Any] = None
76
+ _fastmcp_lifespan: Any | None = None
77
77
 
78
78
  # FastMCP HTTP app storage (the same app instance whose lifespan was extracted)
79
- _fastmcp_http_app: Optional[Any] = None
79
+ _fastmcp_http_app: Any | None = None
80
80
 
81
81
  # FastMCP server info storage (for schema extraction during heartbeat)
82
- _fastmcp_server_info: Optional[dict[str, Any]] = None
82
+ _fastmcp_server_info: dict[str, Any] | None = None
83
+
84
+ # Route-to-wrapper mapping for @mesh.route dependency injection
85
+ # Key: "METHOD:path" (e.g., "GET:/api/v1/benchmark-services")
86
+ # Value: {"wrapper": Callable, "dependencies": list[str]}
87
+ _route_wrapper_registry: dict[str, dict[str, Any]] = {}
88
+
89
+ @classmethod
90
+ def register_route_wrapper(
91
+ cls, method: str, path: str, wrapper: Callable, dependencies: list[str]
92
+ ) -> None:
93
+ """
94
+ Register a route's wrapper function for dependency injection.
95
+
96
+ Args:
97
+ method: HTTP method (e.g., "GET", "POST")
98
+ path: Route path (e.g., "/api/v1/benchmark-services")
99
+ wrapper: The injection wrapper function
100
+ dependencies: List of dependency capability names
101
+ """
102
+ route_id = f"{method}:{path}"
103
+ cls._route_wrapper_registry[route_id] = {
104
+ "wrapper": wrapper,
105
+ "dependencies": dependencies,
106
+ "method": method,
107
+ "path": path,
108
+ }
109
+ logger.debug(
110
+ f"📝 Registered route wrapper: {route_id} with {len(dependencies)} dependencies"
111
+ )
112
+
113
+ @classmethod
114
+ def get_route_wrapper(cls, route_id: str) -> dict[str, Any] | None:
115
+ """Get route wrapper info by route ID (METHOD:path)."""
116
+ return cls._route_wrapper_registry.get(route_id)
117
+
118
+ @classmethod
119
+ def get_all_route_wrappers(cls) -> dict[str, dict[str, Any]]:
120
+ """Get all registered route wrappers."""
121
+ return cls._route_wrapper_registry.copy()
83
122
 
84
123
  @classmethod
85
124
  def register_mesh_agent(cls, func: Callable, metadata: dict[str, Any]) -> None:
@@ -154,7 +193,7 @@ class DecoratorRegistry:
154
193
  cls,
155
194
  func: Callable,
156
195
  config: dict[str, Any],
157
- output_type: Optional[type],
196
+ output_type: type | None,
158
197
  param_name: str,
159
198
  function_id: str,
160
199
  ) -> None:
@@ -355,7 +394,7 @@ class DecoratorRegistry:
355
394
  return stats
356
395
 
357
396
  # Cache for resolved agent configuration to avoid repeated work
358
- _cached_agent_config: Optional[dict[str, Any]] = None
397
+ _cached_agent_config: dict[str, Any] | None = None
359
398
 
360
399
  @classmethod
361
400
  def update_agent_config(cls, updates: dict[str, Any]) -> None:
@@ -610,7 +649,7 @@ class DecoratorRegistry:
610
649
  )
611
650
 
612
651
  @classmethod
613
- def get_immediate_uvicorn_server(cls) -> Optional[dict[str, Any]]:
652
+ def get_immediate_uvicorn_server(cls) -> dict[str, Any] | None:
614
653
  """
615
654
  Get stored immediate uvicorn server reference.
616
655
 
@@ -625,27 +664,28 @@ class DecoratorRegistry:
625
664
  cls._immediate_uvicorn_server = None
626
665
  logger.debug("🔄 REGISTRY: Cleared immediate uvicorn server reference")
627
666
 
628
- # Health check result storage
629
- _health_check_result: dict | None = None
667
+ # Health check result storage (delegated to health_check_manager)
630
668
 
631
669
  @classmethod
632
670
  def store_health_check_result(cls, result: dict) -> None:
633
671
  """Store health check result for /health endpoint."""
634
- cls._health_check_result = result
635
- logger.debug(
636
- f"💾 REGISTRY: Stored health check result: {result.get('status', 'unknown')}"
637
- )
672
+ from ..shared.health_check_manager import store_health_check_result
673
+
674
+ store_health_check_result(result)
638
675
 
639
676
  @classmethod
640
677
  def get_health_check_result(cls) -> dict | None:
641
678
  """Get stored health check result."""
642
- return cls._health_check_result
679
+ from ..shared.health_check_manager import get_health_check_result
680
+
681
+ return get_health_check_result()
643
682
 
644
683
  @classmethod
645
684
  def clear_health_check_result(cls) -> None:
646
685
  """Clear stored health check result."""
647
- cls._health_check_result = None
648
- logger.debug("🗑️ REGISTRY: Cleared health check result")
686
+ from ..shared.health_check_manager import clear_health_check_result
687
+
688
+ clear_health_check_result()
649
689
 
650
690
  @classmethod
651
691
  def store_fastmcp_lifespan(cls, lifespan: Any) -> None:
@@ -659,7 +699,7 @@ class DecoratorRegistry:
659
699
  logger.debug("🔄 REGISTRY: Stored FastMCP lifespan for FastAPI integration")
660
700
 
661
701
  @classmethod
662
- def get_fastmcp_lifespan(cls) -> Optional[Any]:
702
+ def get_fastmcp_lifespan(cls) -> Any | None:
663
703
  """
664
704
  Get stored FastMCP lifespan.
665
705
 
@@ -686,7 +726,7 @@ class DecoratorRegistry:
686
726
  logger.debug("🔄 REGISTRY: Stored FastMCP HTTP app for mounting")
687
727
 
688
728
  @classmethod
689
- def get_fastmcp_http_app(cls) -> Optional[Any]:
729
+ def get_fastmcp_http_app(cls) -> Any | None:
690
730
  """
691
731
  Get stored FastMCP HTTP app.
692
732
 
@@ -715,7 +755,7 @@ class DecoratorRegistry:
715
755
  )
716
756
 
717
757
  @classmethod
718
- def get_fastmcp_server_info(cls) -> Optional[dict[str, Any]]:
758
+ def get_fastmcp_server_info(cls) -> dict[str, Any] | None:
719
759
  """
720
760
  Get stored FastMCP server info.
721
761
 
@@ -14,6 +14,11 @@ 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
+ )
17
22
  from .signature_analyzer import get_mesh_agent_positions, has_llm_agent_parameter
18
23
 
19
24
  logger = logging.getLogger(__name__)
@@ -448,17 +453,17 @@ class DependencyInjector:
448
453
 
449
454
  @functools.wraps(func)
450
455
  async def dependency_wrapper(*args, **kwargs):
456
+ # Get trace prefix if available
457
+ tp = get_trace_prefix()
458
+
459
+ # Log tool invocation - summary line
460
+ arg_keys = list(kwargs.keys()) if kwargs else []
451
461
  wrapper_logger.debug(
452
- f"🔧 DEPENDENCY_WRAPPER: Function {func.__name__} called"
453
- )
454
- wrapper_logger.debug(
455
- f"🔧 DEPENDENCY_WRAPPER: args={args}, kwargs={kwargs}"
456
- )
457
- wrapper_logger.debug(
458
- f"🔧 DEPENDENCY_WRAPPER: mesh_positions={mesh_positions}"
462
+ f"{tp}🔧 Tool '{func.__name__}' called with kwargs={arg_keys}"
459
463
  )
464
+ # Log full args (will be TRACE later)
460
465
  wrapper_logger.debug(
461
- f"🔧 DEPENDENCY_WRAPPER: dependencies={dependencies}"
466
+ f"{tp}🔧 Tool '{func.__name__}' args: {format_log_value(kwargs)}"
462
467
  )
463
468
 
464
469
  # We know mesh_positions is not empty since we checked above
@@ -468,20 +473,14 @@ class DependencyInjector:
468
473
  params = list(sig.parameters.keys())
469
474
  final_kwargs = kwargs.copy()
470
475
 
471
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: params={params}")
472
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: original kwargs={kwargs}")
473
-
474
476
  # Inject dependencies as kwargs (using array-based lookup)
475
477
  injected_count = 0
478
+ injected_deps = [] # Track what was injected for logging
476
479
  for dep_index, param_position in enumerate(mesh_positions):
477
480
  if dep_index < len(dependencies):
478
481
  dep_name = dependencies[dep_index]
479
482
  param_name = params[param_position]
480
483
 
481
- wrapper_logger.debug(
482
- f"🔧 DEPENDENCY_WRAPPER: Processing dep {dep_index}: {dep_name} -> {param_name}"
483
- )
484
-
485
484
  # Only inject if the parameter wasn't explicitly provided
486
485
  if (
487
486
  param_name not in final_kwargs
@@ -493,34 +492,25 @@ class DependencyInjector:
493
492
  dependency = dependency_wrapper._mesh_injected_deps[
494
493
  dep_index
495
494
  ]
496
- wrapper_logger.debug(
497
- f"🔧 DEPENDENCY_WRAPPER: From wrapper storage[{dep_index}]: {dependency}"
498
- )
499
495
 
500
496
  if dependency is None:
501
497
  # Fallback to global storage with composite key
502
498
  dep_key = f"{func.__module__}.{func.__qualname__}:dep_{dep_index}"
503
499
  dependency = self.get_dependency(dep_key)
504
- wrapper_logger.debug(
505
- f"🔧 DEPENDENCY_WRAPPER: From global storage[{dep_key}]: {dependency}"
506
- )
507
500
 
508
501
  final_kwargs[param_name] = dependency
509
502
  injected_count += 1
510
- wrapper_logger.debug(
511
- f"🔧 DEPENDENCY_WRAPPER: Injected {dep_name} from index {dep_index} as {param_name}"
512
- )
513
- else:
514
- wrapper_logger.debug(
515
- f"🔧 DEPENDENCY_WRAPPER: Skipping {param_name} - already provided"
503
+ # Track for consolidated logging
504
+ proxy_type = (
505
+ type(dependency).__name__ if dependency else "None"
516
506
  )
507
+ injected_deps.append(f"{dep_name} → {proxy_type}")
517
508
 
518
- wrapper_logger.debug(
519
- f"🔧 DEPENDENCY_WRAPPER: Injected {injected_count} dependencies"
520
- )
521
- wrapper_logger.debug(
522
- f"🔧 DEPENDENCY_WRAPPER: final_kwargs={final_kwargs}"
523
- )
509
+ # Log consolidated dependency injection summary
510
+ if injected_count > 0:
511
+ wrapper_logger.debug(
512
+ f"{tp}🔧 Injected {injected_count} dependencies: {', '.join(injected_deps)}"
513
+ )
524
514
 
525
515
  # ===== INJECT LLM AGENT IF PRESENT (Option A) =====
526
516
  # Check if this function has @mesh.llm metadata attached (on the original function)
@@ -534,7 +524,7 @@ class DependencyInjector:
534
524
  llm_agent = getattr(func, "_mesh_llm_agent", None)
535
525
  final_kwargs[llm_param] = llm_agent
536
526
  wrapper_logger.debug(
537
- f"🤖 LLM_INJECTION: Injected {llm_param}={llm_agent}"
527
+ f"{tp}🤖 LLM_INJECTION: Injected {llm_param}={llm_agent}"
538
528
  )
539
529
 
540
530
  # ===== EXECUTE WITH DEPENDENCY INJECTION AND TRACING =====
@@ -543,10 +533,6 @@ class DependencyInjector:
543
533
 
544
534
  original_func = func._mesh_original_func
545
535
 
546
- wrapper_logger.debug(
547
- f"🔧 DI: Executing async function {original_func.__name__} with {injected_count} injected dependencies"
548
- )
549
-
550
536
  # Use ExecutionTracer's async method for clean tracing
551
537
  result = await ExecutionTracer.trace_function_execution_async(
552
538
  original_func,
@@ -558,26 +544,32 @@ class DependencyInjector:
558
544
  wrapper_logger,
559
545
  )
560
546
 
547
+ # Log result - summary line
561
548
  wrapper_logger.debug(
562
- f"🔧 DI: Function {original_func.__name__} returned: {type(result)}"
549
+ f"{tp}🔧 Tool '{func.__name__}' returned: {format_result_summary(result)}"
563
550
  )
551
+ # Log full result (will be TRACE later)
552
+ wrapper_logger.debug(
553
+ f"{tp}🔧 Tool '{func.__name__}' result: {format_log_value(result)}"
554
+ )
555
+
564
556
  return result
565
557
 
566
558
  else:
567
559
  # Create sync wrapper for sync functions without dependencies
568
560
  @functools.wraps(func)
569
561
  def dependency_wrapper(*args, **kwargs):
562
+ # Get trace prefix if available
563
+ tp = get_trace_prefix()
564
+
565
+ # Log tool invocation - summary line
566
+ arg_keys = list(kwargs.keys()) if kwargs else []
570
567
  wrapper_logger.debug(
571
- f"🔧 DEPENDENCY_WRAPPER: Function {func.__name__} called"
572
- )
573
- wrapper_logger.debug(
574
- f"🔧 DEPENDENCY_WRAPPER: args={args}, kwargs={kwargs}"
575
- )
576
- wrapper_logger.debug(
577
- f"🔧 DEPENDENCY_WRAPPER: mesh_positions={mesh_positions}"
568
+ f"{tp}🔧 Tool '{func.__name__}' called with kwargs={arg_keys}"
578
569
  )
570
+ # Log full args (will be TRACE later)
579
571
  wrapper_logger.debug(
580
- f"🔧 DEPENDENCY_WRAPPER: dependencies={dependencies}"
572
+ f"{tp}🔧 Tool '{func.__name__}' args: {format_log_value(kwargs)}"
581
573
  )
582
574
 
583
575
  # We know mesh_positions is not empty since we checked above
@@ -589,6 +581,7 @@ class DependencyInjector:
589
581
 
590
582
  # Inject dependencies as kwargs (using array-based lookup)
591
583
  injected_count = 0
584
+ injected_deps = [] # Track what was injected for logging
592
585
  for dep_index, param_position in enumerate(mesh_positions):
593
586
  if dep_index < len(dependencies):
594
587
  dep_name = dependencies[dep_index]
@@ -613,6 +606,17 @@ class DependencyInjector:
613
606
 
614
607
  final_kwargs[param_name] = dependency
615
608
  injected_count += 1
609
+ # Track for consolidated logging
610
+ proxy_type = (
611
+ type(dependency).__name__ if dependency else "None"
612
+ )
613
+ injected_deps.append(f"{dep_name} → {proxy_type}")
614
+
615
+ # Log consolidated dependency injection summary
616
+ if injected_count > 0:
617
+ wrapper_logger.debug(
618
+ f"{tp}🔧 Injected {injected_count} dependencies: {', '.join(injected_deps)}"
619
+ )
616
620
 
617
621
  # ===== INJECT LLM AGENT IF PRESENT (Option A) =====
618
622
  # Check if this function has @mesh.llm metadata attached (on the original function)
@@ -626,19 +630,15 @@ class DependencyInjector:
626
630
  llm_agent = getattr(func, "_mesh_llm_agent", None)
627
631
  final_kwargs[llm_param] = llm_agent
628
632
  wrapper_logger.debug(
629
- f"🤖 LLM_INJECTION: Injected {llm_param}={llm_agent}"
633
+ f"{tp}🤖 LLM_INJECTION: Injected {llm_param}={llm_agent}"
630
634
  )
631
635
 
632
636
  # ===== EXECUTE WITH DEPENDENCY INJECTION AND TRACING =====
633
637
  # Use ExecutionTracer for comprehensive execution logging (v0.4.0 style)
634
638
  from ..tracing.execution_tracer import ExecutionTracer
635
639
 
636
- wrapper_logger.debug(
637
- f"🔧 DI: Executing sync function {func._mesh_original_func.__name__} with {injected_count} injected dependencies"
638
- )
639
-
640
640
  # Use ExecutionTracer for clean execution tracing
641
- return ExecutionTracer.trace_function_execution(
641
+ result = ExecutionTracer.trace_function_execution(
642
642
  func._mesh_original_func,
643
643
  args,
644
644
  final_kwargs,
@@ -648,6 +648,17 @@ class DependencyInjector:
648
648
  wrapper_logger,
649
649
  )
650
650
 
651
+ # Log result - summary line
652
+ wrapper_logger.debug(
653
+ f"{tp}🔧 Tool '{func.__name__}' returned: {format_result_summary(result)}"
654
+ )
655
+ # Log full result (will be TRACE later)
656
+ wrapper_logger.debug(
657
+ f"{tp}🔧 Tool '{func.__name__}' result: {format_log_value(result)}"
658
+ )
659
+
660
+ return result
661
+
651
662
  # Store dependency state on wrapper as array (indexed by position)
652
663
  dependency_wrapper._mesh_injected_deps = [None] * len(dependencies)
653
664
 
@@ -132,7 +132,7 @@ class HttpMcpWrapper:
132
132
 
133
133
  # Phase 3: Metadata caching
134
134
  self._metadata_cache: dict[str, Any] = {}
135
- self._cache_timestamp: Optional[datetime] = None
135
+ self._cache_timestamp: datetime | None = None
136
136
  self._cache_ttl: timedelta = timedelta(minutes=5) # Cache for 5 minutes
137
137
 
138
138
  # Phase 5: Session storage and pod info
@@ -254,7 +254,7 @@ class HttpMcpWrapper:
254
254
  self._cache_timestamp = datetime.now()
255
255
  logger.debug(f"📋 Metadata cache updated with {len(metadata)} entries")
256
256
 
257
- def get_cached_metadata(self) -> Optional[dict[str, Any]]:
257
+ def get_cached_metadata(self) -> dict[str, Any] | None:
258
258
  """Get cached metadata if available and valid."""
259
259
  if self._is_cache_valid():
260
260
  logger.debug("✅ Returning cached metadata")
@@ -391,6 +391,14 @@ class HttpMcpWrapper:
391
391
  try:
392
392
  from ..tracing.trace_context_helper import TraceContextHelper
393
393
 
394
+ # DEBUG: Log incoming headers for trace propagation debugging
395
+ trace_id_header = request.headers.get("X-Trace-ID")
396
+ parent_span_header = request.headers.get("X-Parent-Span")
397
+ self.logger.info(
398
+ f"🔍 INCOMING_HEADERS: X-Trace-ID={trace_id_header}, "
399
+ f"X-Parent-Span={parent_span_header}, path={request.url.path}"
400
+ )
401
+
394
402
  # Use helper class for trace context extraction and setup
395
403
  trace_context = (
396
404
  await TraceContextHelper.extract_trace_context_from_request(