Version Packages (#2555)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
faa7e2b470
commit
cc4b41617c
60 changed files with 514 additions and 355 deletions
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/core': patch
|
||||
'@modelcontextprotocol/server-legacy': patch
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
'@modelcontextprotocol/express': patch
|
||||
'@modelcontextprotocol/hono': patch
|
||||
'@modelcontextprotocol/fastify': patch
|
||||
'@modelcontextprotocol/node': patch
|
||||
---
|
||||
|
||||
First beta release of SDK v2 with support for the MCP 2026-07-28 specification
|
||||
revision. See the migration guides for upgrading from v1
|
||||
(`docs/migration/upgrade-to-v2.md`) and adopting the 2026-07-28 revision
|
||||
(`docs/migration/support-2026-07-28.md`).
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/core-internal': patch
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/core': patch
|
||||
'@modelcontextprotocol/server': patch
|
||||
---
|
||||
|
||||
Restore the v1 parse tolerance for `CallToolResult.content`: an inbound legacy-era `tools/call` result without `content` defaults to `[]` instead of failing validation. Deployed servers — accepted by SDK v1 for years — return `structuredContent`-only (or otherwise content-less) results, and the strict parse turned every such call into an `INVALID_RESULT` error before application code could run.
|
||||
|
||||
The silent-empty-success hazard the strictness guarded is preserved where it matters: the 2025 era's wire-seam schema refuses to default `content` for a body carrying another result family's vocabulary (`task`, `inputRequests`, `requestState` — the era is frozen, so the list is complete), and the 2026-era wire schemas stay strict — modern-revision servers have no legacy excuse. Task interop through an explicit result schema is untouched (including bodies that also stamp a foreign `resultType`), and the server-side authoring normalization refuses the same foreign-family vocabulary.
|
||||
|
||||
Server-side authoring is era-independent: a handler result without `content` (dynamic/JS callers — the TypeScript surface requires it) is normalized to `content: []` before era validation on every leg, reaching the wire spec-valid.
|
||||
|
||||
Conscious call: the nested sampling `ToolResultContentSchema` stays spec-strict — v1 had defaulted its `content` too, but it is params-side (tool results a caller authors into a sampling message), deliberately not restored.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/client': patch
|
||||
---
|
||||
|
||||
Fix the CommonJS `validators/ajv` subpath so reading the exported `Ajv` class no longer throws `ReferenceError: import_ajv is not defined`. The subpath now re-exports the bundled provider's concrete `Ajv` value in CJS output, matching the existing ESM behavior.
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/core': patch
|
||||
'@modelcontextprotocol/server-legacy': patch
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
'@modelcontextprotocol/express': patch
|
||||
'@modelcontextprotocol/hono': patch
|
||||
'@modelcontextprotocol/fastify': patch
|
||||
'@modelcontextprotocol/node': patch
|
||||
---
|
||||
|
||||
Ship CommonJS builds alongside ESM. Each package now emits both `.mjs`/`.d.mts`
|
||||
and `.cjs`/`.d.cts` (via tsdown `format: ['esm', 'cjs']`), and its `exports` map
|
||||
adds a `require` condition so `require('@modelcontextprotocol/…')` works from
|
||||
CommonJS consumers. Output extensions are normalized across all packages
|
||||
(`@modelcontextprotocol/core` moves from `.js`/`.d.ts` to `.mjs`/`.d.mts`); the
|
||||
public import paths are unchanged.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
---
|
||||
|
||||
Version the codemod together with the core SDK packages, matching the migration guide's shared-version guarantee.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
---
|
||||
|
||||
v1-to-v2 migration fixes from continued real-world migrations (codemod iterations 5).
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
---
|
||||
|
||||
Read the v2 package versions the codemod writes into migrated `package.json` files directly from the workspace manifests at build time, replacing the committed generated `versions.ts` (which went stale after every release and made source builds write outdated versions).
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/hono': patch
|
||||
'@modelcontextprotocol/node': patch
|
||||
---
|
||||
|
||||
POSTs whose `Content-Type` media type is not `application/json` are now
|
||||
rejected with `415 Unsupported Media Type`; the header is parsed instead of
|
||||
substring-matched. Previously any value merely containing the substring
|
||||
passed the check (for example `text/plain; a=application/json`), case
|
||||
variants were wrongly rejected, and the 2026-07-28 entry did not inspect
|
||||
`Content-Type` at all — requests with a missing or non-JSON header that used
|
||||
to be served on that path now also answer 415. Values with parameters
|
||||
(`application/json; charset=utf-8`, including malformed parameter sections
|
||||
like `application/json;`) continue to work. SDK clients always send the
|
||||
correct header and are unaffected.
|
||||
|
||||
The new `isJsonContentType(header)` helper is exported for transport and
|
||||
framework-adapter authors — custom entries composing the exported building
|
||||
blocks (`classifyInboundRequest`, `PerRequestHTTPServerTransport`) must apply
|
||||
it themselves. The hono adapter's JSON body pre-parse and the client's
|
||||
response dispatch now use the same parsed-media-type comparison.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/server': patch
|
||||
---
|
||||
|
||||
`instanceof` on the SDK error classes (`ProtocolError` and its typed subclasses, `SdkError`/`SdkHttpError`, `OAuthError`, and the client's `SseError`, `UnauthorizedError`, and OAuth-client-flow error family — `OAuthClientFlowError` and its subclasses) now works across separately bundled copies of the SDK. The classes match by a stable brand (via `Symbol.hasInstance` and a registry symbol) instead of prototype identity, so a process that uses both `@modelcontextprotocol/client` and `@modelcontextprotocol/server` - a gateway, host, or in-process test - can check errors constructed by either package against the class re-exported by the other. Ordinary prototype-based `instanceof` is preserved as a fallback; user-defined subclasses keep plain prototype semantics. Notes: cross-bundle matching requires both copies to be at or after this release; brands assert identity, not field shape, across versions - keep reading fields defensively. As a side effect, a foreign-bundle `SdkError` used as an abort reason is now rethrown as-is instead of being wrapped as a `RequestTimeout`. Branded hierarchies additionally expose an explicit static guard, `X.isInstance(value)`, that reads the same brand and narrows in TypeScript — an alternative for codebases that prefer predicate-style checks over `instanceof`. Also: `UnauthorizedError` now sets `error.name` to `'UnauthorizedError'` (previously `'Error'`), and per-package conformance tests enforce that every exported error class participates in branding. Version-negotiation probing now recognizes `UnauthorizedError` (previously a dead name-string check) and propagates it unchanged, so `connect()` on an auth-gated server rejects with the original `UnauthorizedError` (previously wrapped as the `cause` of an `SdkError(EraNegotiationFailed)`) — run `finishAuth()` and reconnect, and the retry probes with the token.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/node': patch
|
||||
---
|
||||
|
||||
Document composing the host and origin validation guards in front of `toNodeHandler` for hand-wired `node:http` servers, matching the protected wiring the examples and serving guide now demonstrate.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/core-internal': minor
|
||||
'@modelcontextprotocol/client': minor
|
||||
'@modelcontextprotocol/server': minor
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
---
|
||||
|
||||
Export the `Protocol` base class and `mergeCapabilities` from the `@modelcontextprotocol/client` and `@modelcontextprotocol/server` package roots, restoring the v1 import for consumers that subclass `Protocol` (e.g. the MCP Apps SDK). The client and server packages each bundle their own compiled copy of the class, so import it from one package consistently within a process.
|
||||
|
||||
The codemod now rewrites `Protocol` and `mergeCapabilities` imports from `shared/protocol.js` to the client or server package root, like the module's other symbols, instead of dropping them with an action-required marker.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
---
|
||||
|
||||
The Streamable HTTP client transport no longer attaches a session ID to a POST containing an `initialize` request — a new session starts "without a session ID attached" (2025-11-25 transports §Session Management) — and it only captures the `mcp-session-id` response header from a successful initialize response, since the spec assigns the session ID "at initialization time … on the HTTP response containing the InitializeResult". Previously the transport stored the header from any response, so a legacy server answering a protocol-version probe with an error that happened to carry a session ID would poison the fallback initialize, which then went out with a session ID it should not have had. A stale session ID from a previous connection is likewise no longer leaked onto the initialize handshake, and a successful initialize response that carries no session ID now clears any stale ID the transport was holding — clients include only an ID "returned by the server during initialization", so an ID the server never returned this session is outside the session model. Ignoring `mcp-session-id` headers mid-session is the complement of the spec's one actual rotation mechanism: a server that wants a new session terminates the old one (it "MAY terminate the session at any time") and answers 404, after which the client "MUST start a new session by sending a new InitializeRequest without a session ID attached". Rotation exists as session replacement via 404 + re-initialize, never as a header swap on a live session, so a server that rotates per the spec's own flow is handled correctly by this transport.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/server': patch
|
||||
---
|
||||
|
||||
Construct the default Ajv validation engine lazily on first validation. Creating a `Client` or `Server` no longer pays the ajv + ajv-formats instantiation cost at startup when no JSON Schema validation ever runs.
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/server-legacy': patch
|
||||
---
|
||||
|
||||
Build protocol-revision wire schemas lazily on first validation instead of at import. Each revision's schema set is now constructed by a module-level memoized factory, so importing the client or server package no longer pays the construction cost of both frozen wire-schema graphs up front. Method membership in the revision registries stays static, the schemas themselves are unchanged, and registry lookups keep returning reference-identical schema objects.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
---
|
||||
|
||||
Return JSON-RPC Invalid Params with the original URI and an `invalid_uri` reason when `resources/read` receives a syntactically malformed URI.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/server': patch
|
||||
'@modelcontextprotocol/core-internal': patch
|
||||
---
|
||||
|
||||
Return HTTP 400 for a `MissingRequiredClientCapabilityError` (`-32021`) produced after dispatch. The spec mandates `400 Bad Request` for this error with no condition on where it arose, but only the pre-dispatch capability gate honored that; the post-handler emission — the `input_required` gate rejecting an embedded request whose required capability the caller did not declare — surfaced in-band on HTTP 200. The JSON-RPC error body is unchanged, every other error code (including a handler relaying a downstream peer's `-32020`/`-32022`) keeps the origin-keyed in-band behavior, and the mapping only applies while the response is uncommitted: an exchange that already streamed — or one hosted with `responseMode: 'sse'`, which opens its stream at dispatch end — keeps its committed 200 and carries the error in-stream.
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
{
|
||||
"mode": "exit",
|
||||
"tag": "beta",
|
||||
"initialVersions": {
|
||||
"@modelcontextprotocol/eslint-config": "2.0.0",
|
||||
"@modelcontextprotocol/tsconfig": "2.0.0",
|
||||
"@modelcontextprotocol/vitest-config": "2.0.0",
|
||||
"@modelcontextprotocol/examples": "2.0.0-alpha.0",
|
||||
"@mcp-examples/client-quickstart": "2.0.0-alpha.0",
|
||||
"@mcp-examples/server-quickstart": "2.0.0-alpha.0",
|
||||
"@mcp-examples/shared": "2.0.0-alpha.0",
|
||||
"@modelcontextprotocol/client": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/codemod": "2.0.0-alpha.2",
|
||||
"@modelcontextprotocol/core": "2.0.0-alpha.2",
|
||||
"@modelcontextprotocol/core-internal": "2.0.0-alpha.3",
|
||||
"@modelcontextprotocol/express": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/fastify": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/hono": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/node": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/server": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/server-legacy": "2.0.0-alpha.4",
|
||||
"@modelcontextprotocol/test-conformance": "2.0.0-alpha.1",
|
||||
"@modelcontextprotocol/test-e2e": "2.0.0-alpha.1",
|
||||
"@modelcontextprotocol/test-helpers": "2.0.0-alpha.0",
|
||||
"@modelcontextprotocol/test-integration": "2.0.0-alpha.1"
|
||||
},
|
||||
"changesets": [
|
||||
"beta-release",
|
||||
"calltoolresult-content-default",
|
||||
"cjs-ajv-validator-subpath",
|
||||
"cjs-support-v2-packages",
|
||||
"codemod-fixed-group",
|
||||
"codemod-iterations-5",
|
||||
"codemod-versions-from-manifests",
|
||||
"content-type-media-type-validation",
|
||||
"cross-bundle-error-instanceof",
|
||||
"examples-protected-wiring",
|
||||
"export-protocol-class",
|
||||
"initialize-session-hygiene",
|
||||
"lazy-ajv-engine",
|
||||
"lazy-era-wire-schemas",
|
||||
"malformed-resource-uri-invalid-params",
|
||||
"post-dispatch-32021-http-400",
|
||||
"prior-legacy-verdict",
|
||||
"probe-close-handling",
|
||||
"probe-window-handler-restore",
|
||||
"response-cache-document-codec",
|
||||
"schemas-source-home",
|
||||
"silent-validators-wave",
|
||||
"spec-3002-servinfo-meta",
|
||||
"standard-header-ows",
|
||||
"standard-schema-elicitation",
|
||||
"web-standard-bearer-auth",
|
||||
"web-standard-oauth-metadata",
|
||||
"workerd-schema-preload"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': minor
|
||||
---
|
||||
|
||||
`ConnectOptions.prior` accepts a cached era verdict — the new exported type `PriorDiscovery`. `{ kind: 'modern', discover }` adopts a previously obtained `DiscoverResult` with zero round trips; `{ kind: 'legacy' }` skips the `server/discover` probe and runs the plain `initialize` handshake directly, for servers known out-of-band to be legacy — without pinning the client to `mode: 'legacy'`: stop supplying the verdict and `connect()` falls back to the configured `versionNegotiation` mode (under `'auto'`, it re-probes and rediscovers an upgraded server). Freshness is the supplying host's responsibility — a stale legacy verdict succeeds silently against an upgraded server, so hosts must date cached legacy verdicts in their own storage and stop supplying them past their policy horizon. Persisted-blob plumbing is hardened: `prior: null` is treated as absent, the modern arm's `discover` payload is schema-validated before any connection state changes, and an unrecognized shape rejects with a typed `SdkError(EraNegotiationFailed)` instead of a `TypeError`.
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
---
|
||||
|
||||
The version-negotiation probe no longer misclassifies auth-protected or
|
||||
failing servers as legacy. Auth status is never era evidence: a 401 or 403
|
||||
rejection of the `server/discover` probe now surfaces as a typed
|
||||
authorization failure — an `SdkHttpError` with code `ClientHttpAuthentication`
|
||||
(401) or `ClientHttpForbidden` (403), carrying the HTTP status, reason
|
||||
phrase, and response text — instead of triggering the legacy `initialize`
|
||||
fallback (which put a doomed `initialize` on the wire) or, under `pin` mode,
|
||||
the false "server did not offer pinned protocol version" diagnostic. The
|
||||
codes are deliberately not `EraNegotiationFailed`, so era-recovery flows
|
||||
keyed on that code cannot persist a verdict for an unauthorized exchange. A
|
||||
5xx rejecting the probe is a server failure and now also rejects typed
|
||||
(`SdkHttpError(EraNegotiationFailed)`) instead of demoting a mid-deploy
|
||||
modern server to legacy — the legacy fallback now fires only on the 4xx
|
||||
shapes the spec licenses.
|
||||
|
||||
With an `authProvider`, a `401` (and a `403` `insufficient_scope` challenge) runs the transport's auth flow first — a plain `403` rejects the same as without a provider — and whatever
|
||||
escapes it propagates unchanged, identity intact: the HTTP transports stamp
|
||||
errors at their auth seams (the `token()` read, `onUnauthorized` including
|
||||
custom callbacks, the 403 step-up flow, and their own auth-failure
|
||||
constructions), so `UnauthorizedError` for `finishAuth()`, the flow's typed
|
||||
failures (`OAuthError`, `InsufficientScopeError`, the
|
||||
401-after-re-authentication diagnostic), and even an untyped `TypeError`
|
||||
thrown inside the flow all reach the caller as thrown — never rewrapped,
|
||||
never consumed by the probe's browser CORS heuristic as legacy-era evidence.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@modelcontextprotocol/client': patch
|
||||
---
|
||||
|
||||
Probe stdio servers on a disposable sibling process. Some stdio servers exit on any pre-`initialize` request (servers built on the official Rust SDK, rmcp, behave this way), so under `versionNegotiation: { mode: 'auto' }` the `server/discover` probe previously killed the server and `connect()` hard-failed. The probe now runs on a short-lived sibling spawned from the same parameters — its stderr is discarded and it is reaped once the era is known — and the caller's transport spawns exactly once, afterwards: a legacy verdict connects with the plain `initialize` handshake (byte-identical to `mode: 'legacy'`), a modern verdict is adopted directly, and the session wire never carries `server/discover`. Closing the caller's transport during the probe aborts `connect()` with the typed `SdkError(EraNegotiationFailed)` and the session child is never spawned. On HTTP — and on custom stdio-shaped transports, which probe in place — a mid-probe connection close keeps rejecting with the typed connect error, now naming the close in pin-mode and modern-only diagnostics.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue