mcp-mesh 0.6.4__py3-none-any.whl → 0.7.0__py3-none-any.whl

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.
@@ -1,6 +1,7 @@
1
1
  import logging
2
- from typing import Any, Dict
2
+ from typing import Any
3
3
 
4
+ from ...engine.decorator_registry import DecoratorRegistry
4
5
  from ...engine.dependency_injector import get_global_injector
5
6
  from ..shared import PipelineResult, PipelineStatus, PipelineStep
6
7
 
@@ -8,11 +9,11 @@ from ..shared import PipelineResult, PipelineStatus, PipelineStep
8
9
  class RouteIntegrationStep(PipelineStep):
9
10
  """
10
11
  Integrates dependency injection into FastAPI route handlers.
11
-
12
+
12
13
  This step takes the discovered FastAPI apps and @mesh.route decorated handlers,
13
14
  then applies dependency injection by replacing the route.endpoint with a
14
15
  dependency injection wrapper.
15
-
16
+
16
17
  Uses the existing dependency injection engine from MCP tools - route handlers
17
18
  are just functions, so the same injection logic applies perfectly.
18
19
  """
@@ -34,13 +35,13 @@ class RouteIntegrationStep(PipelineStep):
34
35
  # Get discovery results from context
35
36
  fastapi_apps = context.get("fastapi_apps", {})
36
37
  route_mapping = context.get("route_mapping", {})
37
-
38
+
38
39
  if not fastapi_apps:
39
40
  result.status = PipelineStatus.SKIPPED
40
41
  result.message = "No FastAPI applications found"
41
42
  self.logger.warning("⚠️ No FastAPI applications to integrate")
42
43
  return result
43
-
44
+
44
45
  if not route_mapping:
45
46
  result.status = PipelineStatus.SKIPPED
46
47
  result.message = "No @mesh.route handlers found"
@@ -50,26 +51,26 @@ class RouteIntegrationStep(PipelineStep):
50
51
  # Apply dependency injection to each app's routes
51
52
  integration_results = {}
52
53
  total_integrated = 0
53
-
54
+
54
55
  for app_id, app_info in fastapi_apps.items():
55
56
  if app_id not in route_mapping:
56
57
  continue
57
-
58
+
58
59
  app_results = self._integrate_app_routes(
59
60
  app_info, route_mapping[app_id]
60
61
  )
61
62
  integration_results[app_id] = app_results
62
63
  total_integrated += app_results["integrated_count"]
63
-
64
- self.logger.info(
65
- f"📝 Integrated {app_results['integrated_count']} routes in "
64
+
65
+ self.logger.debug(
66
+ f"Integrated {app_results['integrated_count']} routes in "
66
67
  f"'{app_info['title']}'"
67
68
  )
68
69
 
69
70
  # Store integration results in context
70
71
  result.add_context("integration_results", integration_results)
71
72
  result.add_context("total_integrated_routes", total_integrated)
72
-
73
+
73
74
  # Update result message
74
75
  result.message = f"Integrated {total_integrated} route handlers with dependency injection"
75
76
 
@@ -86,22 +87,22 @@ class RouteIntegrationStep(PipelineStep):
86
87
  return result
87
88
 
88
89
  def _integrate_app_routes(
89
- self, app_info: Dict[str, Any], route_mapping: Dict[str, Any]
90
- ) -> Dict[str, Any]:
90
+ self, app_info: dict[str, Any], route_mapping: dict[str, Any]
91
+ ) -> dict[str, Any]:
91
92
  """
92
93
  Apply dependency injection to routes in a single FastAPI app.
93
-
94
+
94
95
  Args:
95
96
  app_info: FastAPI app information from discovery
96
97
  route_mapping: Route mapping for this specific app
97
-
98
+
98
99
  Returns:
99
100
  Integration results for this app
100
101
  """
101
102
  app = app_info["instance"]
102
103
  app_title = app_info["title"]
103
104
  injector = get_global_injector()
104
-
105
+
105
106
  integration_results = {
106
107
  "app_title": app_title,
107
108
  "integrated_count": 0,
@@ -109,45 +110,41 @@ class RouteIntegrationStep(PipelineStep):
109
110
  "error_count": 0,
110
111
  "route_details": {},
111
112
  }
112
-
113
+
113
114
  # Process each @mesh.route decorated handler
114
115
  for route_name, route_info in route_mapping.items():
115
116
  try:
116
- result_detail = self._integrate_single_route(
117
- app, route_info, injector
118
- )
117
+ result_detail = self._integrate_single_route(app, route_info, injector)
119
118
  integration_results["route_details"][route_name] = result_detail
120
-
119
+
121
120
  if result_detail["status"] == "integrated":
122
121
  integration_results["integrated_count"] += 1
123
122
  elif result_detail["status"] == "skipped":
124
123
  integration_results["skipped_count"] += 1
125
124
  else:
126
125
  integration_results["error_count"] += 1
127
-
126
+
128
127
  except Exception as e:
129
- self.logger.error(
130
- f"❌ Failed to integrate route '{route_name}': {e}"
131
- )
128
+ self.logger.error(f"❌ Failed to integrate route '{route_name}': {e}")
132
129
  integration_results["error_count"] += 1
133
130
  integration_results["route_details"][route_name] = {
134
131
  "status": "error",
135
- "error": str(e)
132
+ "error": str(e),
136
133
  }
137
-
134
+
138
135
  return integration_results
139
136
 
140
137
  def _integrate_single_route(
141
- self, app, route_info: Dict[str, Any], injector
142
- ) -> Dict[str, Any]:
138
+ self, app, route_info: dict[str, Any], injector
139
+ ) -> dict[str, Any]:
143
140
  """
144
141
  Apply dependency injection to a single route handler.
145
-
142
+
146
143
  Args:
147
144
  app: FastAPI application instance
148
145
  route_info: Route information including dependencies
149
146
  injector: Dependency injector instance
150
-
147
+
151
148
  Returns:
152
149
  Integration result details
153
150
  """
@@ -156,163 +153,165 @@ class RouteIntegrationStep(PipelineStep):
156
153
  dependencies = route_info["dependencies"]
157
154
  path = route_info["path"]
158
155
  methods = route_info["methods"]
159
-
156
+
160
157
  # Extract dependency names for injector
161
158
  dependency_names = [dep["capability"] for dep in dependencies]
162
-
159
+
163
160
  self.logger.debug(
164
- f"🔧 Integrating route {methods} {path} -> {endpoint_name}() "
161
+ f"Integrating route {methods} {path} -> {endpoint_name}() "
165
162
  f"with dependencies: {dependency_names}"
166
163
  )
167
- self.logger.debug(f"🔍 Route integration processing: {original_handler} at {hex(id(original_handler))}")
168
-
164
+
169
165
  # Skip if no dependencies
170
166
  if not dependency_names:
171
- self.logger.debug(f"⚠️ Route '{endpoint_name}' has no dependencies, skipping")
167
+ self.logger.debug(f"Route '{endpoint_name}' has no dependencies, skipping")
172
168
  return {
173
169
  "status": "skipped",
174
170
  "reason": "no_dependencies",
175
- "dependency_count": 0
171
+ "dependency_count": 0,
176
172
  }
177
-
173
+
178
174
  # Check if function already has an injection wrapper (from @mesh.route decorator)
179
175
  # The function might be the wrapper itself (if decorator order is correct)
180
- is_already_wrapper = getattr(original_handler, '_mesh_is_injection_wrapper', False)
181
- existing_wrapper = getattr(original_handler, '_mesh_injection_wrapper', None)
182
-
183
- self.logger.debug(
184
- f"🔍 Checking function {original_handler} at {hex(id(original_handler))}: "
185
- f"is_wrapper={is_already_wrapper}, has_wrapper_ref={'yes' if existing_wrapper else 'no'}"
176
+ is_already_wrapper = getattr(
177
+ original_handler, "_mesh_is_injection_wrapper", False
186
178
  )
187
-
179
+ existing_wrapper = getattr(original_handler, "_mesh_injection_wrapper", None)
180
+
188
181
  if is_already_wrapper:
189
182
  self.logger.debug(
190
- f"🔄 Function '{endpoint_name}' is already an injection wrapper from @mesh.route decorator"
183
+ f"Function '{endpoint_name}' is already an injection wrapper from @mesh.route decorator"
191
184
  )
192
185
  wrapped_handler = original_handler # Use the function as-is
193
186
  elif existing_wrapper:
194
- self.logger.debug(f"🔍 Existing wrapper: {existing_wrapper} at {hex(id(existing_wrapper))}")
195
187
  self.logger.debug(
196
- f"🔄 Route '{endpoint_name}' already has injection wrapper from @mesh.route decorator, using existing wrapper"
188
+ f"Route '{endpoint_name}' already has injection wrapper from @mesh.route decorator, using existing wrapper"
197
189
  )
198
190
  wrapped_handler = existing_wrapper
199
191
  else:
200
192
  # Create dependency injection wrapper using existing engine
201
193
  self.logger.debug(
202
- f"🔧 Creating new injection wrapper for route '{endpoint_name}'"
194
+ f"Creating new injection wrapper for route '{endpoint_name}'"
203
195
  )
204
196
  try:
205
197
  wrapped_handler = injector.create_injection_wrapper(
206
198
  original_handler, dependency_names
207
199
  )
208
-
200
+
209
201
  # Preserve original handler metadata on wrapper
210
202
  wrapped_handler._mesh_route_metadata = getattr(
211
- original_handler, '_mesh_route_metadata', {}
203
+ original_handler, "_mesh_route_metadata", {}
212
204
  )
213
205
  wrapped_handler._original_handler = original_handler
214
206
  wrapped_handler._mesh_dependencies = dependency_names
215
207
  except Exception as e:
216
- self.logger.error(f"Failed to create injection wrapper for {endpoint_name}: {e}")
208
+ self.logger.error(
209
+ f"Failed to create injection wrapper for {endpoint_name}: {e}"
210
+ )
217
211
  return {
218
212
  "status": "failed",
219
213
  "reason": f"wrapper_creation_failed: {e}",
220
- "dependency_count": len(dependency_names)
214
+ "dependency_count": len(dependency_names),
221
215
  }
222
-
216
+
223
217
  # CRITICAL FIX: Check if there are multiple wrapper instances for this function
224
218
  # If so, use the one that actually receives dependency updates
225
219
  from ...engine.dependency_injector import get_global_injector
220
+
226
221
  injector = get_global_injector()
227
-
222
+
228
223
  # Find all functions that depend on the first dependency of this route
229
224
  if dependency_names:
230
- first_dep = dependency_names[0] # Use first dependency to find all instances
225
+ first_dep = dependency_names[
226
+ 0
227
+ ] # Use first dependency to find all instances
231
228
  affected_functions = injector._dependency_mapping.get(first_dep, set())
232
- self.logger.debug(f"🎯 All functions with '{first_dep}' dependency: {list(affected_functions)}")
233
-
229
+
234
230
  # Check if there are multiple instances and if so, prefer the one that's NOT __main__
235
231
  if len(affected_functions) > 1:
236
- non_main_functions = [f for f in affected_functions if not f.startswith('__main__.')]
232
+ non_main_functions = [
233
+ f for f in affected_functions if not f.startswith("__main__.")
234
+ ]
237
235
  if non_main_functions:
238
236
  # Found a non-main instance, try to get that wrapper instead
239
237
  preferred_func_id = non_main_functions[0] # Take first non-main
240
- preferred_wrapper = injector._function_registry.get(preferred_func_id)
238
+ preferred_wrapper = injector._function_registry.get(
239
+ preferred_func_id
240
+ )
241
241
  if preferred_wrapper:
242
- self.logger.debug(
243
- f"🔄 SWITCHING to preferred wrapper '{preferred_func_id}': "
244
- f"{preferred_wrapper} at {hex(id(preferred_wrapper))}"
245
- )
246
242
  wrapped_handler = preferred_wrapper
247
-
243
+
244
+ # Register the route wrapper in DecoratorRegistry for path-based dependency resolution
245
+ # This creates a mapping from METHOD:path -> wrapper function
246
+ for method in methods:
247
+ DecoratorRegistry.register_route_wrapper(
248
+ method=method,
249
+ path=path,
250
+ wrapper=wrapped_handler,
251
+ dependencies=dependency_names,
252
+ )
253
+
248
254
  # Find and replace the route handler in FastAPI
249
255
  route_replaced = self._replace_route_handler(
250
256
  app, path, methods, original_handler, wrapped_handler
251
257
  )
252
-
258
+
253
259
  if route_replaced:
254
260
  self.logger.debug(
255
- f"Route '{endpoint_name}' integrated successfully with "
256
- f"{len(dependency_names)} dependencies"
261
+ f"Route '{endpoint_name}' integrated with {len(dependency_names)} dependencies"
257
262
  )
258
263
  return {
259
264
  "status": "integrated",
260
265
  "dependency_count": len(dependency_names),
261
266
  "dependencies": dependency_names,
262
267
  "original_handler": original_handler,
263
- "wrapped_handler": wrapped_handler
268
+ "wrapped_handler": wrapped_handler,
264
269
  }
265
270
  else:
266
271
  self.logger.warning(
267
272
  f"⚠️ Failed to find route to replace for '{endpoint_name}'"
268
273
  )
269
- return {
270
- "status": "error",
271
- "error": "route_not_found_for_replacement"
272
- }
274
+ return {"status": "error", "error": "route_not_found_for_replacement"}
273
275
 
274
276
  def _replace_route_handler(
275
277
  self, app, path: str, methods: list, original_handler, wrapped_handler
276
278
  ) -> bool:
277
279
  """
278
280
  Replace the route handler in FastAPI's router.
279
-
281
+
280
282
  Args:
281
283
  app: FastAPI application instance
282
284
  path: Route path to find
283
285
  methods: HTTP methods for the route
284
286
  original_handler: Original handler function
285
287
  wrapped_handler: New wrapped handler function
286
-
288
+
287
289
  Returns:
288
290
  True if replacement was successful, False otherwise
289
291
  """
290
292
  try:
291
293
  # Find the matching route in FastAPI's router
292
294
  for route in app.router.routes:
293
- if (hasattr(route, 'endpoint') and
294
- hasattr(route, 'path') and
295
- hasattr(route, 'methods')):
296
-
295
+ if (
296
+ hasattr(route, "endpoint")
297
+ and hasattr(route, "path")
298
+ and hasattr(route, "methods")
299
+ ):
300
+
297
301
  # Match by path and endpoint function
298
- if (route.path == path and
299
- route.endpoint is original_handler):
300
-
302
+ if route.path == path and route.endpoint is original_handler:
303
+
301
304
  # Replace the endpoint with our wrapped version
302
305
  route.endpoint = wrapped_handler
303
-
304
- self.logger.debug(
305
- f"🔄 Replaced handler for {methods} {path}: "
306
- f"{original_handler.__name__} -> wrapped version"
307
- )
306
+
308
307
  return True
309
-
308
+
310
309
  # If we get here, we didn't find the route
311
310
  self.logger.warning(
312
- f"⚠️ Could not find route {methods} {path} to replace handler"
311
+ f"Could not find route {methods} {path} to replace handler"
313
312
  )
314
313
  return False
315
-
314
+
316
315
  except Exception as e:
317
316
  self.logger.error(f"❌ Error replacing route handler: {e}")
318
- return False
317
+ return False
@@ -422,6 +422,10 @@ class FastAPIServerSetupStep(PipelineStep):
422
422
  except ImportError as e:
423
423
  raise Exception(f"FastAPI not available: {e}")
424
424
 
425
+ # Note: Trace context middleware for distributed tracing is added in
426
+ # mesh/decorators.py BEFORE the FastAPI app starts. This ensures the middleware
427
+ # is properly registered since middleware cannot be added after the app starts.
428
+
425
429
  async def _add_k8s_endpoints(
426
430
  self,
427
431
  app: Any,
@@ -890,6 +894,9 @@ mcp_mesh_up{{agent="{agent_name}"}} 1
890
894
  "✅ SERVER REUSE: FastMCP lifespan already integrated, mounting same HTTP app"
891
895
  )
892
896
 
897
+ # Note: Trace context middleware is added in decorators.py BEFORE the app starts
898
+ # We cannot add middleware after the application has started
899
+
893
900
  # FastMCP lifespan is already integrated, mount the same HTTP app that was used for lifespan
894
901
  for server_key, server_instance in fastmcp_servers.items():
895
902
  try:
@@ -26,8 +26,8 @@ class ExecutionTracer:
26
26
  def __init__(self, function_name: str, logger_instance: logging.Logger):
27
27
  self.function_name = function_name
28
28
  self.logger = logger_instance
29
- self.start_time: Optional[float] = None
30
- self.trace_context: Optional[Any] = None
29
+ self.start_time: float | None = None
30
+ self.trace_context: Any | None = None
31
31
  self.execution_metadata: dict = {}
32
32
 
33
33
  def start_execution(
@@ -41,6 +41,7 @@ class ExecutionTracer:
41
41
  """Start execution tracking and log function start."""
42
42
  try:
43
43
  from .context import TraceContext
44
+ from .utils import generate_trace_id
44
45
 
45
46
  self.start_time = time.time()
46
47
  self.trace_context = TraceContext.get_current()
@@ -60,31 +61,58 @@ class ExecutionTracer:
60
61
  agent_metadata = get_agent_metadata_with_fallback(self.logger)
61
62
  self.execution_metadata.update(agent_metadata)
62
63
 
63
- if self.trace_context:
64
- # Generate a new child span ID for this function execution
65
- # Keep the same trace_id but create unique span_id per function call
66
- function_span_id = generate_span_id()
67
-
64
+ # Generate a new child span ID for this function execution
65
+ function_span_id = generate_span_id()
68
66
 
67
+ if self.trace_context:
68
+ # Have trace context - use existing trace_id, create child span
69
+ # Current trace's span_id becomes this function's parent_span
69
70
  self.execution_metadata.update(
70
71
  {
71
72
  "trace_id": self.trace_context.trace_id,
72
73
  "span_id": function_span_id, # New child span for this function
73
- "parent_span": (
74
- self.trace_context.span_id
75
- if self.trace_context.parent_span is not None
76
- else None
77
- ), # HTTP middleware span becomes parent only if not root
74
+ "parent_span": self.trace_context.span_id, # Parent's span becomes our parent
75
+ }
76
+ )
77
+
78
+ # Update TraceContext for nested calls - this span becomes the new current span
79
+ TraceContext.set_current(
80
+ trace_id=self.trace_context.trace_id,
81
+ span_id=function_span_id,
82
+ parent_span=self.trace_context.span_id,
83
+ )
84
+ else:
85
+ # No trace context (FastMCP context propagation issue) - generate root trace
86
+ # This ensures traces always have IDs even when contextvar propagation fails
87
+ root_trace_id = generate_trace_id()
88
+ self.execution_metadata.update(
89
+ {
90
+ "trace_id": root_trace_id,
91
+ "span_id": function_span_id,
92
+ "parent_span": None, # Root span has no parent
78
93
  }
79
94
  )
80
95
 
96
+ # CRITICAL: Set the TraceContext so outgoing cross-agent calls can propagate it
97
+ # Without this, inject_trace_headers_to_request() won't find the trace context
98
+ # and cross-agent traces won't be linked with parent_span
99
+ TraceContext.set_current(
100
+ trace_id=root_trace_id,
101
+ span_id=function_span_id,
102
+ parent_span=None,
103
+ )
104
+
105
+ self.logger.debug(
106
+ f"Generated root trace for {self.function_name}: trace_id={root_trace_id}"
107
+ )
108
+
81
109
  except Exception as e:
82
110
  self.logger.warning(
83
111
  f"Failed to setup execution logging for {self.function_name}: {e}"
84
112
  )
85
113
 
86
114
  def end_execution(
87
- self, result: Any = None, success: bool = True, error: Optional[str] = None
115
+ self, result: Any = None, success: bool = True, error: str | None = None
88
116
  ) -> None:
89
117
  """End execution tracking and log function completion."""
90
118
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-mesh
3
- Version: 0.6.4
3
+ Version: 0.7.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
@@ -1,15 +1,15 @@
1
- _mcp_mesh/__init__.py,sha256=38W7vaKh5qDOVTJ6vfwtwGJDjwLGJ33t1GCO9UfH34s,2719
1
+ _mcp_mesh/__init__.py,sha256=36WTfOMQ0KFZoAeTSzWMK8W0lxHcWj1Fpk5n3_xXqbI,2719
2
2
  _mcp_mesh/engine/__init__.py,sha256=2ennzbo7yJcpkXO9BqN69TruLjJfmJY4Y5VEsG644K4,3630
3
3
  _mcp_mesh/engine/async_mcp_client.py,sha256=UcbQjxtgVfeRw6DHTZhAzN1gkcKlTg-lUPEePRPQWAU,6306
4
4
  _mcp_mesh/engine/base_injector.py,sha256=qzRLZqFP2VvEFagVovkpdldvDmm3VwPHm6tHwV58a2k,5648
5
- _mcp_mesh/engine/decorator_registry.py,sha256=sb4Ng2y0hZovFzmrLdRCiwIEdwCm57WUD99cXJShTFk,26745
5
+ _mcp_mesh/engine/decorator_registry.py,sha256=zXuER3Sh-4NpqlLMtTxSxn93xBcZTDdEEjKWSCauU2U,28206
6
6
  _mcp_mesh/engine/dependency_injector.py,sha256=1bjeJ7pHUPEF_IoTF-7_Wm1pDLHphtfcFfSrUPWrWI4,31230
7
7
  _mcp_mesh/engine/full_mcp_proxy.py,sha256=PlRv7GSKqn5riOCqeCVulVdtq3z1Ug76mOkwMsOFHXw,25297
8
- _mcp_mesh/engine/http_wrapper.py,sha256=T9VQ2LZbGgCzyOVXVwdqas7-W3Wid0EwRboFUpdYWtM,20718
8
+ _mcp_mesh/engine/http_wrapper.py,sha256=OHbbxHBLyUGDoamHZ2hpYnFKapW_djQ60Y_vMOL6J70,21173
9
9
  _mcp_mesh/engine/llm_config.py,sha256=95bOsGWro5E1JGq7oZtEYhVdrzcIJqjht_r5vEdJVz4,2049
10
10
  _mcp_mesh/engine/llm_errors.py,sha256=h7BiI14u-jL8vtvBfFbFDDrN7gIw8PQjXIl5AP1SBuA,3276
11
11
  _mcp_mesh/engine/mcp_client_proxy.py,sha256=eJStwy_VQJexYYD8bOh_m4Ld3Bb8Ae_dt8N1CC41qBc,17625
12
- _mcp_mesh/engine/mesh_llm_agent.py,sha256=CcS2WX0ku1DSwUSx0H9YdV7oIiPNMs1jbxSPJvScRao,24679
12
+ _mcp_mesh/engine/mesh_llm_agent.py,sha256=AMW6Tu64aujFYwM0p0ZSd9YYaOikKZUN3utnqI0kT38,29015
13
13
  _mcp_mesh/engine/mesh_llm_agent_injector.py,sha256=isufzCBExli8tdLUZOaPuea3uQs3C_yeVXbOVSF0YIU,27270
14
14
  _mcp_mesh/engine/response_parser.py,sha256=NsOuGD7HJ0BFiiDUCp9v9cjLzVaU86HShVKzsrNnulk,8786
15
15
  _mcp_mesh/engine/self_dependency_proxy.py,sha256=OkKt0-B_ADnJlWtHiHItoZCBZ7Su0iz2unEPFfXvrs4,3302
@@ -18,7 +18,7 @@ _mcp_mesh/engine/session_manager.py,sha256=MCr0_fXBaUjXM51WU5EhDkiGvBdfzYQFVNb9D
18
18
  _mcp_mesh/engine/signature_analyzer.py,sha256=ftn9XsX0ZHWIaACdjgBVtCuIdqVU_4ST8cvcpzu4HTk,12339
19
19
  _mcp_mesh/engine/tool_executor.py,sha256=Bf_9d02EEY9_yHm1p1-5YZ4rY6MPxn4SVpI6-3sm1uo,5456
20
20
  _mcp_mesh/engine/tool_schema_builder.py,sha256=SQCxQIrSfdLu9-dLqiFurQLK7dhl0dc0xa0ibaxU-iE,3644
21
- _mcp_mesh/engine/unified_mcp_proxy.py,sha256=SmhLWXdjmgvJWOLGQk-cXrvYjGSzx98HzL0Q5jpMNIY,36326
21
+ _mcp_mesh/engine/unified_mcp_proxy.py,sha256=RIkYQGf04xxKui4kLa6N-L7KvH7XTrOy6I2AeMY9imY,36762
22
22
  _mcp_mesh/engine/provider_handlers/__init__.py,sha256=LLTCOgnuM3dlogbLmrpiMK3oB5L22eAmDC4BfxJ-L2I,593
23
23
  _mcp_mesh/engine/provider_handlers/base_provider_handler.py,sha256=J-SPFFFG1eFSUVvfsv7y4EuNM4REjSxaYWC5E_lC6Pc,4195
24
24
  _mcp_mesh/engine/provider_handlers/claude_handler.py,sha256=CCmlsWiCfIcgrLbAZzeSnl0g2pq0uDffT8zOj4F-sPQ,15727
@@ -78,12 +78,12 @@ _mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py,s
78
78
  _mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py,sha256=9Q_8WaVl0MxswRnHpkqq9GKnvOW54HW4tkrTM9oda14,4461
79
79
  _mcp_mesh/pipeline/__init__.py,sha256=9Aplh4m1z-rYTQys0JQLYlq9wTPdI72eSOhUPqcnvpA,1557
80
80
  _mcp_mesh/pipeline/api_heartbeat/__init__.py,sha256=IXTLoQLAPqQEWZ8VMWc5W_cQJkDv95rlVGXyXoQDjHk,473
81
- _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py,sha256=Q96auBnbypPnxTjiThtKMIezuZ_hUj30JaPNOZc87ng,24096
81
+ _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py,sha256=IvkvVQNyZr0Uqe2lViRpdj9kaLrxtTJ8io-gwjtK5FI,23247
82
82
  _mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py,sha256=PY4bbuZgxy3r0ccuBl-OuJvcPSMhyGz4FomxwYFhuvM,4821
83
83
  _mcp_mesh/pipeline/api_heartbeat/api_health_check.py,sha256=kDmFeOG_4tyqyJSBZjPcc7xTzGpP4vq6ObW_WBqXvzM,5130
84
84
  _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py,sha256=uBswzWOBzU8p_C0AE2DF8UwIWG4rP2zecHfPqKzNuC0,10367
85
85
  _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py,sha256=so8IyKT-Wg7lQk3ULdox9CAOrowzxpUs76e93PQnCik,13520
86
- _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py,sha256=0Qy6zau_3a2qtQdd2wzjXv-QhhzR6bwAaEun8Re9hXo,14546
86
+ _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py,sha256=vszesutlAFXv9B4XXFutEMEBBhN54hF8eztTtDudLaI,15785
87
87
  _mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py,sha256=WBo2crcaGfxi8Q46TU-i5OMhAv0sQKz7Z9jps-GLkvM,5183
88
88
  _mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py,sha256=6N0JdXdnLkaXau4t8syt9DLgv9Y51SPfTXYK3DefBk8,3846
89
89
  _mcp_mesh/pipeline/api_startup/__init__.py,sha256=eivolkSKot2bJTWP2BV8-RKRT1Zm7SGQYuEUiTxusOQ,577
@@ -92,7 +92,7 @@ _mcp_mesh/pipeline/api_startup/api_server_setup.py,sha256=Qy0wbXyIWIQYA7CjiGVZwn
92
92
  _mcp_mesh/pipeline/api_startup/fastapi_discovery.py,sha256=MV3hvDXvX7r1Mrn6LAReu9W3hKt-5-jDhPpPYwZXnco,5770
93
93
  _mcp_mesh/pipeline/api_startup/middleware_integration.py,sha256=ybImXZlmIR6yA-wYg5Zy_ZMFF9YgToLkk4jnBeZJ7WY,6267
94
94
  _mcp_mesh/pipeline/api_startup/route_collection.py,sha256=UjA-F5_RbGVU5TfDT19Np5_x2PtYkNn2mGFyivDsk24,2031
95
- _mcp_mesh/pipeline/api_startup/route_integration.py,sha256=aMT7p7cwK8N3tZBRqeGQF8upc7tU-Exj6Dz0a4cSBhU,13441
95
+ _mcp_mesh/pipeline/api_startup/route_integration.py,sha256=qq1AVaWna-CWEXyehyDL3EyeYKgo5aMtei8uBNdvkZ8,12448
96
96
  _mcp_mesh/pipeline/mcp_heartbeat/__init__.py,sha256=nRNjZ3VD_9bPLQuJ6Nc02gE7KSLcMP7TMquB0hP6hHs,844
97
97
  _mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py,sha256=vW-qrpneBLxxQtUEwEjE7aUTv5cIO9rjDg3Bxv7nj4I,18846
98
98
  _mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py,sha256=2SKHHFTxlYwad_D8a6E7NNtWfH89jBrIO5dQAwM3Xdw,4468
@@ -105,7 +105,7 @@ _mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py,sha256=4abbOKN3echwX82PV
105
105
  _mcp_mesh/pipeline/mcp_startup/__init__.py,sha256=gS0xNmVx66bkLUMw64olMsN40ZLPH3ymwlLixZ4NuTs,1239
106
106
  _mcp_mesh/pipeline/mcp_startup/configuration.py,sha256=6LRLIxrqFMU76qrBb6GjGknUlKPZZ9iqOlxE7F9ZhLs,2808
107
107
  _mcp_mesh/pipeline/mcp_startup/decorator_collection.py,sha256=RHC6MHtfP9aP0hZ-IJjISZu72e0Pml3LU0qr7dc284w,2294
108
- _mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py,sha256=AoH3Mb79mPKvSCYH8WusJwG_LUg7HVgqK59lcyVp110,43649
108
+ _mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py,sha256=O3q3ZNZQsNZ0pL5SkkgQoOxfofzD202H0boshiT2FzI,44074
109
109
  _mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py,sha256=Pm24wrSuRGsgeUrHvMPDnNh6RhIZoznnMAUwAkllohk,10661
110
110
  _mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py,sha256=v85B0ynomvYu87eIvLe-aSZ7-Iwov2VtM4Fg3PkmrZs,3865
111
111
  _mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py,sha256=sOpzxRc0kYiXwSW9lvv8DSjliT85oZCWPODeJRuiqgg,15635
@@ -133,17 +133,17 @@ _mcp_mesh/shared/sse_parser.py,sha256=OEPnfL9xL3rsjQrbyvfUO82WljPSDeO6Z61uUwN1NA
133
133
  _mcp_mesh/shared/support_types.py,sha256=k-ICF_UwDkHxQ1D5LwFZrp-UrNb4E5dzw02CRuLW9iI,7264
134
134
  _mcp_mesh/tracing/agent_context_helper.py,sha256=BIJ3Kc4Znd6emMAu97aUhSoxSIza3qYUmObLgc9ONiA,4765
135
135
  _mcp_mesh/tracing/context.py,sha256=2ozqKEYfx4Qxj64DnbwoVIbMkhNLbaV8BNWtkzAPA7I,2516
136
- _mcp_mesh/tracing/execution_tracer.py,sha256=lJu7Uk2F4hT8W7ChJbmZUl_6DGvrndGEFes3cnYPZho,7785
136
+ _mcp_mesh/tracing/execution_tracer.py,sha256=H28EhZPb7Lyz2fG_toAbsQ7_zKANFxyBsIFlWBZg4FY,9167
137
137
  _mcp_mesh/tracing/fastapi_tracing_middleware.py,sha256=o-xyAb1hB_GIFXv0hqUeTwhDDEoFj3_brygmhSComkE,6848
138
138
  _mcp_mesh/tracing/redis_metadata_publisher.py,sha256=F78E34qnI3D0tOmbHUTBsLbDst2G7Su2-0F37Rq0rcM,4652
139
139
  _mcp_mesh/tracing/trace_context_helper.py,sha256=6tEkwjWFqMBe45zBlhacktmIpzJWTF950ph3bwL3cNc,5994
140
140
  _mcp_mesh/tracing/utils.py,sha256=t9lJuTH7CeuzAiiAaD0WxsJMFJPdzZFR0w6-vyR9f2E,3849
141
141
  _mcp_mesh/utils/fastmcp_schema_extractor.py,sha256=M54ffesC-56zl_fNJHj9dZxElDQaWFf1MXdSLCuFStg,17253
142
142
  mesh/__init__.py,sha256=0zequaBtd_9NLOLsr9sNONuwWa_fT_-G4LnJ1CHTEY0,3808
143
- mesh/decorators.py,sha256=QTd1wJ8XV0Pfjq2ejyXjyeXBtyodbj1gbs5WKG9AFTs,55632
143
+ mesh/decorators.py,sha256=_3yVrEvGHZ5MKX_pf7Zn-vLdOH68iE7o6EIvxKcGOds,57636
144
144
  mesh/helpers.py,sha256=c3FhSy9U4KBHEH6WH6MjCVrPMw9li5JAgBLUTIoamz4,9472
145
145
  mesh/types.py,sha256=9TqbJSxlybLQaPVjugcKwPiIrVnJEzqAOvPRhlX1zmo,15559
146
- mcp_mesh-0.6.4.dist-info/METADATA,sha256=AWReBPZPJbrPJOrxCIXYJRN7nkkQLegtg3aiwljW-Io,4972
147
- mcp_mesh-0.6.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
148
- mcp_mesh-0.6.4.dist-info/licenses/LICENSE,sha256=_EBQHRQThv9FPOLc5eFOUdeeRO0mYwChC7cx60dM1tM,1078
149
- mcp_mesh-0.6.4.dist-info/RECORD,,
146
+ mcp_mesh-0.7.0.dist-info/METADATA,sha256=ikNiCCs-EczkiR8EWKveRVmEdpQ0ovkxd7iyymQA3ic,4972
147
+ mcp_mesh-0.7.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
148
+ mcp_mesh-0.7.0.dist-info/licenses/LICENSE,sha256=_EBQHRQThv9FPOLc5eFOUdeeRO0mYwChC7cx60dM1tM,1078
149
+ mcp_mesh-0.7.0.dist-info/RECORD,,
mesh/decorators.py CHANGED
@@ -76,6 +76,49 @@ def _start_uvicorn_immediately(http_host: str, http_port: int):
76
76
  app = FastAPI(title="MCP Mesh Agent (Starting)")
77
77
  logger.debug("📦 IMMEDIATE UVICORN: Created minimal FastAPI app")
78
78
 
79
+ # Add trace context middleware for distributed tracing BEFORE app starts
80
+ # This must be done before uvicorn.run() since middleware can't be added after start
81
+ try:
82
+ import os
83
+
84
+ tracing_enabled = os.getenv(
85
+ "MCP_MESH_DISTRIBUTED_TRACING_ENABLED", "false"
86
+ ).lower() in ("true", "1", "yes")
87
+ if tracing_enabled:
88
+ from starlette.middleware.base import BaseHTTPMiddleware
89
+ from starlette.requests import Request
90
+
91
+ class TraceContextMiddleware(BaseHTTPMiddleware):
92
+ """Middleware to extract trace headers and set up trace context."""
93
+
94
+ async def dispatch(self, request: Request, call_next):
95
+ try:
96
+ from _mcp_mesh.tracing.trace_context_helper import (
97
+ TraceContextHelper,
98
+ )
99
+
100
+ # Extract and set trace context from headers for distributed tracing
101
+ trace_context = await TraceContextHelper.extract_trace_context_from_request(
102
+ request
103
+ )
104
+ TraceContextHelper.setup_request_trace_context(
105
+ trace_context, logger
106
+ )
107
+ except Exception as e:
108
+ # Never fail request due to tracing issues
109
+ logger.warning(f"Failed to set trace context: {e}")
110
+
111
+ return await call_next(request)
112
+
113
+ app.add_middleware(TraceContextMiddleware)
114
+ logger.debug(
115
+ "📦 IMMEDIATE UVICORN: Added trace context middleware for distributed tracing"
116
+ )
117
+ except Exception as e:
118
+ logger.warning(
119
+ f"⚠️ IMMEDIATE UVICORN: Failed to add trace context middleware: {e}"
120
+ )
121
+
79
122
  # Add health endpoint that can be updated by pipeline
80
123
  # Store health check result in a shared location that can be updated
81
124
  health_result = {"status": "starting", "message": "Agent is starting"}