Proposal: i18n via per-request language negotiation#42
Open
SamMorrowDrums wants to merge 7 commits into
Open
Conversation
Mirrors SEP-2792 (modelcontextprotocol#2792) into the Transports WG proposals/ directory for review of the transport-touching aspects: Streamable HTTP Accept-Language / Content-Language mirroring, byte-equality enforcement, Vary semantics, and per-request statelessness. Co-authored-by: Copilot <[email protected]>
kurtisvg
reviewed
Jun 19, 2026
Mirrors changes from modelcontextprotocol#2792. Addresses @kurtisvg review comments on this PR: - Schema-property descriptions: explicit MAY with a caveat that translation alters what the model sees, with a concrete Codex reference instead of handwaving. - Open-ended "any other displayed field" bullet replaced with an enumerated MUST/MAY/MUST NOT list anchored to the spec's own classification of each field. Co-authored-by: Copilot <[email protected]>
- Resolve duplicate MUST-NOT-translate list (Scope is canonical). - Fix broken Scope anchor. - Resolve notifications open question into the Specification. - Make error.message localization choice explicit. - Update SEP-2243/2575 link targets to merged seps/ files. - Trim Reference Implementation paragraph. Co-authored-by: Copilot <[email protected]>
Drop the parallel localizedMessage field in favor of translating error.message directly. error.code remains the machine-interpreted identifier; error.message is the display string. Co-authored-by: Copilot <[email protected]>
kurtisvg
reviewed
Jul 2, 2026
kurtisvg
left a comment
Collaborator
There was a problem hiding this comment.
Overall, supportive of voting on this to bring to the CMs.
Add concrete public-sector and mixed-language examples, make UI localization a SHOULD, adopt HeaderMismatch -32020, and narrow contentLanguage requirements to negotiated responses. Tighten RFC semantics, header matching, and citations. Co-authored-by: Copilot App <[email protected]> Copilot-Session: b3246f61-3161-4e03-88b5-1137fcbd59e9
Co-authored-by: Copilot App <[email protected]> Copilot-Session: b3246f61-3161-4e03-88b5-1137fcbd59e9
Specify comparison over decoded JSON and parsed HTTP field values, including repeated fields, OWS, normalization, and cache behavior. Co-authored-by: Copilot App <[email protected]> Copilot-Session: b3246f61-3161-4e03-88b5-1137fcbd59e9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bringing this to the Transports WG for review and comment before bringing to the core maintainers.
Upstream SEP: modelcontextprotocol/modelcontextprotocol#2792 (now draft, pending WG input).
Reference implementation: modelcontextprotocol/typescript-sdk#2158 — full client + server, stdio and Streamable HTTP, byte-equality enforcement, 11-case integration matrix.
What this proposes
A single, transport-agnostic way for clients to express language preference per request, and for servers to indicate the language used per response:
params._meta['io.modelcontextprotocol/acceptLanguage']on requestsresult._meta['io.modelcontextprotocol/contentLanguage'](anderror.data._meta[...]) on responsesAccept-Language/Content-Languagestrings (BCP 47 language-range lists with quality values), so no new grammar.Why this is a transports concern
For Streamable HTTP, the proposal mirrors
_metainto the standardAccept-Language/Content-LanguageHTTP headers:Mcp-Method/Mcp-Name(RPC content surfaced as headers for infra observability and routing)._metawhen both are present, rejected via a newHeaderMismatchJSON-RPC error (provisional-32005, HTTP 400). Header absence is tolerated (CDNs stripAccept-Languageby default);_metais the authoritative carrier.Vary: Accept-Languageis MUST on cacheable responses whose body depends on negotiated language._metais still authoritative.For stdio: same
_metafields, no transport changes.Why per-request, not session
Aligns with the recent stateless-by-default direction: language can change mid-conversation (user retries in another language, agent serves multiple end-users) without renegotiation. There is no
initialize-time language state.