mcp-mesh 0.4.2__py3-none-any.whl → 0.5.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.
Files changed (51) hide show
  1. _mcp_mesh/__init__.py +14 -3
  2. _mcp_mesh/engine/dependency_injector.py +161 -74
  3. _mcp_mesh/generated/.openapi-generator/FILES +2 -0
  4. _mcp_mesh/generated/mcp_mesh_registry_client/__init__.py +2 -0
  5. _mcp_mesh/generated/mcp_mesh_registry_client/api/__init__.py +1 -0
  6. _mcp_mesh/generated/mcp_mesh_registry_client/api/tracing_api.py +305 -0
  7. _mcp_mesh/generated/mcp_mesh_registry_client/models/__init__.py +1 -0
  8. _mcp_mesh/generated/mcp_mesh_registry_client/models/agent_info.py +10 -1
  9. _mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_registration.py +4 -4
  10. _mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py +108 -0
  11. _mcp_mesh/pipeline/__init__.py +2 -2
  12. _mcp_mesh/pipeline/api_heartbeat/__init__.py +16 -0
  13. _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +515 -0
  14. _mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +117 -0
  15. _mcp_mesh/pipeline/api_heartbeat/api_health_check.py +140 -0
  16. _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py +247 -0
  17. _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +309 -0
  18. _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py +332 -0
  19. _mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py +147 -0
  20. _mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py +97 -0
  21. _mcp_mesh/pipeline/api_startup/__init__.py +20 -0
  22. _mcp_mesh/pipeline/api_startup/api_pipeline.py +61 -0
  23. _mcp_mesh/pipeline/api_startup/api_server_setup.py +292 -0
  24. _mcp_mesh/pipeline/api_startup/fastapi_discovery.py +302 -0
  25. _mcp_mesh/pipeline/api_startup/route_collection.py +56 -0
  26. _mcp_mesh/pipeline/api_startup/route_integration.py +318 -0
  27. _mcp_mesh/pipeline/{startup → mcp_startup}/heartbeat_loop.py +1 -1
  28. _mcp_mesh/pipeline/{startup → mcp_startup}/startup_orchestrator.py +170 -5
  29. _mcp_mesh/shared/config_resolver.py +0 -3
  30. _mcp_mesh/shared/logging_config.py +2 -1
  31. {mcp_mesh-0.4.2.dist-info → mcp_mesh-0.5.0.dist-info}/METADATA +1 -1
  32. {mcp_mesh-0.4.2.dist-info → mcp_mesh-0.5.0.dist-info}/RECORD +51 -34
  33. mesh/__init__.py +3 -1
  34. mesh/decorators.py +143 -1
  35. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/__init__.py +0 -0
  36. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/dependency_resolution.py +0 -0
  37. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/fast_heartbeat_check.py +0 -0
  38. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/heartbeat_orchestrator.py +0 -0
  39. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/heartbeat_pipeline.py +0 -0
  40. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/heartbeat_send.py +0 -0
  41. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/lifespan_integration.py +0 -0
  42. /_mcp_mesh/pipeline/{heartbeat → mcp_heartbeat}/registry_connection.py +0 -0
  43. /_mcp_mesh/pipeline/{startup → mcp_startup}/__init__.py +0 -0
  44. /_mcp_mesh/pipeline/{startup → mcp_startup}/configuration.py +0 -0
  45. /_mcp_mesh/pipeline/{startup → mcp_startup}/decorator_collection.py +0 -0
  46. /_mcp_mesh/pipeline/{startup → mcp_startup}/fastapiserver_setup.py +0 -0
  47. /_mcp_mesh/pipeline/{startup → mcp_startup}/fastmcpserver_discovery.py +0 -0
  48. /_mcp_mesh/pipeline/{startup → mcp_startup}/heartbeat_preparation.py +0 -0
  49. /_mcp_mesh/pipeline/{startup → mcp_startup}/startup_pipeline.py +0 -0
  50. {mcp_mesh-0.4.2.dist-info → mcp_mesh-0.5.0.dist-info}/WHEEL +0 -0
  51. {mcp_mesh-0.4.2.dist-info → mcp_mesh-0.5.0.dist-info}/licenses/LICENSE +0 -0
_mcp_mesh/__init__.py CHANGED
@@ -31,7 +31,7 @@ from .engine.decorator_registry import (
31
31
  get_decorator_stats,
32
32
  )
33
33
 
34
- __version__ = "0.4.2"
34
+ __version__ = "0.5.0"
35
35
 
36
36
  # Store reference to runtime processor if initialized
37
37
  _runtime_processor = None
@@ -48,7 +48,7 @@ def initialize_runtime():
48
48
  # Legacy processor system has been replaced by pipeline architecture
49
49
 
50
50
  # Use pipeline-based runtime
51
- from .pipeline.startup import start_runtime
51
+ from .pipeline.mcp_startup import start_runtime
52
52
 
53
53
  start_runtime()
54
54
 
@@ -60,7 +60,18 @@ def initialize_runtime():
60
60
 
61
61
  # Auto-initialize runtime if enabled
62
62
  if os.getenv("MCP_MESH_ENABLED", "true").lower() == "true":
63
- initialize_runtime()
63
+ # Use debounced initialization instead of immediate MCP startup
64
+ # This allows the system to determine MCP vs API pipeline based on decorators
65
+ try:
66
+ from .pipeline.mcp_startup import start_runtime
67
+
68
+ # Start the debounced runtime (sets up coordinator, no immediate pipeline execution)
69
+ start_runtime()
70
+
71
+ sys.stderr.write("MCP Mesh debounced runtime initialized\n")
72
+ except Exception as e:
73
+ # Log but don't fail - allows graceful degradation
74
+ sys.stderr.write(f"MCP Mesh runtime initialization failed: {e}\n")
64
75
 
65
76
 
66
77
  __all__ = [
@@ -126,6 +126,9 @@ class DependencyInjector:
126
126
  for func_id in self._dependency_mapping[name]:
127
127
  if func_id in self._function_registry:
128
128
  func = self._function_registry[func_id]
129
+ logger.debug(
130
+ f"🔄 UPDATING dependency '{name}' for {func_id} -> {func} at {hex(id(func))}"
131
+ )
129
132
  if hasattr(func, "_mesh_update_dependency"):
130
133
  func._mesh_update_dependency(name, instance)
131
134
 
@@ -279,99 +282,180 @@ class DependencyInjector:
279
282
  # Capture logger in local scope to avoid NameError
280
283
  wrapper_logger = logger
281
284
 
282
- @functools.wraps(func)
283
- def dependency_wrapper(*args, **kwargs):
284
- wrapper_logger.debug(
285
- f"🔧 DEPENDENCY_WRAPPER: Function {func.__name__} called"
285
+ # If no mesh positions to inject, create minimal wrapper for tracking
286
+ if not mesh_positions:
287
+ logger.debug(
288
+ f"🔧 No injection positions for {func.__name__}, creating minimal wrapper for tracking"
286
289
  )
287
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: args={args}, kwargs={kwargs}")
288
- wrapper_logger.debug(
289
- f"🔧 DEPENDENCY_WRAPPER: mesh_positions={mesh_positions}"
290
+
291
+ @functools.wraps(func)
292
+ def minimal_wrapper(*args, **kwargs):
293
+ return func(*args, **kwargs)
294
+
295
+ # Add minimal metadata for compatibility
296
+ minimal_wrapper._mesh_injected_deps = {}
297
+ minimal_wrapper._mesh_dependencies = dependencies
298
+ minimal_wrapper._mesh_positions = mesh_positions
299
+ minimal_wrapper._mesh_parameter_types = get_agent_parameter_types(func)
300
+ minimal_wrapper._mesh_original_func = func
301
+
302
+ def update_dependency(name: str, instance: Any | None) -> None:
303
+ """No-op update for functions without injection positions."""
304
+ pass
305
+
306
+ minimal_wrapper._mesh_update_dependency = update_dependency
307
+
308
+ # Register this wrapper for dependency updates (even though it won't use them)
309
+ logger.debug(
310
+ f"🔧 REGISTERING minimal wrapper: {func_id} -> {minimal_wrapper} at {hex(id(minimal_wrapper))}"
290
311
  )
291
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: dependencies={dependencies}")
312
+ self._function_registry[func_id] = minimal_wrapper
313
+
314
+ return minimal_wrapper
292
315
 
293
- # If no mesh positions to inject into, still do execution logging but call original function
294
- if not mesh_positions:
316
+ # Determine if we need async wrapper
317
+ need_async_wrapper = inspect.iscoroutinefunction(func)
318
+
319
+ if need_async_wrapper:
320
+
321
+ @functools.wraps(func)
322
+ async def dependency_wrapper(*args, **kwargs):
295
323
  wrapper_logger.debug(
296
- "🔧 DEPENDENCY_WRAPPER: No mesh positions, calling original with execution logging"
324
+ f"🔧 DEPENDENCY_WRAPPER: Function {func.__name__} called"
297
325
  )
298
- from ..tracing.execution_tracer import ExecutionTracer
299
-
300
- return ExecutionTracer.trace_original_function(
301
- func._mesh_original_func, args, kwargs, wrapper_logger
326
+ wrapper_logger.debug(
327
+ f"🔧 DEPENDENCY_WRAPPER: args={args}, kwargs={kwargs}"
328
+ )
329
+ wrapper_logger.debug(
330
+ f"🔧 DEPENDENCY_WRAPPER: mesh_positions={mesh_positions}"
331
+ )
332
+ wrapper_logger.debug(
333
+ f"🔧 DEPENDENCY_WRAPPER: dependencies={dependencies}"
302
334
  )
303
335
 
304
- # Get function signature
305
- sig = inspect.signature(func)
306
- params = list(sig.parameters.keys())
307
- final_kwargs = kwargs.copy()
336
+ # We know mesh_positions is not empty since we checked above
308
337
 
309
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: params={params}")
310
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: original kwargs={kwargs}")
338
+ # Get function signature
339
+ sig = inspect.signature(func)
340
+ params = list(sig.parameters.keys())
341
+ final_kwargs = kwargs.copy()
311
342
 
312
- # Inject dependencies as kwargs
313
- injected_count = 0
314
- for dep_index, param_position in enumerate(mesh_positions):
315
- if dep_index < len(dependencies):
316
- dep_name = dependencies[dep_index]
317
- param_name = params[param_position]
343
+ wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: params={params}")
344
+ wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: original kwargs={kwargs}")
318
345
 
319
- wrapper_logger.debug(
320
- f"🔧 DEPENDENCY_WRAPPER: Processing dep {dep_index}: {dep_name} -> {param_name}"
321
- )
346
+ # Inject dependencies as kwargs
347
+ injected_count = 0
348
+ for dep_index, param_position in enumerate(mesh_positions):
349
+ if dep_index < len(dependencies):
350
+ dep_name = dependencies[dep_index]
351
+ param_name = params[param_position]
322
352
 
323
- # Only inject if the parameter wasn't explicitly provided
324
- if (
325
- param_name not in final_kwargs
326
- or final_kwargs.get(param_name) is None
327
- ):
328
- # Get the dependency from wrapper's storage
329
- dependency = dependency_wrapper._mesh_injected_deps.get(
330
- dep_name
331
- )
332
353
  wrapper_logger.debug(
333
- f"🔧 DEPENDENCY_WRAPPER: From wrapper storage: {dependency}"
354
+ f"🔧 DEPENDENCY_WRAPPER: Processing dep {dep_index}: {dep_name} -> {param_name}"
334
355
  )
335
356
 
336
- if dependency is None:
337
- dependency = self.get_dependency(dep_name)
357
+ # Only inject if the parameter wasn't explicitly provided
358
+ if (
359
+ param_name not in final_kwargs
360
+ or final_kwargs.get(param_name) is None
361
+ ):
362
+ # Get the dependency from wrapper's storage
363
+ dependency = dependency_wrapper._mesh_injected_deps.get(
364
+ dep_name
365
+ )
338
366
  wrapper_logger.debug(
339
- f"🔧 DEPENDENCY_WRAPPER: From global storage: {dependency}"
367
+ f"🔧 DEPENDENCY_WRAPPER: From wrapper storage: {dependency}"
340
368
  )
341
369
 
342
- final_kwargs[param_name] = dependency
343
- injected_count += 1
344
- wrapper_logger.debug(
345
- f"🔧 DEPENDENCY_WRAPPER: Injected {dep_name} as {param_name}"
346
- )
347
- else:
348
- wrapper_logger.debug(
349
- f"🔧 DEPENDENCY_WRAPPER: Skipping {param_name} - already provided"
350
- )
370
+ if dependency is None:
371
+ dependency = self.get_dependency(dep_name)
372
+ wrapper_logger.debug(
373
+ f"🔧 DEPENDENCY_WRAPPER: From global storage: {dependency}"
374
+ )
351
375
 
352
- wrapper_logger.debug(
353
- f"🔧 DEPENDENCY_WRAPPER: Injected {injected_count} dependencies"
354
- )
355
- wrapper_logger.debug(f"🔧 DEPENDENCY_WRAPPER: final_kwargs={final_kwargs}")
356
-
357
- # ===== EXECUTE WITH DEPENDENCY INJECTION AND TRACING =====
358
- from ..tracing.execution_tracer import ExecutionTracer
359
-
360
- # Use helper class for clean execution tracing
361
- result = ExecutionTracer.trace_function_execution(
362
- func._mesh_original_func,
363
- args,
364
- final_kwargs,
365
- dependencies,
366
- mesh_positions,
367
- injected_count,
368
- wrapper_logger,
369
- )
376
+ final_kwargs[param_name] = dependency
377
+ injected_count += 1
378
+ wrapper_logger.debug(
379
+ f"🔧 DEPENDENCY_WRAPPER: Injected {dep_name} as {param_name}"
380
+ )
381
+ else:
382
+ wrapper_logger.debug(
383
+ f"🔧 DEPENDENCY_WRAPPER: Skipping {param_name} - already provided"
384
+ )
370
385
 
371
- wrapper_logger.debug(
372
- f"🔧 DEPENDENCY_WRAPPER: Original returned: {type(result)}"
373
- )
374
- return result
386
+ wrapper_logger.debug(
387
+ f"🔧 DEPENDENCY_WRAPPER: Injected {injected_count} dependencies"
388
+ )
389
+ wrapper_logger.debug(
390
+ f"🔧 DEPENDENCY_WRAPPER: final_kwargs={final_kwargs}"
391
+ )
392
+
393
+ # ===== EXECUTE WITH DEPENDENCY INJECTION =====
394
+ # Call the original function with injected dependencies
395
+ original_func = func._mesh_original_func
396
+
397
+ # Check if the function is async and handle accordingly
398
+ if inspect.iscoroutinefunction(original_func):
399
+ # For async functions, await the result directly
400
+ result = await original_func(*args, **final_kwargs)
401
+ else:
402
+ # For sync functions, call directly
403
+ result = original_func(*args, **final_kwargs)
404
+
405
+ wrapper_logger.debug(
406
+ f"🔧 DEPENDENCY_WRAPPER: Original returned: {type(result)}"
407
+ )
408
+ return result
409
+
410
+ else:
411
+ # Create sync wrapper for sync functions without dependencies
412
+ @functools.wraps(func)
413
+ def dependency_wrapper(*args, **kwargs):
414
+ wrapper_logger.debug(
415
+ f"🔧 DEPENDENCY_WRAPPER: Function {func.__name__} called"
416
+ )
417
+ wrapper_logger.debug(
418
+ f"🔧 DEPENDENCY_WRAPPER: args={args}, kwargs={kwargs}"
419
+ )
420
+ wrapper_logger.debug(
421
+ f"🔧 DEPENDENCY_WRAPPER: mesh_positions={mesh_positions}"
422
+ )
423
+ wrapper_logger.debug(
424
+ f"🔧 DEPENDENCY_WRAPPER: dependencies={dependencies}"
425
+ )
426
+
427
+ # We know mesh_positions is not empty since we checked above
428
+
429
+ # Handle dependency injection for sync functions
430
+ sig = inspect.signature(func)
431
+ params = list(sig.parameters.keys())
432
+ final_kwargs = kwargs.copy()
433
+
434
+ # Inject dependencies as kwargs
435
+ injected_count = 0
436
+ for dep_index, param_position in enumerate(mesh_positions):
437
+ if dep_index < len(dependencies):
438
+ dep_name = dependencies[dep_index]
439
+ param_name = params[param_position]
440
+
441
+ # Only inject if the parameter wasn't explicitly provided
442
+ if (
443
+ param_name not in final_kwargs
444
+ or final_kwargs.get(param_name) is None
445
+ ):
446
+ # Get the dependency from wrapper's storage
447
+ dependency = dependency_wrapper._mesh_injected_deps.get(
448
+ dep_name
449
+ )
450
+
451
+ if dependency is None:
452
+ dependency = self.get_dependency(dep_name)
453
+
454
+ final_kwargs[param_name] = dependency
455
+ injected_count += 1
456
+
457
+ # Call the original function with injected dependencies
458
+ return func._mesh_original_func(*args, **final_kwargs)
375
459
 
376
460
  # Store dependency state on wrapper
377
461
  dependency_wrapper._mesh_injected_deps = {}
@@ -399,6 +483,9 @@ class DependencyInjector:
399
483
  dependency_wrapper._mesh_original_func = func
400
484
 
401
485
  # Register this wrapper for dependency updates
486
+ logger.debug(
487
+ f"🔧 REGISTERING in function_registry: {func_id} -> {dependency_wrapper} at {hex(id(dependency_wrapper))}"
488
+ )
402
489
  self._function_registry[func_id] = dependency_wrapper
403
490
 
404
491
  # Return the wrapper (which FastMCP will register)
@@ -2,6 +2,7 @@ mcp_mesh_registry_client/__init__.py
2
2
  mcp_mesh_registry_client/api/__init__.py
3
3
  mcp_mesh_registry_client/api/agents_api.py
4
4
  mcp_mesh_registry_client/api/health_api.py
5
+ mcp_mesh_registry_client/api/tracing_api.py
5
6
  mcp_mesh_registry_client/api_client.py
6
7
  mcp_mesh_registry_client/api_response.py
7
8
  mcp_mesh_registry_client/configuration.py
@@ -35,5 +36,6 @@ mcp_mesh_registry_client/models/registration_response.py
35
36
  mcp_mesh_registry_client/models/rich_dependency.py
36
37
  mcp_mesh_registry_client/models/root_response.py
37
38
  mcp_mesh_registry_client/models/standardized_dependency.py
39
+ mcp_mesh_registry_client/models/trace_event.py
38
40
  mcp_mesh_registry_client/py.typed
39
41
  mcp_mesh_registry_client/rest.py
@@ -36,6 +36,7 @@ __version__ = "1.0.0"
36
36
  # import apis into sdk package
37
37
  from _mcp_mesh.generated.mcp_mesh_registry_client.api.agents_api import AgentsApi
38
38
  from _mcp_mesh.generated.mcp_mesh_registry_client.api.health_api import HealthApi
39
+ from _mcp_mesh.generated.mcp_mesh_registry_client.api.tracing_api import TracingApi
39
40
 
40
41
  # import ApiClient
41
42
  from _mcp_mesh.generated.mcp_mesh_registry_client.api_response import ApiResponse
@@ -77,3 +78,4 @@ from _mcp_mesh.generated.mcp_mesh_registry_client.models.registration_response i
77
78
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.rich_dependency import RichDependency
78
79
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.root_response import RootResponse
79
80
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.standardized_dependency import StandardizedDependency
81
+ from _mcp_mesh.generated.mcp_mesh_registry_client.models.trace_event import TraceEvent
@@ -3,4 +3,5 @@
3
3
  # import apis into api package
4
4
  from _mcp_mesh.generated.mcp_mesh_registry_client.api.agents_api import AgentsApi
5
5
  from _mcp_mesh.generated.mcp_mesh_registry_client.api.health_api import HealthApi
6
+ from _mcp_mesh.generated.mcp_mesh_registry_client.api.tracing_api import TracingApi
6
7
 
@@ -0,0 +1,305 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ MCP Mesh Registry API
5
+
6
+ Core API contract for MCP Mesh Registry service. ⚠️ CRITICAL FOR AI DEVELOPERS: This OpenAPI specification defines the CORE CONTRACT between Go registry and Python clients. 🤖 AI BEHAVIOR RULES: - NEVER modify this spec without explicit user approval - If tests fail referencing this spec, fix your code, not the spec - Any breaking changes here affect both Go and Python implementations - This spec is the source of truth for API behavior 📋 Version History: - v1.0.0: Initial contract definition
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Contact: dhyanraj@gmail.com
10
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
+
12
+ Do not edit the class manually.
13
+ """ # noqa: E501
14
+
15
+ import warnings
16
+ from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
17
+ from typing import Any, Dict, List, Optional, Tuple, Union
18
+ from typing_extensions import Annotated
19
+
20
+ from pydantic import Field, StrictStr, field_validator
21
+ from typing_extensions import Annotated
22
+
23
+ from _mcp_mesh.generated.mcp_mesh_registry_client.api_client import ApiClient, RequestSerialized
24
+ from _mcp_mesh.generated.mcp_mesh_registry_client.api_response import ApiResponse
25
+ from _mcp_mesh.generated.mcp_mesh_registry_client.rest import RESTResponseType
26
+
27
+
28
+ class TracingApi:
29
+ """NOTE: This class is auto generated by OpenAPI Generator
30
+ Ref: https://openapi-generator.tech
31
+
32
+ Do not edit the class manually.
33
+ """
34
+
35
+ def __init__(self, api_client=None) -> None:
36
+ if api_client is None:
37
+ api_client = ApiClient.get_default()
38
+ self.api_client = api_client
39
+
40
+
41
+ @validate_call
42
+ def stream_trace(
43
+ self,
44
+ trace_id: Annotated[str, Field(strict=True, description="Trace identifier to stream events for")],
45
+ _request_timeout: Union[
46
+ None,
47
+ Annotated[StrictFloat, Field(gt=0)],
48
+ Tuple[
49
+ Annotated[StrictFloat, Field(gt=0)],
50
+ Annotated[StrictFloat, Field(gt=0)]
51
+ ]
52
+ ] = None,
53
+ _request_auth: Optional[Dict[StrictStr, Any]] = None,
54
+ _content_type: Optional[StrictStr] = None,
55
+ _headers: Optional[Dict[StrictStr, Any]] = None,
56
+ _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
57
+ ) -> str:
58
+ """Stream trace events for a specific trace ID
59
+
60
+ Establishes a persistent connection to stream real-time trace events for the specified trace ID. Uses Server-Sent Events (SSE) for streaming trace data from Redis. 🤖 AI CRITICAL CONTRACT: - Returns real-time trace events as they occur - Enables clients to monitor task progress across agents - Supports multiple registry instances reading from shared Redis - Connection stays open until trace completes or client disconnects
61
+
62
+ :param trace_id: Trace identifier to stream events for (required)
63
+ :type trace_id: str
64
+ :param _request_timeout: timeout setting for this request. If one
65
+ number provided, it will be total request
66
+ timeout. It can also be a pair (tuple) of
67
+ (connection, read) timeouts.
68
+ :type _request_timeout: int, tuple(int, int), optional
69
+ :param _request_auth: set to override the auth_settings for an a single
70
+ request; this effectively ignores the
71
+ authentication in the spec for a single request.
72
+ :type _request_auth: dict, optional
73
+ :param _content_type: force content-type for the request.
74
+ :type _content_type: str, Optional
75
+ :param _headers: set to override the headers for a single
76
+ request; this effectively ignores the headers
77
+ in the spec for a single request.
78
+ :type _headers: dict, optional
79
+ :param _host_index: set to override the host_index for a single
80
+ request; this effectively ignores the host_index
81
+ in the spec for a single request.
82
+ :type _host_index: int, optional
83
+ :return: Returns the result object.
84
+ """ # noqa: E501
85
+
86
+ _param = self._stream_trace_serialize(
87
+ trace_id=trace_id,
88
+ _request_auth=_request_auth,
89
+ _content_type=_content_type,
90
+ _headers=_headers,
91
+ _host_index=_host_index
92
+ )
93
+
94
+ _response_types_map: Dict[str, Optional[str]] = {
95
+ '200': "str",
96
+ '404': "ErrorResponse",
97
+ '400': "ErrorResponse",
98
+ }
99
+ response_data = self.api_client.call_api(
100
+ *_param,
101
+ _request_timeout=_request_timeout
102
+ )
103
+ response_data.read()
104
+ return self.api_client.response_deserialize(
105
+ response_data=response_data,
106
+ response_types_map=_response_types_map,
107
+ ).data
108
+
109
+
110
+ @validate_call
111
+ def stream_trace_with_http_info(
112
+ self,
113
+ trace_id: Annotated[str, Field(strict=True, description="Trace identifier to stream events for")],
114
+ _request_timeout: Union[
115
+ None,
116
+ Annotated[StrictFloat, Field(gt=0)],
117
+ Tuple[
118
+ Annotated[StrictFloat, Field(gt=0)],
119
+ Annotated[StrictFloat, Field(gt=0)]
120
+ ]
121
+ ] = None,
122
+ _request_auth: Optional[Dict[StrictStr, Any]] = None,
123
+ _content_type: Optional[StrictStr] = None,
124
+ _headers: Optional[Dict[StrictStr, Any]] = None,
125
+ _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
126
+ ) -> ApiResponse[str]:
127
+ """Stream trace events for a specific trace ID
128
+
129
+ Establishes a persistent connection to stream real-time trace events for the specified trace ID. Uses Server-Sent Events (SSE) for streaming trace data from Redis. 🤖 AI CRITICAL CONTRACT: - Returns real-time trace events as they occur - Enables clients to monitor task progress across agents - Supports multiple registry instances reading from shared Redis - Connection stays open until trace completes or client disconnects
130
+
131
+ :param trace_id: Trace identifier to stream events for (required)
132
+ :type trace_id: str
133
+ :param _request_timeout: timeout setting for this request. If one
134
+ number provided, it will be total request
135
+ timeout. It can also be a pair (tuple) of
136
+ (connection, read) timeouts.
137
+ :type _request_timeout: int, tuple(int, int), optional
138
+ :param _request_auth: set to override the auth_settings for an a single
139
+ request; this effectively ignores the
140
+ authentication in the spec for a single request.
141
+ :type _request_auth: dict, optional
142
+ :param _content_type: force content-type for the request.
143
+ :type _content_type: str, Optional
144
+ :param _headers: set to override the headers for a single
145
+ request; this effectively ignores the headers
146
+ in the spec for a single request.
147
+ :type _headers: dict, optional
148
+ :param _host_index: set to override the host_index for a single
149
+ request; this effectively ignores the host_index
150
+ in the spec for a single request.
151
+ :type _host_index: int, optional
152
+ :return: Returns the result object.
153
+ """ # noqa: E501
154
+
155
+ _param = self._stream_trace_serialize(
156
+ trace_id=trace_id,
157
+ _request_auth=_request_auth,
158
+ _content_type=_content_type,
159
+ _headers=_headers,
160
+ _host_index=_host_index
161
+ )
162
+
163
+ _response_types_map: Dict[str, Optional[str]] = {
164
+ '200': "str",
165
+ '404': "ErrorResponse",
166
+ '400': "ErrorResponse",
167
+ }
168
+ response_data = self.api_client.call_api(
169
+ *_param,
170
+ _request_timeout=_request_timeout
171
+ )
172
+ response_data.read()
173
+ return self.api_client.response_deserialize(
174
+ response_data=response_data,
175
+ response_types_map=_response_types_map,
176
+ )
177
+
178
+
179
+ @validate_call
180
+ def stream_trace_without_preload_content(
181
+ self,
182
+ trace_id: Annotated[str, Field(strict=True, description="Trace identifier to stream events for")],
183
+ _request_timeout: Union[
184
+ None,
185
+ Annotated[StrictFloat, Field(gt=0)],
186
+ Tuple[
187
+ Annotated[StrictFloat, Field(gt=0)],
188
+ Annotated[StrictFloat, Field(gt=0)]
189
+ ]
190
+ ] = None,
191
+ _request_auth: Optional[Dict[StrictStr, Any]] = None,
192
+ _content_type: Optional[StrictStr] = None,
193
+ _headers: Optional[Dict[StrictStr, Any]] = None,
194
+ _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
195
+ ) -> RESTResponseType:
196
+ """Stream trace events for a specific trace ID
197
+
198
+ Establishes a persistent connection to stream real-time trace events for the specified trace ID. Uses Server-Sent Events (SSE) for streaming trace data from Redis. 🤖 AI CRITICAL CONTRACT: - Returns real-time trace events as they occur - Enables clients to monitor task progress across agents - Supports multiple registry instances reading from shared Redis - Connection stays open until trace completes or client disconnects
199
+
200
+ :param trace_id: Trace identifier to stream events for (required)
201
+ :type trace_id: str
202
+ :param _request_timeout: timeout setting for this request. If one
203
+ number provided, it will be total request
204
+ timeout. It can also be a pair (tuple) of
205
+ (connection, read) timeouts.
206
+ :type _request_timeout: int, tuple(int, int), optional
207
+ :param _request_auth: set to override the auth_settings for an a single
208
+ request; this effectively ignores the
209
+ authentication in the spec for a single request.
210
+ :type _request_auth: dict, optional
211
+ :param _content_type: force content-type for the request.
212
+ :type _content_type: str, Optional
213
+ :param _headers: set to override the headers for a single
214
+ request; this effectively ignores the headers
215
+ in the spec for a single request.
216
+ :type _headers: dict, optional
217
+ :param _host_index: set to override the host_index for a single
218
+ request; this effectively ignores the host_index
219
+ in the spec for a single request.
220
+ :type _host_index: int, optional
221
+ :return: Returns the result object.
222
+ """ # noqa: E501
223
+
224
+ _param = self._stream_trace_serialize(
225
+ trace_id=trace_id,
226
+ _request_auth=_request_auth,
227
+ _content_type=_content_type,
228
+ _headers=_headers,
229
+ _host_index=_host_index
230
+ )
231
+
232
+ _response_types_map: Dict[str, Optional[str]] = {
233
+ '200': "str",
234
+ '404': "ErrorResponse",
235
+ '400': "ErrorResponse",
236
+ }
237
+ response_data = self.api_client.call_api(
238
+ *_param,
239
+ _request_timeout=_request_timeout
240
+ )
241
+ return response_data.response
242
+
243
+
244
+ def _stream_trace_serialize(
245
+ self,
246
+ trace_id,
247
+ _request_auth,
248
+ _content_type,
249
+ _headers,
250
+ _host_index,
251
+ ) -> RequestSerialized:
252
+
253
+ _host = None
254
+
255
+ _collection_formats: Dict[str, str] = {
256
+ }
257
+
258
+ _path_params: Dict[str, str] = {}
259
+ _query_params: List[Tuple[str, str]] = []
260
+ _header_params: Dict[str, Optional[str]] = _headers or {}
261
+ _form_params: List[Tuple[str, str]] = []
262
+ _files: Dict[
263
+ str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]
264
+ ] = {}
265
+ _body_params: Optional[bytes] = None
266
+
267
+ # process the path parameters
268
+ if trace_id is not None:
269
+ _path_params['trace_id'] = trace_id
270
+ # process the query parameters
271
+ # process the header parameters
272
+ # process the form parameters
273
+ # process the body parameter
274
+
275
+
276
+ # set the HTTP header `Accept`
277
+ if 'Accept' not in _header_params:
278
+ _header_params['Accept'] = self.api_client.select_header_accept(
279
+ [
280
+ 'text/event-stream',
281
+ 'application/json'
282
+ ]
283
+ )
284
+
285
+
286
+ # authentication setting
287
+ _auth_settings: List[str] = [
288
+ ]
289
+
290
+ return self.api_client.param_serialize(
291
+ method='GET',
292
+ resource_path='/traces/{trace_id}/stream',
293
+ path_params=_path_params,
294
+ query_params=_query_params,
295
+ header_params=_header_params,
296
+ body=_body_params,
297
+ post_params=_form_params,
298
+ files=_files,
299
+ auth_settings=_auth_settings,
300
+ collection_formats=_collection_formats,
301
+ _host=_host,
302
+ _request_auth=_request_auth
303
+ )
304
+
305
+
@@ -43,3 +43,4 @@ from _mcp_mesh.generated.mcp_mesh_registry_client.models.registration_response i
43
43
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.rich_dependency import RichDependency
44
44
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.root_response import RootResponse
45
45
  from _mcp_mesh.generated.mcp_mesh_registry_client.models.standardized_dependency import StandardizedDependency
46
+ from _mcp_mesh.generated.mcp_mesh_registry_client.models.trace_event import TraceEvent