mcp-mesh 0.5.1__tar.gz → 0.5.3__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 (122) hide show
  1. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/PKG-INFO +1 -1
  2. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/__init__.py +1 -1
  3. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/dependency_injector.py +53 -99
  4. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/http_wrapper.py +21 -9
  5. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/unified_mcp_proxy.py +135 -83
  6. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/api_pipeline.py +8 -5
  7. mcp_mesh-0.5.3/_mcp_mesh/pipeline/api_startup/middleware_integration.py +153 -0
  8. mcp_mesh-0.5.3/_mcp_mesh/shared/fastapi_middleware_manager.py +371 -0
  9. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/tracing/agent_context_helper.py +13 -8
  10. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/tracing/context.py +10 -4
  11. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/tracing/execution_tracer.py +26 -43
  12. mcp_mesh-0.5.3/_mcp_mesh/tracing/fastapi_tracing_middleware.py +204 -0
  13. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/tracing/redis_metadata_publisher.py +14 -34
  14. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/tracing/trace_context_helper.py +14 -19
  15. mcp_mesh-0.5.3/_mcp_mesh/tracing/utils.py +137 -0
  16. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/mesh/decorators.py +35 -0
  17. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/pyproject.toml +4 -4
  18. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/.gitignore +0 -0
  19. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/LICENSE +0 -0
  20. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/README.md +0 -0
  21. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/__init__.py +0 -0
  22. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/async_mcp_client.py +0 -0
  23. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/decorator_registry.py +0 -0
  24. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/full_mcp_proxy.py +0 -0
  25. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/mcp_client_proxy.py +0 -0
  26. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/self_dependency_proxy.py +0 -0
  27. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/session_aware_client.py +0 -0
  28. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/session_manager.py +0 -0
  29. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/engine/signature_analyzer.py +0 -0
  30. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/.openapi-generator/FILES +0 -0
  31. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/.openapi-generator/VERSION +0 -0
  32. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/.openapi-generator-ignore +0 -0
  33. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/__init__.py +0 -0
  34. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api/__init__.py +0 -0
  35. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api/agents_api.py +0 -0
  36. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api/health_api.py +0 -0
  37. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api/tracing_api.py +0 -0
  38. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api_client.py +0 -0
  39. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/api_response.py +0 -0
  40. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/configuration.py +0 -0
  41. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/exceptions.py +0 -0
  42. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/__init__.py +0 -0
  43. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_info.py +0 -0
  44. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata.py +0 -0
  45. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner.py +0 -0
  46. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner_one_of.py +0 -0
  47. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration.py +0 -0
  48. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration_metadata.py +0 -0
  49. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/agents_list_response.py +0 -0
  50. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/capability_info.py +0 -0
  51. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_metadata.py +0 -0
  52. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_request.py +0 -0
  53. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_info.py +0 -0
  54. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_info.py +0 -0
  55. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/error_response.py +0 -0
  56. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/health_response.py +0 -0
  57. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request.py +0 -0
  58. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request_metadata.py +0 -0
  59. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_response.py +0 -0
  60. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_register_metadata.py +0 -0
  61. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_registration.py +0 -0
  62. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response.py +0 -0
  63. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response_dependencies_resolved_value_inner.py +0 -0
  64. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_dependency_registration.py +0 -0
  65. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_register_metadata.py +0 -0
  66. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_registration.py +0 -0
  67. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/registration_response.py +0 -0
  68. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/rich_dependency.py +0 -0
  69. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/root_response.py +0 -0
  70. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py +0 -0
  71. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py +0 -0
  72. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/py.typed +0 -0
  73. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/generated/mcp_mesh_registry_client/rest.py +0 -0
  74. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/__init__.py +0 -0
  75. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/__init__.py +0 -0
  76. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +0 -0
  77. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +0 -0
  78. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_health_check.py +0 -0
  79. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py +0 -0
  80. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +0 -0
  81. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py +0 -0
  82. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py +0 -0
  83. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py +0 -0
  84. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/__init__.py +0 -0
  85. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/api_server_setup.py +0 -0
  86. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/fastapi_discovery.py +0 -0
  87. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/route_collection.py +0 -0
  88. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/api_startup/route_integration.py +0 -0
  89. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +0 -0
  90. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py +0 -0
  91. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py +0 -0
  92. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py +0 -0
  93. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py +0 -0
  94. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py +0 -0
  95. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/lifespan_integration.py +0 -0
  96. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py +0 -0
  97. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/__init__.py +0 -0
  98. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/configuration.py +0 -0
  99. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/decorator_collection.py +0 -0
  100. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py +0 -0
  101. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py +0 -0
  102. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py +0 -0
  103. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py +0 -0
  104. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py +0 -0
  105. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/mcp_startup/startup_pipeline.py +0 -0
  106. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/shared/__init__.py +0 -0
  107. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/shared/base_step.py +0 -0
  108. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/shared/mesh_pipeline.py +0 -0
  109. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/shared/pipeline_types.py +0 -0
  110. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/pipeline/shared/registry_connection.py +0 -0
  111. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/__init__.py +0 -0
  112. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/config_resolver.py +0 -0
  113. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/content_extractor.py +0 -0
  114. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/defaults.py +0 -0
  115. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/fast_heartbeat_status.py +0 -0
  116. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/host_resolver.py +0 -0
  117. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/logging_config.py +0 -0
  118. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/registry_client_wrapper.py +0 -0
  119. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/sse_parser.py +0 -0
  120. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/_mcp_mesh/shared/support_types.py +0 -0
  121. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/mesh/__init__.py +0 -0
  122. {mcp_mesh-0.5.1 → mcp_mesh-0.5.3}/mesh/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-mesh
3
- Version: 0.5.1
3
+ Version: 0.5.3
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.5.1"
34
+ __version__ = "0.5.3"
35
35
 
36
36
  # Store reference to runtime processor if initialized
37
37
  _runtime_processor = None
@@ -2,6 +2,8 @@
2
2
  Dynamic dependency injection system for MCP Mesh.
3
3
 
4
4
  Handles both initial injection and runtime updates when topology changes.
5
+ Focused purely on dependency injection - telemetry/tracing is handled at
6
+ the HTTP middleware layer for unified approach across MCP agents and FastAPI apps.
5
7
  """
6
8
 
7
9
  import asyncio
@@ -292,41 +294,23 @@ class DependencyInjector:
292
294
  if inspect.iscoroutinefunction(func):
293
295
  @functools.wraps(func)
294
296
  async def minimal_wrapper(*args, **kwargs):
295
- # Execute with telemetry tracing even for async functions without dependencies
296
- try:
297
- from ..tracing.execution_tracer import ExecutionTracer
298
-
299
- # Use ExecutionTracer for minimal async wrapper (no dependencies)
300
- return await ExecutionTracer.trace_function_execution_async(
301
- func, args, kwargs, [], [], 0, wrapper_logger
302
- )
303
- except ImportError:
304
- # Fallback if tracing is unavailable - never fail user function
305
- wrapper_logger.debug("🔇 Tracing unavailable, executing without telemetry")
306
- return await func(*args, **kwargs)
307
- except Exception as e:
308
- # Never fail user function due to tracing errors
309
- wrapper_logger.warning(f"⚠️ Telemetry failed, executing without: {e}")
310
- return await func(*args, **kwargs)
297
+ # Use ExecutionTracer for functions without dependencies (v0.4.0 style)
298
+ from ..tracing.execution_tracer import ExecutionTracer
299
+ wrapper_logger.debug(f"🔧 DI: Executing async function {func.__name__} (no dependencies)")
300
+
301
+ # For async functions without dependencies, use the async tracer
302
+ return await ExecutionTracer.trace_function_execution_async(
303
+ func, args, kwargs, [], [], 0, wrapper_logger
304
+ )
311
305
  else:
312
306
  @functools.wraps(func)
313
307
  def minimal_wrapper(*args, **kwargs):
314
- # Execute with telemetry tracing even for functions without dependencies
315
- try:
316
- from ..tracing.execution_tracer import ExecutionTracer
317
-
318
- # Use ExecutionTracer for minimal wrapper (no dependencies)
319
- return ExecutionTracer.trace_original_function(
320
- func, args, kwargs, wrapper_logger
321
- )
322
- except ImportError:
323
- # Fallback if tracing is unavailable - never fail user function
324
- wrapper_logger.debug("🔇 Tracing unavailable, executing without telemetry")
325
- return func(*args, **kwargs)
326
- except Exception as e:
327
- # Never fail user function due to tracing errors
328
- wrapper_logger.warning(f"⚠️ Telemetry failed, executing without: {e}")
329
- return func(*args, **kwargs)
308
+ # Use ExecutionTracer for functions without dependencies (v0.4.0 style)
309
+ from ..tracing.execution_tracer import ExecutionTracer
310
+ wrapper_logger.debug(f"🔧 DI: Executing sync function {func.__name__} (no dependencies)")
311
+
312
+ # Use original function tracer for functions without dependencies
313
+ return ExecutionTracer.trace_original_function(func, args, kwargs, wrapper_logger)
330
314
 
331
315
  # Add minimal metadata for compatibility
332
316
  minimal_wrapper._mesh_injected_deps = {}
@@ -426,54 +410,29 @@ class DependencyInjector:
426
410
  f"🔧 DEPENDENCY_WRAPPER: final_kwargs={final_kwargs}"
427
411
  )
428
412
 
429
- # ===== EXECUTE WITH TELEMETRY AND DEPENDENCY INJECTION =====
430
- # Call the original function with telemetry tracing and injected dependencies
413
+ # ===== EXECUTE WITH DEPENDENCY INJECTION AND TRACING =====
414
+ # Use ExecutionTracer for comprehensive execution logging (v0.4.0 style)
415
+ from ..tracing.execution_tracer import ExecutionTracer
416
+
431
417
  original_func = func._mesh_original_func
432
418
 
433
- # Execute with telemetry tracing
434
- try:
435
- from ..tracing.execution_tracer import ExecutionTracer
436
-
437
- # Use ExecutionTracer for comprehensive telemetry
438
- if inspect.iscoroutinefunction(original_func):
439
- # For async functions, await the result directly
440
- result = await ExecutionTracer.trace_function_execution_async(
441
- original_func,
442
- args,
443
- final_kwargs,
444
- dependencies,
445
- mesh_positions,
446
- injected_count,
447
- wrapper_logger,
448
- )
449
- else:
450
- # For sync functions, call directly
451
- result = ExecutionTracer.trace_function_execution(
452
- original_func,
453
- args,
454
- final_kwargs,
455
- dependencies,
456
- mesh_positions,
457
- injected_count,
458
- wrapper_logger,
459
- )
460
- except ImportError:
461
- # Fallback if tracing is unavailable - never fail user function
462
- wrapper_logger.debug("🔇 Tracing unavailable, executing without telemetry")
463
- if inspect.iscoroutinefunction(original_func):
464
- result = await original_func(*args, **final_kwargs)
465
- else:
466
- result = original_func(*args, **final_kwargs)
467
- except Exception as e:
468
- # Never fail user function due to tracing errors
469
- wrapper_logger.warning(f"⚠️ Telemetry failed, executing without: {e}")
470
- if inspect.iscoroutinefunction(original_func):
471
- result = await original_func(*args, **final_kwargs)
472
- else:
473
- result = original_func(*args, **final_kwargs)
419
+ wrapper_logger.debug(
420
+ f"🔧 DI: Executing async function {original_func.__name__} with {injected_count} injected dependencies"
421
+ )
422
+
423
+ # Use ExecutionTracer's async method for clean tracing
424
+ result = await ExecutionTracer.trace_function_execution_async(
425
+ original_func,
426
+ args,
427
+ final_kwargs,
428
+ dependencies,
429
+ mesh_positions,
430
+ injected_count,
431
+ wrapper_logger,
432
+ )
474
433
 
475
434
  wrapper_logger.debug(
476
- f"🔧 DEPENDENCY_WRAPPER: Original returned: {type(result)}"
435
+ f"🔧 DI: Function {original_func.__name__} returned: {type(result)}"
477
436
  )
478
437
  return result
479
438
 
@@ -524,29 +483,24 @@ class DependencyInjector:
524
483
  final_kwargs[param_name] = dependency
525
484
  injected_count += 1
526
485
 
527
- # ===== EXECUTE WITH TELEMETRY AND DEPENDENCY INJECTION =====
528
- # Call the original function with telemetry tracing and injected dependencies
529
- try:
530
- from ..tracing.execution_tracer import ExecutionTracer
531
-
532
- # Use ExecutionTracer for comprehensive telemetry
533
- return ExecutionTracer.trace_function_execution(
534
- func._mesh_original_func,
535
- args,
536
- final_kwargs,
537
- dependencies,
538
- mesh_positions,
539
- injected_count,
540
- wrapper_logger,
541
- )
542
- except ImportError:
543
- # Fallback if tracing is unavailable - never fail user function
544
- wrapper_logger.debug("🔇 Tracing unavailable, executing without telemetry")
545
- return func._mesh_original_func(*args, **final_kwargs)
546
- except Exception as e:
547
- # Never fail user function due to tracing errors
548
- wrapper_logger.warning(f"⚠️ Telemetry failed, executing without: {e}")
549
- return func._mesh_original_func(*args, **final_kwargs)
486
+ # ===== EXECUTE WITH DEPENDENCY INJECTION AND TRACING =====
487
+ # Use ExecutionTracer for comprehensive execution logging (v0.4.0 style)
488
+ from ..tracing.execution_tracer import ExecutionTracer
489
+
490
+ wrapper_logger.debug(
491
+ f"🔧 DI: Executing sync function {func._mesh_original_func.__name__} with {injected_count} injected dependencies"
492
+ )
493
+
494
+ # Use ExecutionTracer for clean execution tracing
495
+ return ExecutionTracer.trace_function_execution(
496
+ func._mesh_original_func,
497
+ args,
498
+ final_kwargs,
499
+ dependencies,
500
+ mesh_positions,
501
+ injected_count,
502
+ wrapper_logger,
503
+ )
550
504
 
551
505
  # Store dependency state on wrapper
552
506
  dependency_wrapper._mesh_injected_deps = {}
@@ -395,11 +395,10 @@ class HttpMcpWrapper:
395
395
  from starlette.responses import Response
396
396
 
397
397
  class MCPSessionRoutingMiddleware(BaseHTTPMiddleware):
398
- """Session routing middleware for MCP requests.
398
+ """Clean session routing middleware for MCP requests (v0.4.0 style).
399
399
 
400
- Handles session affinity by routing requests to appropriate pods
401
- based on session ID. Telemetry/tracing is now handled in the
402
- DI function wrapper for unified coverage of both MCP and API calls.
400
+ Handles session affinity and basic trace context setup only.
401
+ Function execution tracing is handled by ExecutionTracer in DependencyInjector.
403
402
  """
404
403
  def __init__(self, app, http_wrapper):
405
404
  super().__init__(app)
@@ -407,10 +406,23 @@ class HttpMcpWrapper:
407
406
  self.logger = logger
408
407
 
409
408
  async def dispatch(self, request: Request, call_next):
410
- # Only handle MCP requests (FastMCP app already only handles /mcp)
411
-
412
- # Note: Telemetry/tracing now handled in DI function wrapper for unified approach
413
- # This middleware focuses purely on session routing
409
+ # Extract and set trace context from headers for distributed tracing
410
+ try:
411
+ from ..tracing.trace_context_helper import TraceContextHelper
412
+
413
+ # Use helper class for trace context extraction and setup
414
+ trace_context = (
415
+ await TraceContextHelper.extract_trace_context_from_request(
416
+ request
417
+ )
418
+ )
419
+ TraceContextHelper.setup_request_trace_context(
420
+ trace_context, self.logger
421
+ )
422
+ except Exception as e:
423
+ # Never fail request due to tracing issues
424
+ self.logger.warning(f"Failed to set trace context: {e}")
425
+ pass
414
426
 
415
427
  # Extract session ID from request
416
428
  session_id = await self.http_wrapper._extract_session_id(request)
@@ -443,7 +455,7 @@ class HttpMcpWrapper:
443
455
 
444
456
  # Add the middleware to FastMCP app
445
457
  self._mcp_app.add_middleware(MCPSessionRoutingMiddleware, http_wrapper=self)
446
- logger.info("✅ Session routing middleware added to FastMCP app")
458
+ logger.info("✅ Clean session routing middleware added to FastMCP app (v0.4.0 style)")
447
459
 
448
460
  async def _extract_session_id(self, request) -> str:
449
461
  """Extract session ID from request headers or body."""
@@ -56,6 +56,67 @@ class UnifiedMCPProxy:
56
56
  f"🔧 UnifiedMCPProxy initialized with kwargs: {self.kwargs_config}"
57
57
  )
58
58
 
59
+ def _create_fastmcp_client(self, endpoint: str):
60
+ """Create FastMCP client with automatic trace header injection.
61
+
62
+ This method automatically detects trace context and adds distributed tracing
63
+ headers when available, while maintaining full backward compatibility.
64
+
65
+ Args:
66
+ endpoint: MCP endpoint URL
67
+
68
+ Returns:
69
+ FastMCP Client instance with or without trace headers
70
+ """
71
+ try:
72
+ from fastmcp import Client
73
+ from fastmcp.client.transports import StreamableHttpTransport
74
+
75
+ # Try to get current trace context for header injection
76
+ trace_headers = self._get_trace_headers()
77
+
78
+ if trace_headers:
79
+ # Create client with trace headers for distributed tracing
80
+ transport = StreamableHttpTransport(url=endpoint, headers=trace_headers)
81
+ return Client(transport)
82
+ else:
83
+ # Create standard client when no trace context available
84
+ return Client(endpoint)
85
+
86
+ except ImportError:
87
+ # If StreamableHttpTransport not available, fall back to standard client
88
+ from fastmcp import Client
89
+
90
+ return Client(endpoint)
91
+ except Exception as e:
92
+ # Any other error, fall back to standard client
93
+ from fastmcp import Client
94
+
95
+ return Client(endpoint)
96
+
97
+ def _get_trace_headers(self) -> dict[str, str]:
98
+ """Extract trace headers from current context for distributed tracing.
99
+
100
+ Returns:
101
+ Dict of trace headers or empty dict if no trace context available
102
+ """
103
+ try:
104
+ from ..tracing.context import TraceContext
105
+
106
+ current_trace = TraceContext.get_current()
107
+ if current_trace:
108
+ headers = {
109
+ "X-Trace-ID": current_trace.trace_id,
110
+ "X-Parent-Span": current_trace.span_id, # Current span becomes parent for downstream
111
+ }
112
+ return headers
113
+ else:
114
+ return {}
115
+
116
+ except Exception as e:
117
+ # Never fail MCP calls due to tracing issues
118
+ return {}
119
+
59
120
  def _configure_from_kwargs(self):
60
121
  """Auto-configure proxy settings from kwargs."""
61
122
  # Basic configuration
@@ -213,74 +274,63 @@ class UnifiedMCPProxy:
213
274
  return await self.call_tool_with_tracing(self.function_name, kwargs)
214
275
 
215
276
  async def call_tool_with_tracing(self, name: str, arguments: dict = None) -> Any:
216
- """Call a tool with comprehensive tracing and telemetry."""
217
- # Check if telemetry is enabled
218
- if not self.telemetry_enabled:
219
- self.logger.debug(f"🔇 Telemetry disabled, calling tool directly: {name}")
220
- return await self.call_tool(name, arguments)
221
-
222
- # Import tracing dependencies
277
+ """Call a tool with clean ExecutionTracer integration (v0.4.0 style)."""
278
+ # Check if telemetry is enabled - use same check as ExecutionTracer for consistency
223
279
  from ..tracing.execution_tracer import ExecutionTracer
280
+ from ..tracing.utils import is_tracing_enabled
224
281
 
225
- # Initialize execution tracer
226
- tracer = ExecutionTracer(name, self.logger)
227
-
228
- try:
229
- # Start execution tracing with proxy metadata
230
- tracer.start_execution(
231
- args=(),
232
- kwargs=arguments or {},
233
- dependencies=[self.endpoint],
234
- mesh_positions=[],
235
- injected_count=1, # This is an injected dependency call
236
- )
237
-
238
- # Add proxy-specific metadata
239
- tracer.execution_metadata.update(
240
- {
241
- "call_type": "unified_mcp_proxy",
242
- "endpoint": self.endpoint,
243
- "function_name": name,
244
- "proxy_type": "fastmcp_with_fallback",
245
- "streaming_capable": self.streaming_capable,
246
- "timeout": self.timeout,
247
- "retry_count": self.retry_count,
248
- }
249
- )
250
-
251
- # Add enhanced agent context metadata if enabled
252
- if self.collect_agent_context:
253
- try:
254
- agent_context = self._collect_agent_context_metadata(
255
- name, arguments
256
- )
257
- tracer.execution_metadata.update(agent_context)
258
- except Exception as e:
259
- self.logger.debug(f"Failed to collect agent context metadata: {e}")
260
- # Add minimal fallback metadata
261
- tracer.execution_metadata.update(
262
- {
263
- "client_agent_id": "unknown",
264
- "target_agent_endpoint": self.endpoint,
265
- "proxy_instance_id": id(self),
266
- }
267
- )
282
+ if not self.telemetry_enabled or not is_tracing_enabled():
283
+ return await self.call_tool(name, arguments)
268
284
 
269
- # Perform the actual tool call
270
- result = await self.call_tool(name, arguments)
285
+ # Create wrapper function for ExecutionTracer compatibility
286
+ async def proxy_call_wrapper(*args, **kwargs):
287
+ # Add proxy-specific metadata to execution context if tracer is available
288
+ try:
289
+ from ..tracing.context import TraceContext
290
+
291
+ current_trace = TraceContext.get_current()
292
+ if current_trace and hasattr(current_trace, "execution_metadata"):
293
+ # Add proxy metadata to current trace
294
+ proxy_metadata = {
295
+ "call_type": "unified_mcp_proxy",
296
+ "endpoint": self.endpoint,
297
+ "proxy_type": "fastmcp_with_fallback",
298
+ "streaming_capable": self.streaming_capable,
299
+ "timeout": self.timeout,
300
+ "retry_count": self.retry_count,
301
+ }
271
302
 
272
- # End tracing with success
273
- tracer.end_execution(result, success=True)
303
+ # Add enhanced agent context if enabled
304
+ if self.collect_agent_context:
305
+ try:
306
+ agent_context = self._collect_agent_context_metadata(
307
+ name, arguments
308
+ )
309
+ proxy_metadata.update(agent_context)
310
+ except Exception as e:
311
+ self.logger.debug(
312
+ f"Failed to collect agent context metadata: {e}"
313
+ )
314
+
315
+ # Update current execution metadata
316
+ if hasattr(current_trace, "execution_metadata"):
317
+ current_trace.execution_metadata.update(proxy_metadata)
274
318
 
275
- self.logger.info(f"✅ Traced tool call '{name}' succeeded")
276
- return result
319
+ except Exception as e:
320
+ self.logger.debug(f"Failed to add proxy metadata: {e}")
277
321
 
278
- except Exception as e:
279
- # End tracing with error
280
- tracer.end_execution(error=str(e), success=False)
322
+ return await self.call_tool(name, arguments)
281
323
 
282
- self.logger.error(f"❌ Traced tool call '{name}' failed: {e}")
283
- raise # Re-raise the exception
324
+ # Use ExecutionTracer's static async method for clean integration
325
+ return await ExecutionTracer.trace_function_execution_async(
326
+ proxy_call_wrapper,
327
+ args=(),
328
+ kwargs={}, # arguments are handled inside the wrapper
329
+ dependencies=[self.endpoint],
330
+ mesh_positions=[],
331
+ injected_count=1,
332
+ logger_instance=self.logger,
333
+ )
284
334
 
285
335
  async def call_tool(self, name: str, arguments: dict = None) -> Any:
286
336
  """Call a tool using FastMCP client with HTTP transport.
@@ -292,15 +342,13 @@ class UnifiedMCPProxy:
292
342
  start_time = time.time()
293
343
 
294
344
  try:
295
- from fastmcp import Client
296
-
297
345
  # Use correct FastMCP client endpoint - agents expose MCP on /mcp
298
346
  mcp_endpoint = f"{self.endpoint}/mcp"
299
347
  self.logger.debug(f"🔄 Trying FastMCP client with endpoint: {mcp_endpoint}")
300
348
 
301
- async with Client(mcp_endpoint) as client:
302
- # Add tracing metadata for FastMCP client
303
- self.logger.debug(f"🔄 FastMCP client call with tracing: {name}")
349
+ # Create client with automatic trace header injection
350
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
351
+ async with client_instance as client:
304
352
 
305
353
  # Use FastMCP's call_tool which returns CallToolResult object
306
354
  result = await client.call_tool(name, arguments or {})
@@ -651,46 +699,51 @@ class UnifiedMCPProxy:
651
699
  # MCP Protocol Methods - using FastMCP client's superior implementation
652
700
  async def list_tools(self) -> list:
653
701
  """List available tools from remote agent."""
654
- from fastmcp import Client
655
-
656
702
  mcp_endpoint = f"{self.endpoint}/mcp"
657
- async with Client(mcp_endpoint) as client:
703
+
704
+ # Create client with automatic trace header injection
705
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
706
+ async with client_instance as client:
658
707
  result = await client.list_tools()
659
708
  return result.tools if hasattr(result, "tools") else result
660
709
 
661
710
  async def list_resources(self) -> list:
662
711
  """List available resources from remote agent."""
663
- from fastmcp import Client
664
-
665
712
  mcp_endpoint = f"{self.endpoint}/mcp"
666
- async with Client(mcp_endpoint) as client:
713
+
714
+ # Create client with automatic trace header injection
715
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
716
+ async with client_instance as client:
667
717
  result = await client.list_resources()
668
718
  return result.resources if hasattr(result, "resources") else result
669
719
 
670
720
  async def read_resource(self, uri: str) -> Any:
671
721
  """Read resource contents from remote agent."""
672
- from fastmcp import Client
673
-
674
722
  mcp_endpoint = f"{self.endpoint}/mcp"
675
- async with Client(mcp_endpoint) as client:
723
+
724
+ # Create client with automatic trace header injection
725
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
726
+ async with client_instance as client:
676
727
  result = await client.read_resource(uri)
677
728
  return result.contents if hasattr(result, "contents") else result
678
729
 
679
730
  async def list_prompts(self) -> list:
680
731
  """List available prompts from remote agent."""
681
- from fastmcp import Client
682
-
683
732
  mcp_endpoint = f"{self.endpoint}/mcp"
684
- async with Client(mcp_endpoint) as client:
733
+
734
+ # Create client with automatic trace header injection
735
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
736
+ async with client_instance as client:
685
737
  result = await client.list_prompts()
686
738
  return result.prompts if hasattr(result, "prompts") else result
687
739
 
688
740
  async def get_prompt(self, name: str, arguments: dict = None) -> Any:
689
741
  """Get prompt template from remote agent."""
690
- from fastmcp import Client
691
-
692
742
  mcp_endpoint = f"{self.endpoint}/mcp"
693
- async with Client(mcp_endpoint) as client:
743
+
744
+ # Create client with automatic trace header injection
745
+ client_instance = self._create_fastmcp_client(mcp_endpoint)
746
+ async with client_instance as client:
694
747
  result = await client.get_prompt(name, arguments or {})
695
748
  return result
696
749
 
@@ -700,8 +753,7 @@ class UnifiedMCPProxy:
700
753
 
701
754
  FastMCP client handles session management internally.
702
755
  """
703
- import uuid
704
-
756
+
705
757
  # Generate session ID for compatibility
706
758
  session_id = f"session:{uuid.uuid4().hex[:16]}"
707
759
  self.logger.debug(f"📝 Created session ID: {session_id}")
@@ -11,6 +11,7 @@ import logging
11
11
  from ..shared.mesh_pipeline import MeshPipeline
12
12
  from .api_server_setup import APIServerSetupStep
13
13
  from .fastapi_discovery import FastAPIAppDiscoveryStep
14
+ from .middleware_integration import TracingMiddlewareIntegrationStep
14
15
  from .route_collection import RouteCollectionStep
15
16
  from .route_integration import RouteIntegrationStep
16
17
 
@@ -25,7 +26,8 @@ class APIPipeline(MeshPipeline):
25
26
  1. Route collection (@mesh.route decorators)
26
27
  2. FastAPI app discovery (find user's FastAPI instances)
27
28
  3. Route integration (apply dependency injection)
28
- 4. API server setup (service registration metadata)
29
+ 4. Tracing middleware integration (add telemetry to FastAPI apps)
30
+ 5. API server setup (service registration metadata)
29
31
 
30
32
  Unlike MCP agents, API services are consumers so we focus on:
31
33
  - Dependency injection into route handlers
@@ -41,10 +43,11 @@ class APIPipeline(MeshPipeline):
41
43
  """Setup the API pipeline steps."""
42
44
  # Essential API integration steps
43
45
  steps = [
44
- RouteCollectionStep(), # Collect @mesh.route decorators
45
- FastAPIAppDiscoveryStep(), # Find user's FastAPI app instances
46
- RouteIntegrationStep(), # Apply dependency injection to routes
47
- APIServerSetupStep(), # Prepare service registration metadata
46
+ RouteCollectionStep(), # Collect @mesh.route decorators
47
+ FastAPIAppDiscoveryStep(), # Find user's FastAPI app instances
48
+ RouteIntegrationStep(), # Apply dependency injection to routes
49
+ TracingMiddlewareIntegrationStep(), # Add tracing middleware to FastAPI apps
50
+ APIServerSetupStep(), # Prepare service registration metadata
48
51
  # Note: Heartbeat integration will be added in next phase
49
52
  # Note: User controls FastAPI server startup (uvicorn/gunicorn)
50
53
  ]