mcp-mesh 0.7.11__py3-none-any.whl → 0.7.13__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 (41) hide show
  1. _mcp_mesh/__init__.py +1 -1
  2. _mcp_mesh/engine/__init__.py +1 -22
  3. _mcp_mesh/engine/async_mcp_client.py +88 -25
  4. _mcp_mesh/engine/decorator_registry.py +10 -9
  5. _mcp_mesh/engine/dependency_injector.py +64 -53
  6. _mcp_mesh/engine/mesh_llm_agent.py +119 -5
  7. _mcp_mesh/engine/mesh_llm_agent_injector.py +30 -0
  8. _mcp_mesh/engine/session_aware_client.py +3 -3
  9. _mcp_mesh/engine/unified_mcp_proxy.py +82 -90
  10. _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +0 -89
  11. _mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +3 -3
  12. _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +30 -28
  13. _mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py +16 -18
  14. _mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py +5 -5
  15. _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py +3 -3
  16. _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py +6 -6
  17. _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py +1 -1
  18. _mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py +15 -11
  19. _mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py +3 -3
  20. _mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py +37 -268
  21. _mcp_mesh/pipeline/mcp_startup/lifespan_factory.py +142 -0
  22. _mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py +57 -93
  23. _mcp_mesh/pipeline/shared/registry_connection.py +1 -1
  24. _mcp_mesh/shared/health_check_manager.py +313 -0
  25. _mcp_mesh/shared/logging_config.py +205 -14
  26. _mcp_mesh/shared/registry_client_wrapper.py +8 -8
  27. _mcp_mesh/shared/sse_parser.py +19 -17
  28. _mcp_mesh/tracing/execution_tracer.py +26 -1
  29. _mcp_mesh/tracing/fastapi_tracing_middleware.py +3 -4
  30. _mcp_mesh/tracing/trace_context_helper.py +25 -6
  31. {mcp_mesh-0.7.11.dist-info → mcp_mesh-0.7.13.dist-info}/METADATA +1 -1
  32. {mcp_mesh-0.7.11.dist-info → mcp_mesh-0.7.13.dist-info}/RECORD +38 -39
  33. mesh/__init__.py +3 -1
  34. mesh/decorators.py +81 -43
  35. mesh/helpers.py +72 -4
  36. mesh/types.py +48 -4
  37. _mcp_mesh/engine/full_mcp_proxy.py +0 -641
  38. _mcp_mesh/engine/mcp_client_proxy.py +0 -457
  39. _mcp_mesh/shared/health_check_cache.py +0 -246
  40. {mcp_mesh-0.7.11.dist-info → mcp_mesh-0.7.13.dist-info}/WHEEL +0 -0
  41. {mcp_mesh-0.7.11.dist-info → mcp_mesh-0.7.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,24 +1,22 @@
1
- _mcp_mesh/__init__.py,sha256=YyIzN6x9OBfdEWJq2A9-8O8byF-947bWhfJAdmVa1ZE,2720
2
- _mcp_mesh/engine/__init__.py,sha256=2ennzbo7yJcpkXO9BqN69TruLjJfmJY4Y5VEsG644K4,3630
3
- _mcp_mesh/engine/async_mcp_client.py,sha256=UcbQjxtgVfeRw6DHTZhAzN1gkcKlTg-lUPEePRPQWAU,6306
1
+ _mcp_mesh/__init__.py,sha256=Op8T4rx0MN_ILAC8sr_ueOBgfVL3Au6aENGgMLuLWAY,2720
2
+ _mcp_mesh/engine/__init__.py,sha256=U_6Kw3vA_3RiNK0Oln5c5C7WvA9lSONV22wWzfxYHNw,2975
3
+ _mcp_mesh/engine/async_mcp_client.py,sha256=Sz-rXTkb1Mng_f0SpLqLuOdPJ8vZjv3DFy0i8yYOqYk,8792
4
4
  _mcp_mesh/engine/base_injector.py,sha256=qzRLZqFP2VvEFagVovkpdldvDmm3VwPHm6tHwV58a2k,5648
5
- _mcp_mesh/engine/decorator_registry.py,sha256=zXuER3Sh-4NpqlLMtTxSxn93xBcZTDdEEjKWSCauU2U,28206
6
- _mcp_mesh/engine/dependency_injector.py,sha256=1bjeJ7pHUPEF_IoTF-7_Wm1pDLHphtfcFfSrUPWrWI4,31230
7
- _mcp_mesh/engine/full_mcp_proxy.py,sha256=PlRv7GSKqn5riOCqeCVulVdtq3z1Ug76mOkwMsOFHXw,25297
5
+ _mcp_mesh/engine/decorator_registry.py,sha256=cch2QdQ6bKjHKEGi1XWp1YcLLO3uI2YlxwWBO7Np65E,28229
6
+ _mcp_mesh/engine/dependency_injector.py,sha256=VLOmYAAvWSOs1wg5nUX8Psy4IL88a_gaMZpEHNZPDEc,31536
8
7
  _mcp_mesh/engine/http_wrapper.py,sha256=OHbbxHBLyUGDoamHZ2hpYnFKapW_djQ60Y_vMOL6J70,21173
9
8
  _mcp_mesh/engine/llm_config.py,sha256=95bOsGWro5E1JGq7oZtEYhVdrzcIJqjht_r5vEdJVz4,2049
10
9
  _mcp_mesh/engine/llm_errors.py,sha256=h7BiI14u-jL8vtvBfFbFDDrN7gIw8PQjXIl5AP1SBuA,3276
11
- _mcp_mesh/engine/mcp_client_proxy.py,sha256=eJStwy_VQJexYYD8bOh_m4Ld3Bb8Ae_dt8N1CC41qBc,17625
12
- _mcp_mesh/engine/mesh_llm_agent.py,sha256=AMW6Tu64aujFYwM0p0ZSd9YYaOikKZUN3utnqI0kT38,29015
13
- _mcp_mesh/engine/mesh_llm_agent_injector.py,sha256=isufzCBExli8tdLUZOaPuea3uQs3C_yeVXbOVSF0YIU,27270
10
+ _mcp_mesh/engine/mesh_llm_agent.py,sha256=ChfHL2qXLhvI6M3BYjVe2PDVzGB-8NbdDV_ZNgP6jFk,34205
11
+ _mcp_mesh/engine/mesh_llm_agent_injector.py,sha256=Ji_lmycB-xGVL-J3n50eQWemYB9kpsLd1tqOTNYUZ4Q,28343
14
12
  _mcp_mesh/engine/response_parser.py,sha256=NsOuGD7HJ0BFiiDUCp9v9cjLzVaU86HShVKzsrNnulk,8786
15
13
  _mcp_mesh/engine/self_dependency_proxy.py,sha256=OkKt0-B_ADnJlWtHiHItoZCBZ7Su0iz2unEPFfXvrs4,3302
16
- _mcp_mesh/engine/session_aware_client.py,sha256=mc9eh-aCvUvfllORiXTf_X8_jPqV-32QdWKlr8tHLkU,10600
14
+ _mcp_mesh/engine/session_aware_client.py,sha256=QejKag5zYNos5BVffQvNXFMECHFMLNOv78By4e_JzQE,10589
17
15
  _mcp_mesh/engine/session_manager.py,sha256=MCr0_fXBaUjXM51WU5EhDkiGvBdfzYQFVNb9DCXXL0A,10418
18
16
  _mcp_mesh/engine/signature_analyzer.py,sha256=ftn9XsX0ZHWIaACdjgBVtCuIdqVU_4ST8cvcpzu4HTk,12339
19
17
  _mcp_mesh/engine/tool_executor.py,sha256=Bf_9d02EEY9_yHm1p1-5YZ4rY6MPxn4SVpI6-3sm1uo,5456
20
18
  _mcp_mesh/engine/tool_schema_builder.py,sha256=SQCxQIrSfdLu9-dLqiFurQLK7dhl0dc0xa0ibaxU-iE,3644
21
- _mcp_mesh/engine/unified_mcp_proxy.py,sha256=FG3zwE5Li3Fdx8Rabzogpd4FsYIt13xjXcpU48Zth6c,37778
19
+ _mcp_mesh/engine/unified_mcp_proxy.py,sha256=dkhX0jgP_Rcg63WVM3h0KefEHSPh51dwmqgZyoKztGw,36521
22
20
  _mcp_mesh/engine/provider_handlers/__init__.py,sha256=LLTCOgnuM3dlogbLmrpiMK3oB5L22eAmDC4BfxJ-L2I,593
23
21
  _mcp_mesh/engine/provider_handlers/base_provider_handler.py,sha256=J-SPFFFG1eFSUVvfsv7y4EuNM4REjSxaYWC5E_lC6Pc,4195
24
22
  _mcp_mesh/engine/provider_handlers/claude_handler.py,sha256=CCmlsWiCfIcgrLbAZzeSnl0g2pq0uDffT8zOj4F-sPQ,15727
@@ -80,11 +78,11 @@ _mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py,s
80
78
  _mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py,sha256=zceJuFnY-q2B43avqEc1GwkW1UcBpOAgRl__zcb-WDc,4458
81
79
  _mcp_mesh/pipeline/__init__.py,sha256=9Aplh4m1z-rYTQys0JQLYlq9wTPdI72eSOhUPqcnvpA,1557
82
80
  _mcp_mesh/pipeline/api_heartbeat/__init__.py,sha256=IXTLoQLAPqQEWZ8VMWc5W_cQJkDv95rlVGXyXoQDjHk,473
83
- _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py,sha256=IvkvVQNyZr0Uqe2lViRpdj9kaLrxtTJ8io-gwjtK5FI,23247
84
- _mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py,sha256=PY4bbuZgxy3r0ccuBl-OuJvcPSMhyGz4FomxwYFhuvM,4821
81
+ _mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py,sha256=LDeLvN2U2MgYK3HLEUIhG5FUC2FyrGUs7SueF7gcfAA,20027
82
+ _mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py,sha256=vXiGTvBl5mwnVRwzFFNa7GvYWa7B-flCsHSX_ECv_JI,4822
85
83
  _mcp_mesh/pipeline/api_heartbeat/api_health_check.py,sha256=kDmFeOG_4tyqyJSBZjPcc7xTzGpP4vq6ObW_WBqXvzM,5130
86
84
  _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py,sha256=uBswzWOBzU8p_C0AE2DF8UwIWG4rP2zecHfPqKzNuC0,10367
87
- _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py,sha256=so8IyKT-Wg7lQk3ULdox9CAOrowzxpUs76e93PQnCik,13520
85
+ _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py,sha256=1bvQcO6lwZYTGILLAyWQuTOhyI5IY8mmhfSWAoJzMQU,13480
88
86
  _mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py,sha256=vszesutlAFXv9B4XXFutEMEBBhN54hF8eztTtDudLaI,15785
89
87
  _mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py,sha256=WBo2crcaGfxi8Q46TU-i5OMhAv0sQKz7Z9jps-GLkvM,5183
90
88
  _mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py,sha256=6N0JdXdnLkaXau4t8syt9DLgv9Y51SPfTXYK3DefBk8,3846
@@ -96,56 +94,57 @@ _mcp_mesh/pipeline/api_startup/middleware_integration.py,sha256=ybImXZlmIR6yA-wY
96
94
  _mcp_mesh/pipeline/api_startup/route_collection.py,sha256=UjA-F5_RbGVU5TfDT19Np5_x2PtYkNn2mGFyivDsk24,2031
97
95
  _mcp_mesh/pipeline/api_startup/route_integration.py,sha256=qq1AVaWna-CWEXyehyDL3EyeYKgo5aMtei8uBNdvkZ8,12448
98
96
  _mcp_mesh/pipeline/mcp_heartbeat/__init__.py,sha256=nRNjZ3VD_9bPLQuJ6Nc02gE7KSLcMP7TMquB0hP6hHs,844
99
- _mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py,sha256=vW-qrpneBLxxQtUEwEjE7aUTv5cIO9rjDg3Bxv7nj4I,18846
100
- _mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py,sha256=2SKHHFTxlYwad_D8a6E7NNtWfH89jBrIO5dQAwM3Xdw,4468
101
- _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py,sha256=DYX35H3edra_1qbnNzjmtnYit0oVLDIHidLoQUjeULU,12556
102
- _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py,sha256=BzoZK9PmE6vQEt8vs8_oiKBiTa9ba3IruBHebnvWaGI,11767
103
- _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py,sha256=ydVx-Vb_RgW1WPCboHVdZfEwNbgDngFV6Y9elZIBrAw,3602
97
+ _mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py,sha256=3f6B5uUUGKj1o5Q5kVR817YpEVI9V173xcVRHAV3k4Q,18784
98
+ _mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py,sha256=XgU3Y5XPThXaPaEfxGZVCmwAgzTG8p0tba95EnMwWeE,4468
99
+ _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py,sha256=yMl_oE_Bim0F0W39V9pvvTCN_81KoqwSa5rfjJ1mPxo,12560
100
+ _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py,sha256=I9kohm8lugJDEFT5kMLcLCt5DaRaK3q_wcvN-ed18Bw,11767
101
+ _mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py,sha256=_97o_T0odK-oTH-0qQ_r7gUiy-hxj1HSEhCI7djbE3c,3602
104
102
  _mcp_mesh/pipeline/mcp_heartbeat/lifespan_integration.py,sha256=4XPPlaJ6rz-FkDO3bxzVxHmVF-aq1CCaTW4vIBXrB0c,3016
105
- _mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py,sha256=zqecYzvTXKC3yvJOiSLWipBdp5U-jyPOUBQNWSN1gSE,10900
106
- _mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py,sha256=4abbOKN3echwX82PV0RvxF6cJZUu0pMgisOpILZ_ZzY,2875
103
+ _mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py,sha256=dKYpr8ZKBHthkKxZKYI0WR6e2yEWVRsvf6cDj6XUjUc,10963
104
+ _mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py,sha256=kL7k_yx2zafH3HO4sAxYCTxWdYWCoFsTOwCsRJVqUJk,2876
107
105
  _mcp_mesh/pipeline/mcp_startup/__init__.py,sha256=gS0xNmVx66bkLUMw64olMsN40ZLPH3ymwlLixZ4NuTs,1239
108
106
  _mcp_mesh/pipeline/mcp_startup/configuration.py,sha256=6LRLIxrqFMU76qrBb6GjGknUlKPZZ9iqOlxE7F9ZhLs,2808
109
107
  _mcp_mesh/pipeline/mcp_startup/decorator_collection.py,sha256=RHC6MHtfP9aP0hZ-IJjISZu72e0Pml3LU0qr7dc284w,2294
110
- _mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py,sha256=O3q3ZNZQsNZ0pL5SkkgQoOxfofzD202H0boshiT2FzI,44074
108
+ _mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py,sha256=si_HkHkpBbJDUIciDOA9-tppjnutGVg4K6Qcm6-gCKg,33888
111
109
  _mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py,sha256=Pm24wrSuRGsgeUrHvMPDnNh6RhIZoznnMAUwAkllohk,10661
112
110
  _mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py,sha256=v85B0ynomvYu87eIvLe-aSZ7-Iwov2VtM4Fg3PkmrZs,3865
113
111
  _mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py,sha256=sOpzxRc0kYiXwSW9lvv8DSjliT85oZCWPODeJRuiqgg,15635
112
+ _mcp_mesh/pipeline/mcp_startup/lifespan_factory.py,sha256=Hu7IvrhVH9sM7-XQDyWAGA3rgOnNIRyWFBtobkUQ5Es,4404
114
113
  _mcp_mesh/pipeline/mcp_startup/server_discovery.py,sha256=VuqqaBE00h6AerPjk-Ab-g51x6jODCbMX4nemLRQIIQ,8375
115
- _mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py,sha256=cz3VILoHmQ1wtTZUYMNkOfi88JfHPFuVBdHKCpZcBew,26758
114
+ _mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py,sha256=dT96P2f6Ci0H8sDe-6_Uro88Y0lZiyjPanN2bPsrTyk,25066
116
115
  _mcp_mesh/pipeline/mcp_startup/startup_pipeline.py,sha256=cAAbqioYRswf-P25OpZFX2yL_qN2sl_bVk-kcynFxPw,2347
117
116
  _mcp_mesh/pipeline/shared/__init__.py,sha256=s9xmdf6LkoetrVRGd7Zp3NUxcJCW6YZ_yNKzUBcnYys,352
118
117
  _mcp_mesh/pipeline/shared/base_step.py,sha256=kyPbNUX79NyGrE_0Q-e-Aek7m1J0TW036njWfv0iZ0I,1080
119
118
  _mcp_mesh/pipeline/shared/mesh_pipeline.py,sha256=UlQBrPWqbruFiUdVYgFKgPOpp_sMVsO97nZsWX90k9U,6498
120
119
  _mcp_mesh/pipeline/shared/pipeline_types.py,sha256=iKSgzCoYu3bpIwLViw6lE7T7irEzOm7gpie29lyy7SQ,1504
121
- _mcp_mesh/pipeline/shared/registry_connection.py,sha256=jmlgULixRM1NMNyMc-8SJN3RpCtV9hUf76vn9nciAN4,2904
120
+ _mcp_mesh/pipeline/shared/registry_connection.py,sha256=kB6gL1B7avmsPsOpEZVFh9143p0CAMeRIaLPBy86i-U,2905
122
121
  _mcp_mesh/shared/__init__.py,sha256=L0detgEWjnc_XfxA_5vIBcaGTuLcT6AARKkUpUBIaH4,1116
123
122
  _mcp_mesh/shared/config_resolver.py,sha256=r8WcO8lrd4XBHhH9IkAM7iy-QeCmTiVLmKhnJ47pFP0,7780
124
123
  _mcp_mesh/shared/content_extractor.py,sha256=culjhieFl_J6EMDv1VFKvS38O3IMhWMs8fHhNuR2rVk,3656
125
124
  _mcp_mesh/shared/defaults.py,sha256=5qazybkn7QHi418dXCS0b6QlNQl3DMg97ItzNGkc8d4,1851
126
125
  _mcp_mesh/shared/fast_heartbeat_status.py,sha256=OquEsX9ZTbxY1lIsll0Mbb2KDzSJD76sLMOlr3Z73Sc,5188
127
126
  _mcp_mesh/shared/fastapi_middleware_manager.py,sha256=_h10dSL9mgQstpJW_ZM2cpkU6yTKaYKlZaKXMk2i6IA,14638
128
- _mcp_mesh/shared/health_check_cache.py,sha256=bEdWMBwubK7W01gRCDcZo9NjVQELY4p42fIreeGahZ4,9399
127
+ _mcp_mesh/shared/health_check_manager.py,sha256=xZjQp-mWdPD64djp06nU5fN-fqi3Q_cIc1PAwMQTRBY,10362
129
128
  _mcp_mesh/shared/host_resolver.py,sha256=ycs6gXnI1zJX5KiqiLJPX5GkHX8r4j8NMHQOlG2J2X8,2964
130
- _mcp_mesh/shared/logging_config.py,sha256=lIljIVd2a_ekWj4isZnNDi4lzaEbPB-nyIapXPAz22c,2748
131
- _mcp_mesh/shared/registry_client_wrapper.py,sha256=8x40IzeigI0SFPz44OWgbXCkVrEDgV7N9a8wZ58Lh4Y,21181
129
+ _mcp_mesh/shared/logging_config.py,sha256=a0r6EmpuGhNHl3-t6fgw84qSiyGdW7cdiCGfiyEigSg,8872
130
+ _mcp_mesh/shared/registry_client_wrapper.py,sha256=WTHivh4Np740CvqN4d4wEYcimjPy1GCr1XXt-ZhEzO4,21181
132
131
  _mcp_mesh/shared/server_discovery.py,sha256=W5nsN-GvEVFD-7XkbMTxh-9FUIEiyWOxP3GYr8GNi3E,13142
133
132
  _mcp_mesh/shared/simple_shutdown.py,sha256=jnF1rTR2yR619LZnEjNlu-ZdKlB3PovxKqG0VZ3HDgE,8319
134
- _mcp_mesh/shared/sse_parser.py,sha256=OEPnfL9xL3rsjQrbyvfUO82WljPSDeO6Z61uUwN1NAo,8035
133
+ _mcp_mesh/shared/sse_parser.py,sha256=1NgnTMr4LQ-tW_cKJYj2oY0B5KDNskNeGlE23LcTOVk,8128
135
134
  _mcp_mesh/shared/support_types.py,sha256=k-ICF_UwDkHxQ1D5LwFZrp-UrNb4E5dzw02CRuLW9iI,7264
136
135
  _mcp_mesh/tracing/agent_context_helper.py,sha256=BIJ3Kc4Znd6emMAu97aUhSoxSIza3qYUmObLgc9ONiA,4765
137
136
  _mcp_mesh/tracing/context.py,sha256=2ozqKEYfx4Qxj64DnbwoVIbMkhNLbaV8BNWtkzAPA7I,2516
138
- _mcp_mesh/tracing/execution_tracer.py,sha256=H28EhZPb7Lyz2fG_toAbsQ7_zKANFxyBsIFlWBZg4FY,9167
139
- _mcp_mesh/tracing/fastapi_tracing_middleware.py,sha256=o-xyAb1hB_GIFXv0hqUeTwhDDEoFj3_brygmhSComkE,6848
137
+ _mcp_mesh/tracing/execution_tracer.py,sha256=nm1bXlomc8B_YYERO-LntwEDAcxJP3vbW8qpbVaXShg,10267
138
+ _mcp_mesh/tracing/fastapi_tracing_middleware.py,sha256=FXjhA1A1Krk-ngyuOZPc1Ic4Llggv4Wide9OuPmkwCY,6959
140
139
  _mcp_mesh/tracing/redis_metadata_publisher.py,sha256=F78E34qnI3D0tOmbHUTBsLbDst2G7Su2-0F37Rq0rcM,4652
141
- _mcp_mesh/tracing/trace_context_helper.py,sha256=6tEkwjWFqMBe45zBlhacktmIpzJWTF950ph3bwL3cNc,5994
140
+ _mcp_mesh/tracing/trace_context_helper.py,sha256=3XWVU_cnsqrfjgAGRJaRK0Uvkns363scr4hVCGMzBgo,6858
142
141
  _mcp_mesh/tracing/utils.py,sha256=t9lJuTH7CeuzAiiAaD0WxsJMFJPdzZFR0w6-vyR9f2E,3849
143
142
  _mcp_mesh/utils/fastmcp_schema_extractor.py,sha256=M54ffesC-56zl_fNJHj9dZxElDQaWFf1MXdSLCuFStg,17253
144
- mesh/__init__.py,sha256=0zequaBtd_9NLOLsr9sNONuwWa_fT_-G4LnJ1CHTEY0,3808
145
- mesh/decorators.py,sha256=_3yVrEvGHZ5MKX_pf7Zn-vLdOH68iE7o6EIvxKcGOds,57636
146
- mesh/helpers.py,sha256=2Iquvco5mDl0Qs_FD4rMiI88Q-sjXEkKitsXw2HS4Jc,9878
147
- mesh/types.py,sha256=9TqbJSxlybLQaPVjugcKwPiIrVnJEzqAOvPRhlX1zmo,15559
148
- mcp_mesh-0.7.11.dist-info/METADATA,sha256=gWVztMobWhc0salCmhAZ2STRs6SPBYGtErNDe_RMyLc,4973
149
- mcp_mesh-0.7.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
150
- mcp_mesh-0.7.11.dist-info/licenses/LICENSE,sha256=_EBQHRQThv9FPOLc5eFOUdeeRO0mYwChC7cx60dM1tM,1078
151
- mcp_mesh-0.7.11.dist-info/RECORD,,
143
+ mesh/__init__.py,sha256=Va5XRBWgejQurad7Maz3E-zPY7vu431B2_4sAdCu1zk,3868
144
+ mesh/decorators.py,sha256=v0l_0oAS_UZBQLC1WwhJQTil9AvGMCFL9kYS-N7febk,59627
145
+ mesh/helpers.py,sha256=ITua2zdxbXeBLF5qS46A6A1P2GQNbfL_2_BMCKazQ4U,12575
146
+ mesh/types.py,sha256=n0MxrBYZJ84xyQWGf_X2ZbVWSAaIcEBkRV7qaCmX6Ac,17008
147
+ mcp_mesh-0.7.13.dist-info/METADATA,sha256=-8HA6G4aePVlFZYau62AdSjXd2tNjGZW0dEdD6-k36A,4973
148
+ mcp_mesh-0.7.13.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
149
+ mcp_mesh-0.7.13.dist-info/licenses/LICENSE,sha256=_EBQHRQThv9FPOLc5eFOUdeeRO0mYwChC7cx60dM1tM,1078
150
+ mcp_mesh-0.7.13.dist-info/RECORD,,
mesh/__init__.py CHANGED
@@ -19,7 +19,7 @@ Use 'import mesh' and then '@mesh.tool()' for consistency with MCP patterns.
19
19
  """
20
20
 
21
21
  from . import decorators
22
- from .types import McpMeshAgent, MeshContextModel, MeshLlmAgent, MeshLlmRequest
22
+ from .types import LlmMeta, McpMeshAgent, MeshContextModel, MeshLlmAgent, MeshLlmRequest
23
23
 
24
24
  # Note: helpers.llm_provider is imported lazily in __getattr__ to avoid
25
25
  # initialization timing issues with @mesh.agent auto_run in tests
@@ -113,6 +113,8 @@ def __getattr__(name):
113
113
  return MeshLlmAgent
114
114
  elif name == "MeshLlmRequest":
115
115
  return MeshLlmRequest
116
+ elif name == "LlmMeta":
117
+ return LlmMeta
116
118
  elif name == "create_server":
117
119
  return create_server
118
120
  raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
mesh/decorators.py CHANGED
@@ -85,30 +85,88 @@ def _start_uvicorn_immediately(http_host: str, http_port: int):
85
85
  "MCP_MESH_DISTRIBUTED_TRACING_ENABLED", "false"
86
86
  ).lower() in ("true", "1", "yes")
87
87
  if tracing_enabled:
88
- from starlette.middleware.base import BaseHTTPMiddleware
89
- from starlette.requests import Request
88
+ # Use pure ASGI middleware for proper SSE header injection (Issue #310)
89
+ class TraceContextMiddleware:
90
+ """Pure ASGI middleware for trace context and header injection.
90
91
 
91
- class TraceContextMiddleware(BaseHTTPMiddleware):
92
- """Middleware to extract trace headers and set up trace context."""
92
+ This middleware:
93
+ 1. Extracts trace context from incoming request headers
94
+ 2. Sets up trace context for the request lifecycle
95
+ 3. Injects trace headers into the response (works with SSE)
96
+ """
97
+
98
+ def __init__(self, app):
99
+ self.app = app
100
+
101
+ async def __call__(self, scope, receive, send):
102
+ if scope["type"] != "http":
103
+ await self.app(scope, receive, send)
104
+ return
105
+
106
+ path = scope.get("path", "")
107
+ logger.debug(f"[TRACE] Processing request {path}")
108
+
109
+ # Extract and set trace context from request headers
110
+ trace_id = None
111
+ span_id = None
112
+ parent_span = None
93
113
 
94
- async def dispatch(self, request: Request, call_next):
95
114
  try:
115
+ from _mcp_mesh.tracing.context import TraceContext
96
116
  from _mcp_mesh.tracing.trace_context_helper import (
97
117
  TraceContextHelper,
118
+ get_header_case_insensitive,
98
119
  )
99
120
 
100
- # Extract and set trace context from headers for distributed tracing
101
- trace_context = await TraceContextHelper.extract_trace_context_from_request(
102
- request
121
+ # Extract trace headers from request (case-insensitive)
122
+ headers_list = scope.get("headers", [])
123
+ incoming_trace_id = get_header_case_insensitive(
124
+ headers_list, "x-trace-id"
103
125
  )
126
+ incoming_parent_span = get_header_case_insensitive(
127
+ headers_list, "x-parent-span"
128
+ )
129
+
130
+ # Setup trace context
131
+ trace_context = {
132
+ "trace_id": (
133
+ incoming_trace_id if incoming_trace_id else None
134
+ ),
135
+ "parent_span": (
136
+ incoming_parent_span
137
+ if incoming_parent_span
138
+ else None
139
+ ),
140
+ }
104
141
  TraceContextHelper.setup_request_trace_context(
105
142
  trace_context, logger
106
143
  )
144
+
145
+ # Get trace IDs to inject into response
146
+ current_trace = TraceContext.get_current()
147
+ if current_trace:
148
+ trace_id = current_trace.trace_id
149
+ span_id = current_trace.span_id
150
+ parent_span = current_trace.parent_span
107
151
  except Exception as e:
108
- # Never fail request due to tracing issues
109
152
  logger.warning(f"Failed to set trace context: {e}")
110
153
 
111
- return await call_next(request)
154
+ # Wrap send to inject headers before response starts
155
+ async def send_with_trace_headers(message):
156
+ if message["type"] == "http.response.start" and trace_id:
157
+ # Add trace headers to the response
158
+ headers = list(message.get("headers", []))
159
+ headers.append((b"x-trace-id", trace_id.encode()))
160
+ if span_id:
161
+ headers.append((b"x-span-id", span_id.encode()))
162
+ if parent_span:
163
+ headers.append(
164
+ (b"x-parent-span-id", parent_span.encode())
165
+ )
166
+ message = {**message, "headers": headers}
167
+ await send(message)
168
+
169
+ await self.app(scope, receive, send_with_trace_headers)
112
170
 
113
171
  app.add_middleware(TraceContextMiddleware)
114
172
  logger.debug(
@@ -119,54 +177,34 @@ def _start_uvicorn_immediately(http_host: str, http_port: int):
119
177
  f"⚠️ IMMEDIATE UVICORN: Failed to add trace context middleware: {e}"
120
178
  )
121
179
 
122
- # Add health endpoint that can be updated by pipeline
123
- # Store health check result in a shared location that can be updated
124
- health_result = {"status": "starting", "message": "Agent is starting"}
180
+ # Add K8s health endpoints using health_check_manager
181
+ from _mcp_mesh.shared.health_check_manager import (
182
+ build_health_response,
183
+ build_livez_response,
184
+ build_ready_response,
185
+ )
125
186
 
126
187
  @app.get("/health")
127
188
  @app.head("/health")
128
189
  async def health(response: Response):
129
190
  """Health check endpoint that supports custom health checks."""
130
- # Check if a custom health check has been configured
131
- # The pipeline will update this via DecoratorRegistry
132
- custom_health = DecoratorRegistry.get_health_check_result()
133
- health_data = custom_health if custom_health else health_result
134
-
135
- # Set HTTP status code based on health status
136
- # K8s expects non-200 status for unhealthy services
137
- status = health_data.get("status", "starting")
138
- if status == "healthy":
139
- response.status_code = 200
140
- else:
141
- # Return 503 for unhealthy, degraded, starting, or unknown
142
- response.status_code = 503
143
-
144
- return health_data
191
+ data, status_code = build_health_response(agent_name="mcp-mesh-agent")
192
+ response.status_code = status_code
193
+ return data
145
194
 
146
195
  @app.get("/ready")
147
196
  @app.head("/ready")
148
197
  async def ready(response: Response):
149
198
  """Kubernetes readiness probe - service ready to serve traffic."""
150
- custom_health = DecoratorRegistry.get_health_check_result()
151
- health_data = custom_health if custom_health else health_result
152
-
153
- status = health_data.get("status", "starting")
154
- if status == "healthy":
155
- response.status_code = 200
156
- return {"ready": True, "status": status}
157
- else:
158
- response.status_code = 503
159
- return {
160
- "ready": False,
161
- "status": status,
162
- "reason": f"Service is {status}",
163
- }
199
+ data, status_code = build_ready_response(agent_name="mcp-mesh-agent")
200
+ response.status_code = status_code
201
+ return data
164
202
 
165
203
  @app.get("/livez")
166
204
  @app.head("/livez")
167
205
  async def livez():
168
206
  """Kubernetes liveness probe - always returns 200 if app is running."""
169
- return {"alive": True, "message": "Application is running"}
207
+ return build_livez_response(agent_name="mcp-mesh-agent")
170
208
 
171
209
  @app.get("/immediate-status")
172
210
  def immediate_status():
mesh/helpers.py CHANGED
@@ -11,6 +11,34 @@ from typing import Any, Dict, List, Optional
11
11
  logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
+ def _extract_vendor_from_model(model: str) -> str | None:
15
+ """
16
+ Extract vendor name from LiteLLM model string.
17
+
18
+ LiteLLM uses vendor/model format (e.g., "anthropic/claude-sonnet-4-5").
19
+ This extracts the vendor for provider handler selection.
20
+
21
+ Args:
22
+ model: LiteLLM model string
23
+
24
+ Returns:
25
+ Vendor name (e.g., "anthropic", "openai") or None if not extractable
26
+
27
+ Examples:
28
+ "anthropic/claude-sonnet-4-5" -> "anthropic"
29
+ "openai/gpt-4o" -> "openai"
30
+ "gpt-4" -> None (no vendor prefix)
31
+ """
32
+ if not model:
33
+ return None
34
+
35
+ if "/" in model:
36
+ vendor = model.split("/")[0].lower().strip()
37
+ return vendor
38
+
39
+ return None
40
+
41
+
14
42
  def llm_provider(
15
43
  model: str,
16
44
  capability: str = "llm",
@@ -154,9 +182,39 @@ def llm_provider(
154
182
  """
155
183
  import litellm
156
184
 
185
+ # Determine effective model (check for consumer override - issue #308)
186
+ effective_model = model # Default to provider's model
187
+ model_params_copy = (
188
+ dict(request.model_params) if request.model_params else {}
189
+ )
190
+
191
+ if "model" in model_params_copy:
192
+ override_model = model_params_copy.pop(
193
+ "model"
194
+ ) # Remove to avoid duplication
195
+
196
+ if override_model:
197
+ # Validate vendor compatibility
198
+ override_vendor = _extract_vendor_from_model(override_model)
199
+
200
+ if override_vendor and override_vendor != vendor:
201
+ # Vendor mismatch - log warning and fall back to provider's model
202
+ logger.warning(
203
+ f"⚠️ Model override '{override_model}' ignored - vendor mismatch "
204
+ f"(override vendor: '{override_vendor}', provider vendor: '{vendor}'). "
205
+ f"Using provider's default model: '{model}'"
206
+ )
207
+ else:
208
+ # Vendor matches or can't be determined - use override
209
+ effective_model = override_model
210
+ logger.info(
211
+ f"🔄 Using model override '{effective_model}' "
212
+ f"(requested by consumer)"
213
+ )
214
+
157
215
  # Build litellm.completion arguments
158
216
  completion_args: dict[str, Any] = {
159
- "model": model,
217
+ "model": effective_model,
160
218
  "messages": request.messages,
161
219
  **litellm_kwargs,
162
220
  }
@@ -165,8 +223,8 @@ def llm_provider(
165
223
  if request.tools:
166
224
  completion_args["tools"] = request.tools
167
225
 
168
- if request.model_params:
169
- completion_args.update(request.model_params)
226
+ if model_params_copy:
227
+ completion_args.update(model_params_copy)
170
228
 
171
229
  # Call LiteLLM
172
230
  try:
@@ -219,9 +277,19 @@ def llm_provider(
219
277
  for tc in message.tool_calls
220
278
  ]
221
279
 
280
+ # Issue #311: Include usage metadata for cost tracking
281
+ if hasattr(response, "usage") and response.usage:
282
+ usage = response.usage
283
+ message_dict["_mesh_usage"] = {
284
+ "prompt_tokens": getattr(usage, "prompt_tokens", 0) or 0,
285
+ "completion_tokens": getattr(usage, "completion_tokens", 0)
286
+ or 0,
287
+ "model": effective_model,
288
+ }
289
+
222
290
  logger.info(
223
291
  f"LLM provider {func.__name__} processed request "
224
- f"(model={model}, messages={len(request.messages)}, "
292
+ f"(model={effective_model}, messages={len(request.messages)}, "
225
293
  f"tool_calls={len(message_dict.get('tool_calls', []))})"
226
294
  )
227
295
 
mesh/types.py CHANGED
@@ -386,6 +386,50 @@ except ImportError:
386
386
  pass
387
387
 
388
388
 
389
+ @dataclass
390
+ class LlmMeta:
391
+ """
392
+ Metadata from LLM response for cost tracking and debugging.
393
+
394
+ This is attached to results from @mesh.llm calls as `_mesh_meta` attribute,
395
+ providing access to token counts, latency, and model information.
396
+
397
+ Attributes:
398
+ provider: LLM provider name (e.g., "anthropic", "openai")
399
+ model: Full model identifier (e.g., "anthropic/claude-3-5-haiku-20241022")
400
+ input_tokens: Number of tokens in the prompt
401
+ output_tokens: Number of tokens in the response
402
+ total_tokens: Total tokens used (input + output)
403
+ latency_ms: Request latency in milliseconds
404
+
405
+ Usage:
406
+ @mesh.llm(provider="anthropic/claude-3-5-haiku-20241022")
407
+ async def ask(question: str, llm: MeshLlmAgent) -> Answer:
408
+ result = await llm(question)
409
+
410
+ # Access result normally
411
+ print(result.answer)
412
+
413
+ # Access metadata
414
+ print(result._mesh_meta.model) # "anthropic/claude-3-5-haiku-20241022"
415
+ print(result._mesh_meta.output_tokens) # 85
416
+ print(result._mesh_meta.latency_ms) # 125.5
417
+
418
+ return result
419
+
420
+ Note:
421
+ For primitive return types (str, int, etc.) and frozen Pydantic models,
422
+ _mesh_meta cannot be attached. This is a Python limitation.
423
+ """
424
+
425
+ provider: str
426
+ model: str
427
+ input_tokens: int
428
+ output_tokens: int
429
+ total_tokens: int
430
+ latency_ms: float
431
+
432
+
389
433
  @dataclass
390
434
  class MeshLlmRequest:
391
435
  """
@@ -414,9 +458,9 @@ class MeshLlmRequest:
414
458
  caller_agent: Optional agent name that initiated the request
415
459
  """
416
460
 
417
- messages: List[Dict[str, Any]] # Changed from Dict[str, str] to allow tool_calls
418
- tools: Optional[List[Dict]] = None
419
- model_params: Optional[Dict] = None
420
- context: Optional[Dict] = None
461
+ messages: list[dict[str, Any]] # Changed from Dict[str, str] to allow tool_calls
462
+ tools: Optional[list[dict]] = None
463
+ model_params: Optional[dict] = None
464
+ context: Optional[dict] = None
421
465
  request_id: Optional[str] = None
422
466
  caller_agent: Optional[str] = None