You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: use token-based instrumentation API for OpenTelemetry support
This change addresses feedback on the instrumentation interface design. The updated API now uses a token-based approach where on_request_start() returns a token that is passed to on_request_end() and on_error(). This enables instrumenters to maintain state (like OpenTelemetry spans) without external storage or side-channels.
Changes:
- Updated Instrumenter protocol to return token from on_request_start()
- Modified on_request_end() and on_error() to accept token as first parameter
- Updated server.py to capture and pass instrumentation tokens
- Updated all tests to match new API
- Added complete OpenTelemetry example implementation
- Updated documentation with token-based examples
Fixes#421
The MCP Python SDK provides a pluggable instrumentation interface for monitoring request/response lifecycle. This enables integration with OpenTelemetry, custom metrics, logging frameworks, and other observability tools.
4
4
5
+
**Related issue**: [#421 - Adding OpenTelemetry to MCP SDK](https://github.com/modelcontextprotocol/python-sdk/issues/421)
6
+
5
7
## Overview
6
8
7
9
The `Instrumenter` protocol defines three hooks:
8
10
9
-
-`on_request_start`: Called when a request starts processing
10
-
-`on_request_end`: Called when a request completes (successfully or not)
11
-
-`on_error`: Called when an error occurs during request processing
11
+
-`on_request_start`: Called when a request starts processing, **returns a token**
12
+
-`on_request_end`: Called when a request completes, **receives the token**
13
+
-`on_error`: Called when an error occurs, **receives the token**
14
+
15
+
The token-based design allows instrumenters to maintain state (like OpenTelemetry spans) between `on_request_start` and `on_request_end` without needing external storage or side-channels.
12
16
13
17
All methods are optional (no-op implementations are valid). Exceptions raised by instrumentation hooks are logged but do not affect request processing.
14
18
@@ -17,6 +21,7 @@ All methods are optional (no-op implementations are valid). Exceptions raised by
17
21
### Server-Side Instrumentation
18
22
19
23
```python
24
+
from typing import Any
20
25
from mcp.server.lowlevel import Server
21
26
from mcp.shared.instrumentation import Instrumenter
22
27
from mcp.types import RequestId
@@ -30,27 +35,35 @@ class MyInstrumenter:
30
35
request_type: str,
31
36
method: str|None=None,
32
37
**metadata,
33
-
) -> None:
38
+
) -> Any:
39
+
"""Return a token (any value) to track this request."""
Note: For this simple metrics case, the token isn't strictly necessary, so we just return the `request_type`. For more complex instrumenters (like OpenTelemetry), the token is essential for maintaining state.
367
+
202
368
## Future Work
203
369
204
-
- Full OpenTelemetry integration as a separate module
- Support for distributed tracing via `params._meta.traceparent` propagation (see [modelcontextprotocol/spec#414](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/414))
373
+
- Semantic conventions for MCP traces and metrics (see [open-telemetry/semantic-conventions#2083](https://github.com/open-telemetry/semantic-conventions/pull/2083))
206
374
- Client-side request instrumentation
207
375
- Async hook support for long-running instrumentation operations
0 commit comments