SEP-2792: Reference implementation for per-request language negotiation#2158
SEP-2792: Reference implementation for per-request language negotiation#2158SamMorrowDrums wants to merge 4 commits into
Conversation
…tiation Implements internationalization via per-request language negotiation as specified in SEP-2792. Changes include: SDK changes: - Add i18n helper module (packages/core/src/shared/i18n.ts) with: - ACCEPT_LANGUAGE_META / CONTENT_LANGUAGE_META constants - getAcceptLanguage / setAcceptLanguage helpers for request _meta - getContentLanguage / setContentLanguage helpers for response _meta - negotiateLanguage() using @formatjs/intl-localematcher (RFC 4647) - Client Streamable HTTP transport: mirrors _meta acceptLanguage to Accept-Language header; throws on header/body mismatch - Server Streamable HTTP transport: validates Accept-Language header vs _meta (400 on mismatch), copies header→_meta when only header present, mirrors Content-Language header from response _meta on JSON responses Examples: - examples/server/src/i18nExample.ts: server with get_greeting tool supporting en/fr/de via stdio and HTTP transports - examples/client/src/i18nClient.ts: client demonstrating three language scenarios (exact, fallback chain, no-match fallback) Tests: - Unit tests for all helpers and negotiateLanguage (quality values, subtag matching, fallback behavior) - HTTP integration tests: header mirroring, Content-Language on response, 400 on mismatch, agreement pass-through - stdio integration test: mid-session language switching on same connection Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/server
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
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>
1. Use -32001 HeaderMismatch error code (SEP-2243) for language header/body mismatch on both client and server sides. 2. Add error-response localization: getErrorContentLanguage/ setErrorContentLanguage helpers for error.data._meta, mirror Content-Language header from error responses, demonstrate in example server (empty name triggers localized error). 3. Remove batch handling from client Accept-Language extraction (MCP no longer permits JSON-RPC batches over Streamable HTTP). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update: Review feedback addressed (commit 5a5f548)Following @pja-ant's review on the SEP (modelcontextprotocol/modelcontextprotocol#2792), three changes applied per SEP commit b5667477: 1.
|
…view The SEP-2792 strict mismatch rule is dropped per reviewer feedback: intermediaries (CloudFront, Fastly, Varnish) routinely strip or rewrite Accept-Language, making byte-equality enforcement unreliable. Changes: - Server: rename validateAndCopyAcceptLanguage → copyAcceptLanguageFromHeader; always use _meta as canonical, fall back to header only when _meta absent - Client: remove mismatch throw; always mirror _meta → header unconditionally - Delete HEADER_MISMATCH_ERROR_CODE constant (no longer used) - Replace mismatch integration test with positive 'stripped header' tests - Remove HEADER_MISMATCH_ERROR_CODE unit test Refs: SEP commit 63dc3e1a on SamMorrowDrums/modelcontextprotocol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove header/body mismatch rejection (SEP commit
|
SEP-2792 now defines _meta[acceptLanguage] as the ONLY canonical carrier. Servers MUST NOT treat a bare Accept-Language header (without _meta) as an MCP language preference. This removes the copyAcceptLanguageFromHeader method entirely — the server transport no longer reads Accept-Language on the inbound path at all. Client still mirrors _meta → Accept-Language on outbound (best-effort hint). Server still mirrors _meta[contentLanguage] → Content-Language on response. Refs: SEP commit 8e1b6f4d on SamMorrowDrums/modelcontextprotocol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove bare-header fallback (SEP commit
|
SEP-2792: Reference Implementation
This PR implements the reference implementation for SEP-2792: Internationalization via Per-Request Language Negotiation.
What shipped in the SDK
Core i18n helpers (
packages/core/src/shared/i18n.ts):ACCEPT_LANGUAGE_META/CONTENT_LANGUAGE_META(usingio.modelcontextprotocol/vendor prefix)getAcceptLanguage,setAcceptLanguage,getContentLanguage,setContentLanguagenegotiateLanguage(acceptLanguage, available, defaultLocale?)— thin wrapper around@formatjs/intl-localematcherfor RFC 4647 matchingClient Streamable HTTP transport (
packages/client/src/client/streamableHttp.ts):_meta[acceptLanguage]→Accept-LanguageHTTP header on outbound requestsServer Streamable HTTP transport (
packages/server/src/server/streamableHttp.ts):Accept-Languageheader vs_metaon inbound POST (returns HTTP 400 on mismatch)_metawhen only header is present (transparent to handler code)_meta[contentLanguage]→Content-Languageresponse headerExample server & client
examples/server/src/i18nExample.ts: Aget_greetingtool localized in en/fr/de, supporting both stdio and HTTPexamples/client/src/i18nClient.ts: Exercises three scenarios — explicit English, French-Canadian with quality-value fallback, and Japanese (forces fallback to English)Sample client output (stdio transport):
AI Disclosure
This PR was authored with assistance from GitHub Copilot (claude-opus-4.6).
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com