|
7 | 7 |
|
8 | 8 | import httpx |
9 | 9 | import requests |
| 10 | +import uvicorn |
10 | 11 | from fastmcp import FastMCP |
11 | 12 | from requests.adapters import HTTPAdapter |
| 13 | +from starlette.middleware import Middleware |
| 14 | +from starlette.middleware.base import BaseHTTPMiddleware |
12 | 15 | from urllib3.util.retry import Retry |
13 | 16 | from fastmcp.server.dependencies import get_http_headers |
14 | 17 |
|
@@ -157,15 +160,31 @@ async def get_weather(city: str) -> str: |
157 | 160 |
|
158 | 161 |
|
159 | 162 |
|
| 163 | +async def _trace_propagation_middleware(request, call_next): |
| 164 | + """Extract W3C traceparent from HTTP headers before FastMCP creates its span. |
| 165 | +
|
| 166 | + FastMCP creates its own root span per request. Without this middleware, |
| 167 | + that span has no parent, producing a disconnected trace in Phoenix/Jaeger. |
| 168 | + Attaching the incoming context here makes FastMCP's span a child of the |
| 169 | + caller's span automatically, since OTEL picks up the ambient context. |
| 170 | + """ |
| 171 | + incoming_ctx = extract(dict(request.headers)) |
| 172 | + token = otel_context.attach(incoming_ctx) |
| 173 | + try: |
| 174 | + return await call_next(request) |
| 175 | + finally: |
| 176 | + otel_context.detach(token) |
| 177 | + |
| 178 | + |
160 | 179 | # host can be specified with HOST env variable |
161 | 180 | # transport can be specified with MCP_TRANSPORT env variable (defaults to streamable-http) |
162 | 181 | def run_server(): |
163 | 182 | "Run the MCP server" |
164 | 183 | setup_tracing() |
165 | | - transport = os.getenv("MCP_TRANSPORT", "streamable-http") |
166 | 184 | host = os.getenv("HOST", "0.0.0.0") |
167 | 185 | port = int(os.getenv("PORT", "8000")) |
168 | | - mcp.run(transport=transport, host=host, port=port) |
| 186 | + app = mcp.http_app(middleware=[Middleware(BaseHTTPMiddleware, dispatch=_trace_propagation_middleware)]) |
| 187 | + uvicorn.run(app, host=host, port=port) |
169 | 188 |
|
170 | 189 |
|
171 | 190 | if __name__ == "__main__": |
|
0 commit comments