| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Hi @kurtisvg, @pja-ant, tagging you both directly given your feedback on #2355, which is the seed for this SEP (indeed I believe we discussed at MCP Dev Summit that I would look at converting this to a SEP in order to include the metadata for all transports).
Scope is intentionally narrow: user-facing strings (titles, descriptions, UI-bound errors, user-visible notifications) are the primary target; servers MAY also translate body content. Reference implementation is up as a draft on the TypeScript SDK: modelcontextprotocol/typescript-sdk#2158. It includes the core _meta helpers (wrapping @formatjs/intl-localematcher, no bespoke matcher), Streamable HTTP header/_meta mirroring with the strict-mismatch rule, stdio pass-through, an en/fr/de example server + client across both transports, and unit + integration tests, including the per-request mid-session language switch proof on stdio. All builds, typechecks, lints and tests pass. Would either of you be willing to sponsor? |
Sorry, something went wrong.
Adds a transport-agnostic, fully opt-in i18n mechanism for MCP using _meta['io.modelcontextprotocol/acceptLanguage'] on requests and _meta['io.modelcontextprotocol/contentLanguage'] on responses, mirrored into the standard HTTP Accept-Language / Content-Language headers on the Streamable HTTP transport with a strict-mismatch rule consistent with SEP-2243. Per-request scope (no handshake-bound state) aligns with SEP-2575 and supports mid-conversation language switching. Reuses BCP 47, RFC 4647 language-range matching, and existing ecosystem libraries verbatim, no bespoke matcher or schema. Supersedes modelcontextprotocol#2355. Proposes subsuming the locale aspect of SEP-1809. Reference implementation: modelcontextprotocol/typescript-sdk#2158 (en/fr/de server + client, stdio and Streamable HTTP, unit and integration tests including mid-session language switch on stdio). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Clean, well-scoped, and I think the shape is right: per-request language in _meta, mirrored to the HTTP headers, no session state. Lines up with SEP-2243 and SEP-2575, reuses BCP 47 / Accept-Language rather than inventing anything. No objections to the design — and the scary-sounding mismatch-rule concerns don't hold up, since the 400 only fires when both the header and body _meta are present and disagree (and _meta isn't intermediary-rewritable).
Two things to fix first:
Minor: name the mismatch code explicitly (-32001 HeaderMismatch, now in the draft spec — the TS impl drifted to SendFailed); and "reused unchanged" undersells it — you're extending the 2243 rule to a standard header, worth a line in Security Implications.
Structure's all there, file/docs are right. Just needs a sponsor and (for Final) a conformance scenario per SEP-2484.
Sorry, something went wrong.
- Drop Batching section (JSON-RPC batching is removed from MCP) - Define error-response localization via error.data._meta - Name mismatch error explicitly as -32001 HeaderMismatch - Reframe SEP-2243 relationship as extending its rule and error code - Add SEP-2484 conformance scenario outline Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Feedback applied @pja-ant - thank you for the thorough review. Changes in b5667477:
The TS SDK reference implementation (modelcontextprotocol/typescript-sdk#2158) is being updated in lockstep: switching the placeholder SdkErrorCode.SendFailed to -32001 HeaderMismatch, implementing error.data._meta localization with HTTP Content-Language mirroring on errors, and demonstrating both in the example server/client with tests. |
Sorry, something went wrong.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Accept-Language/Content-Language are routinely stripped, normalized, or rewritten by intermediaries (CloudFront default behavior, Fastly accept.language_lookup, Varnish vmod_accept). RFC 9110 also lacks a canonical byte-equality form for Accept-Language. Applying SEP-2243's hard-fail rule to these headers would error out exactly the edge-i18n deployments we cite as motivating. - _meta is now canonical; headers are best-effort hints (SHOULD mirror) - Remove -32001 HeaderMismatch reject path entirely - Reframe Why-mirror rationale around expected intermediary rewriting - Replace mismatch-attack security note with header-tampering-expected - Replace conformance scenario 4 (reject mismatch) with one asserting that a stripped/rewritten Accept-Language MUST NOT cause rejection - Update reference-implementation summary to drop mismatch claims Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Feedback applied @pja-ant - and you're right, this is much cleaner. 63dc3e1a drops the strict header/body mismatch rule for Accept-Language / Content-Language entirely. The new model:
This also sidesteps the -32001 vs SDK conventions discussion entirely, since we no longer need a code at all. |
Sorry, something went wrong.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The PoC implementation notes (build status, deferred mismatch rule rationale, SSE vs JSON header behavior) belong in the PR description, not in the SEP itself. Keep the SEP focused on the protocol design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per WG feedback (Kurtis), revert the bare-header-tolerated design and restore strict byte-equality between _meta and the corresponding HTTP header on both request (Accept-Language) and response (Content-Language) sides, with header absence on requests tolerated for CDN compatibility. Use error code -32005 for HeaderMismatch instead of -32001, which is already in conflicting use across SDKs (REQUEST_TIMEOUT in Python and Kotlin vs HeaderMismatch in Go and C#); the code is provisional pending SEP-2243 / SEP-2678 / PR modelcontextprotocol#2642 schema-level reservation work. Add a Normalization footgun section covering Fastly, Varnish, CloudFront and reverse-proxy header rewriting; consolidate operator-config detail in that section so Security and Backward Compatibility just link to it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Split the bundled 'header absent / bare header' bullet into two distinct rules so each cell of the (_meta-present, header-present) matrix has its own normative line. - Trim the Streamable HTTP intro to one opinionated paragraph. - Drop the trailing 'no new attack surface' platitude from Security. - Promote 'caches must Vary' from a reminder to a MUST. - Replace 'Tentative answer' hedging in Open Questions with explicit proposed resolutions. - Reference Implementation point 5 reads as a factual list rather than a results pitch. - Add [RFC 9111] reference link. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MUST NOT rule lives in the Specification section that immediately follows; the cross-reference adds no information. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The bullet list and coordination note restated the preceding paragraph. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The detailed bullet list duplicated the linked PR's description and will rot. Keep the SEP terse; the PR is the source of truth. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Vary requirement now lives normatively in the Response section. Security bullet shortened to a pointer. The Open Questions entry is resolved (MUST) and dropped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drop the bold leading-phrases on 6 and 7 so all seven scenarios use the same plain-bullet style. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses @kurtisvg feedback on transports-wg#42: - Replaces the open-ended "any field the host displays" catch-all with an explicit, enumerated list anchored to the schema's own classification of each field (display-only vs "hint to the model"). - Makes the consequence of translating model-facing fields (Tool.description, inputSchema descriptions, etc.) explicit, with a concrete example from the Codex implementation, instead of handwaving. - Calls out MCP Apps UI resource bodies (SEP-1865) by name. - Defers schema property descriptions (dual-purpose model + human) to MAY with a stated caveat rather than a separate SEP. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…8n-language-negotiation
- Resolve merge with main. - Drop duplicate (and now-stale) MUST NOT translate list from the acceptLanguage subsection; the Scope section is the single source of truth. - Fix broken anchor to the renamed Scope heading. - Resolve the open question on notifications into the Specification: notifications carrying user-facing text MUST set params._meta[contentLanguage]. Open Questions section removed. - Make the error.message localization choice explicit (server may localize message inline or carry the translated text in a structured error.data field). - Update SEP-2243 and SEP-2575 link targets from PRs to the merged seps/ files. - Trim the Reference Implementation paragraph. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bring PR modelcontextprotocol#2792 up to date with upstream main (163 commits) and replace seps/2792-i18n-language-negotiation.md with the Transports WG-reviewed authoritative source at SamMorrowDrums/transports-wg@c85169e (proposals/XXXX-i18n-language-negotiation.md). Highlights vs previous PR head (94cc51c): - HeaderMismatch error code is now the settled `-32020` (matches the reservation now live in schema/draft/schema.ts on main), replacing the provisional `-32005`. - Exact HTTP field-value comparison algorithm: comparison happens on the decoded JSON string vs. the parsed HTTP field-value (per RFC 9110 §5.5), so surrounding OWS is stripped and repeated field lines are joined with `, ` before byte-comparison. Explicit worked examples for OWS, case, q-value zero-padding, and multi-line fields added to Conformance. - Corrected RFC/citation semantics throughout (RFC 9110 §5.3, §5.5, §12.5.4, §12.5.5; RFC 9111 §4.1; RFC 5646 §2.1.1) and clarified language-matching reuse (server hands the value verbatim to any RFC 4647 matcher; no bespoke matching defined here). - error.message localized in place (no parallel field), with the contract that error.code remains the machine-interpreted identifier and clients MUST NOT branch on error.message text. - Notifications rule promoted from Open Questions into Specification. - Scope restated as three explicit MUST / MAY-with-caveat / MUST-NOT buckets, anchored to the schema's own field-level classification. Regenerated docs/seps/2792-i18n-language-negotiation.mdx and refreshed docs/seps/index.mdx and docs/docs.json via `npm run generate:seps`. `npm run check:seps` clean. Supersedes stash "sep-2792 error.message edit, pending WG outcome".
These four SEPs (1330, 1577, 2322, 2663) arrived from upstream/main with pre-existing prettier drift in their TypeScript code fences (missing leading `|` in union types). The Markdown Format Check CI job on this PR fails on them even though the changes are unrelated to SEP-2792. Apply `prettier --write` to satisfy CI; content is unchanged (union-type formatting only). No mdx regeneration needed — the rendered mdx already matches. Also verified: - npm run check:seps: clean - npm run check:docs:format: clean
Prettier 3.9.5 (pinned in package.json) formats these differently than 3.8.3 did (which was in this workspace's stale node_modules when the previous commit ran). CI runs `npm ci` so it uses 3.9.5 and rejects the un-reformatted files. Apply `npm run format:docs` so both md and mdx match the pinned prettier version. Verified: - npm run check:docs:format: clean - npm run generate:seps: clean - npm run check:seps: clean
Narrow SEP-2792 to request-scoped language preference propagation, precise display-field translation guidance, HTTP mirroring, and language-aware caching. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f2236498-f7bf-43f1-9ef1-d54fd21665ae
The simplified draft referred to "the transport's equality rule" without saying what it was, so two conformant implementations could reach different verdicts on the same request and the conformance scenario could not be written. Define it. Mirror agreement is exact equality of the two exposed field values, and is distinct from RFC 4647 language matching, which stays semantic. Spell out the comparison: take the decoded _meta string unnormalized, take the HTTP field value after normal field parsing (RFC 9110 5.5), join repeated field lines in received order with comma SP (RFC 9110 5.3), then compare character for character with no parsing or re-serialization. Require an HTTP API that exposes all field line values, and require senders to emit a single field line. Also make agreement evaluation order explicit relative to grammar validation, extend the response mirror to error responses and SSE streams, note that a present mirrored field must be preserved exactly or removed by intermediaries, and add the exact-match conformance cases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f2236498-f7bf-43f1-9ef1-d54fd21665ae
| Back | FazBrowse Home | New Git URL |
Summary
SEP-2792 defines transport-neutral propagation of a user's natural-language preference on each MCP request:
Core behavior
Clients with a known applicable preference should send it on every request. Servers may ignore it; participating servers use RFC-compatible matching, fall back without error when no language matches, and report the actual selected language.
The display-oriented translation guidance is intentionally narrow: BaseMetadata.title on current title-bearing types, ToolAnnotations.title, elicitation messages and form property titles/descriptions, and progress messages are in the SHOULD category. Error.message and other natural-language/model-facing/returned content are MAY, with an explicit warning that translation can change model behavior. Machine-interpreted names, methods, URIs, schema keys, enum/const values, discriminators, protocol identifiers, error codes, _meta keys, and opaque tokens remain stable.
Explicit method or tool language arguments SHOULD take precedence for the content they control; the negotiated preference remains fallback context and MAY provide a fallback when the explicit argument is absent. It is available before discovery or tool selection.
HTTP and caching
_meta is canonical across transports. Streamable HTTP clients mirror the preference to Accept-Language; JSON responses mirror the selected language to Content-Language. SSE and notifications retain per-message _meta reporting.
Mirror agreement is exact equality of the field values, not semantic Accept-Language equivalence and not raw wire bytes. The SEP spells out the comparison: take the decoded _meta string unnormalized, take the HTTP field value after normal field parsing (RFC 9110 §5.5), join repeated field lines in received order with comma SP (RFC 9110 §5.3), then compare character for character. Tag casing, comma spacing, range order, and q-value spelling are therefore significant. A present mismatch is rejected with 400 Bad Request and HeaderMismatch (-32020), while a stripped request header can be tolerated — the asymmetry agreed in review. Intermediaries must preserve a present mirrored field exactly or remove it.
Language-dependent responses remain cacheable. MCP/client caches include acceptLanguage in the cache key when representations vary, existing ttlMs/cacheScope semantics remain intact, and HTTP variants use Vary: Accept-Language. Shared caches that cannot observe the language signal must use a visible equivalent key or keep the response private.
Examples
The proposal leads with localized tools/list discovery: stable tool name, localized display title, and no model or tool argument involvement. It follows with localized elicitation UI using a stable form field key, then shows an explicit language argument overriding the fallback preference for an official document edition.
Transport WG review
The Transport WG proposal is modelcontextprotocol/transports-wg#42. The vote passed with 3 Accept and 3 Accept with Changes. The requested changes were:
Both are addressed in this revision through discovery/elicitation examples and dedicated rationale sections.
Reference implementation and prior art
AI disclosure
This SEP was authored with assistance from GitHub Copilot.