-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Document request.params._meta convention #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document request.params._meta convention #414
Conversation
|
I would love the text in the spec to include more of what you have written in the PR description, and that the recommendation is to use It could be labelled as "Optional: OpenTelemetry context". I hope that SDKs decide to implement it where they have existing OTel ecosystems that they can leverage. MCP clients are not required to send it, and MCP servers that do not support OTel can safely ignore those parameters. This may be too much for the index file, but they could be added to the typescript and documentation. |
|
@samsp-msft, thanks for your thoughtful feedback! I’ve updated the "Basic" section to keep it neutral and avoid implying MCP defines OpenTelemetry (OTel) specifics: Updated Rationale:This keeps Specifically, we want to make room in otel for what's likely an inevitable OTEP for MCP. I say inevitable because the other discussion includes transport details (e.g. OTLP which is not propagation). This feels a lot like past discussions that led to specification clarifications including env variable propagation and how to handle messaging. In fact, there's already work in Otel for semantic conventions (thanks for participating in that). Ideally an engineer will be able to see the otel details coherently in one place (e.g. an OTEP). Long story short, deferring OTel keeps MCP focused on protocol mechanics, not telemetry details. By adding an example, we hint of how to hand-over to otel for clarity on telemetry. Does this address your concern? |
6c55543 to
2081ae2
Compare
|
I took time to update the description with feedback in the comments and also relating to discussions by @ZengyiZhao here and @wdawson here. Hope we can land this soon! |
|
@dsp-ant @jspahrsummers So, for anecdotal context. What drove me to the discussion leading to this and the PR itself was your podcast on latent space with @FanaHOVA and @swyxio Was a knock-out episode, and since working in oss since 2008 this made me feel the best:
So, my goal with this change was to make the absolutely least change possible, with the highest rigor. Even if it is a no, all good. Thanks for inspiring me to give it a go. I love the do the work, then let's talk approach to change. |
LGTM There is a balance between what needs to go into the base specification - providing the place to pass context - and having agreement amongst the SDK as to how they will use the extensibility mechanisms to implement telemetry propagation. The details of which key values pairs should be used and their values can probably be delegated to docs in the OTel space. It can probably go in the docs for the semantic conventions. I am hoping that we can get common agreement amongst most MCP SDKs about how to incorporate telemetry so that they can interoperate nicely, and it doesn't need major retrofits later. |
|
@samsp-msft thanks for the support. PS I raised a PR to csharp-sdk to change the carrier from |
This documents the convention of using the request parameter key `_meta` to hold metadata for use in trace identifiers or correlation IDs. For example, if using [w3c trace-context propagation](https://www.w3.org/TR/trace-context/#relationship-between-the-headers) (commonly used by opentelemetry), the client would encode its trace IDs like this ``` request.params._meta[traceparent]="00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" ``` This does not constrain metadata values to stringly typed to allow portability with ACP which hast some structured metadata. A common request may be: why define this? Rationale of the question centered on that the MCP specification already permits extra fields. The main answer is consistency so that other specifications can reliably build on it, and reduce confusion in potential alternate key names. Fixes modelcontextprotocol#246
Signed-off-by: Adrian Cole <adrian.cole@elastic.co>
757a83e to
8a5e71f
Compare
|
Earlier I mis-attributed I've revised the spec change to link to the progress spec, and also shored up the description accordingly. |
|
@dsp-ant do you have any advice for us on how to progress this PR? I'm happy to revise it, but it seems stalled. |
|
Right now, by naming convention ( Specifically, this PR describes some use cases:
Whereas in the schema today, there are 13 occurrences of this advice on
The recent work by @findleyr and friends on the Go SDK design implies code generation, and there's a small gap you can see if you look carefully here.
There are a number of ways to address code generation coherency.. we could make a single "meta" type and use that for Finally, we can decide to not solve it strictly in the schema. Rather, stick with advice here and mention to code generator authors that there's a relationship with anything ending in Request, Response etc that should have special casing. I don't have a preferred way out, but I would like to help close out this topic. Any thoughts? |
|
added a section to the description that it is possible a future JSON-RPC 2.1 could formalize "_meta". That said, I don't expect this to change any current practice. cc @mpcm |
|
@codefromthecrypt See recently posted: https://groups.google.com/g/json-rpc/c/pFFuI0JN8Cs |
|
In the JSON-RPC group discussion, I mentioned that responses could benefit from a The protocol currently uses |
|
@jonathanhefner Thanks for the suggestion - personally, if the compatibility issue is acceptable I would suggest top level |
|
We have a similar need. I too would prefer something outside of the params, although it's a good way to experiment for the time being. |
|
going to close this out as it hasn't moved forward in a month. happy to re-open when maintainers are interested in a change. Meanwhile, per the description, there are enough artifacts here and there to suggest |
|
FWIW, i was able to abuse the protocol's sending: https://github.com/dylibso/mcp-otel/blob/2407c736c92d6a5e71b454845d839f33dabbbfca/src/agent.ts#L122 I think this should be safe if you do your best to avoid name collisions, but going to ask around. Doing the actual context propagation and naming of everything works, but is a little tedious if you're not familiar with it. This could perhaps be part of an otel adapter for the SDKs, or one day adopted with the SDKs if some things can be agreed upon. |
|
@bhelx thx for the feedback. I will add to the description your use of this pattern which aligns with others mentioned there including Arize Openinference which is an otel SDK. That way folks don't have to scroll through comments should there be a desire to formalize this later. |
…ropagation Replace HTTP header-based trace propagation with MCP _meta field convention. This makes the solution transport-agnostic and follows the emerging MCP standard for metadata propagation. Changes: - Update otel_utils.py with _meta field extraction/injection functions - Replace with_otel_context_from_headers with with_otel_context_from_meta - Add _meta parameter to server tools (get_weather, get_forecast) - Update client to inject context into _meta field instead of headers - Add inject_otel_context_to_meta() and extract_otel_context_from_meta() - Update README with comprehensive documentation on _meta approach - Add CHANGELOG.md documenting migration path and breaking changes Benefits: - Transport agnostic: works with stdio, HTTP, and SSE transports - Follows emerging MCP standard (PR #414) - Compatible with openinference-instrumentation-mcp - Maintains W3C Trace Context compatibility BREAKING CHANGE: Server tools now require _meta parameter, and clients must use inject_otel_context_to_meta() instead of HTTP header injection. See CHANGELOG.md for migration guide. References: - modelcontextprotocol/modelcontextprotocol#414 - https://github.com/Arize-ai/openinference/tree/main/python/instrumentation/openinference-instrumentation-mcp
This documents the convention of using the request parameter key
_metato hold metadata for use in trace identifiers or correlation IDs.For example, if using w3c trace-context propagation (commonly used by opentelemetry), and progress flow, the client would encode a tools/call message like this:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "get_weather", "arguments": { "location": "New York" }, "_meta": { "progressToken": "abc123", "traceparent": "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" } } }Motivation and Context
Right now there's an emerging convention of using the
request.params._metafield to propagate extra metadata. For example, it is used in the MCP progress flow specification. It is also used to pass trace identifiers between MCP clients to the server, in order to establish causal links needed in observability. The motivation to standardize on_metais to avoid portability accidents (such as one side usingmetaand the other_meta).Longer discussion is here
How Has This Been Tested?
Arize OpenInference released
request.params._metapattern in their instrumentation for the official MCP python and typescript SDKs. This was a collaboration between Arize and Elastic with mammoth effort by @anuraaga recently, including ensuring it can integrate with MCP inspector. Arize did a video about it and have a code example here.The csharp-sdk has an existing implementation, but using
request.paramsinstead ofrequest.params._meta. I backfilled a test and raised a PR to switch to the latter.Breaking Changes
This is not a breaking change as the specification already allows this parameter value.
Types of changes
Checklist
Additional context
Fixes #246
Why document this considering extra params are not forbidden?
Neither JSON-RPC nor Model Context Protocol prohibit extra request parameters. However, documentation is essential to standardize context propagation (e.g., correlation and trace IDs) between client and server. Without it, parties must coordinate ad hoc, which can lead to inconsistent conventions or conflation of metadata with request parameters.
Why choose "_meta" instead of "meta" or "extra"?
The "_meta" field was selected for header-like data based on precedent and feedback:
request.params._metarequest.params._metarequest.params._meta.__traceContextWhy not solve this only for W3C trace-context?
Focusing solely on W3C trace-context (e.g., "traceparent", "tracestate") restricts flexibility.
DistributedContextPropagatorsupports fields like "Request-Id", "baggage", and "Correlation-Context", while OpenTelemetry includes B3, Jaeger, and more. A generic "_meta" field supports diverse systems, including non-tracing use cases, such as progress flow. Finally, documenting a single field keeps the spec changes to a minimum.That said, as you can tell from the description above, some agreement should be made as there are at least 2 different incompatible ways in use to propagation trace context.
Why not mix metadata with existing parameters?
Storing metadata in
request.params._metaprevents key conflicts and serialization errors. For example, an easy bug could be using OpenTelemetry text map serialization. If applied to the entire parameters object, it would corrupt the arguments like this.{ "jsonrpc": "2.0", "id": "2", "method": "tools/call", "params": { "name": "get_weather", "arguments": "{\"location\": \"New York\"}", "progressToken": "abc123", "traceparent": "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01" } }Another reason to not co-mingle is to prevent leaking secrets to an LLM. For example, if custom metadata is mixed with regular params, they could end up being sent to an LLM. If stored in
_meta, they can be summarily stripped. This redaction is important when custom metadata includes an auth value.Why not handle this directly in JSON-RPC?
The "meta" field is commonplace in many protocols over JSON-RPC. While not formally included in JSON-RPC 2.0, it is possible to have this discussion for 2.1, as started here.