typescript-sdk/packages/client/CHANGELOG.md
Felix Weinberger 1823aae891
Implement MCP 2026-07-28 (#2286)
Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 14:01:10 +01:00

28 KiB
Raw Blame History

@modelcontextprotocol/client

2.0.0-alpha.3

Major Changes

  • #2128 c8d7401 Thanks @felixweinberger! - SEP-2663: remove 2025-11 experimental tasks (TaskManager, experimental.tasks.* accessors). Tasks are now Extensions Track.

Minor Changes

  • #2049 4f226c1 Thanks @KKonstantinov! - Add SdkHttpError subclass with typed .status / .statusText accessors for HTTP transport failures. StreamableHTTPClientTransport now throws SdkHttpError (which extends SdkError) for non-OK HTTP responses; SSEClientTransport throws SdkHttpError for 401-after-reauth (circuit breaker).

  • #1974 db83829 Thanks @felixweinberger! - Add custom (non-spec) method support: a 3-arg setRequestHandler(method, schemas, handler) / setNotificationHandler(method, schemas, handler) form for vendor-prefixed methods, and a request(req, resultSchema) overload (also on ctx.mcpReq.send) for typed custom-method results. Spec-method calls are unchanged.

    Response result-schema validation failure now rejects with SdkError(InvalidResult) instead of a raw ZodError. Adds SdkErrorCode.InvalidResult.

  • #1653 6bec24a Thanks @rechedev9! - Add validateClientMetadataUrl() utility for early validation of clientMetadataUrl

    Exports a validateClientMetadataUrl() function that OAuthClientProvider implementations can call in their constructors to fail fast on invalid URL-based client IDs, instead of discovering the error deep in the auth flow.

  • #2354 0fb8406 Thanks @KKonstantinov! - Add the v2 IdJagTokenExchangeResponse type to the public API and register its schema as an MCP spec type. IdJagTokenExchangeResponse is now exported from @modelcontextprotocol/client and @modelcontextprotocol/server, 'IdJagTokenExchangeResponse' joins the SpecTypeName union, and isSpecType.IdJagTokenExchangeResponse(value) / specTypeSchemas.IdJagTokenExchangeResponse validate it by name — matching how the OAuth/OpenID auth schemas are already exposed. The Zod schema itself, IdJagTokenExchangeResponseSchema, is available from @modelcontextprotocol/core.

  • #2248 db28156 Thanks @felixweinberger! - Restore the 2025-11-25 task wire types that were removed together with the task feature: the task schemas and inferred types, task members of the request/result/notification unions, the task request-params augmentation, the tasks capability key, the isTaskAugmentedRequestParams guard, and RELATED_TASK_META_KEY. The task feature itself remains removed — servers do not advertise the tasks capability and inbound tasks/* requests receive -32601 — but the wire surface stays so SDKs interoperate cleanly with peers on the 2025-11-25 revision.

  • #1887 96db044 Thanks @felixweinberger! - Export isSpecType and specTypeSchemas records for runtime validation of any MCP spec type by name. isSpecType.ContentBlock(value) is a type predicate; specTypeSchemas.ContentBlock is a StandardSchemaV1Sync<ContentBlock> validator — validate() returns the result synchronously. Guards are standalone functions, so arr.filter(isSpecType.ContentBlock) works. Also export the SpecTypeName, SpecTypes, and StandardSchemaV1Sync types.

  • #1871 9fc9070 Thanks @felixweinberger! - Move stdio transports to a ./stdio subpath export. Import StdioClientTransport, getDefaultEnvironment, DEFAULT_INHERITED_ENV_VARS, and StdioServerParameters from @modelcontextprotocol/client/stdio, and StdioServerTransport from @modelcontextprotocol/server/stdio. The @modelcontextprotocol/client root entry no longer pulls in node:child_process, node:stream, or cross-spawn, fixing bundling for browser and Cloudflare Workers targets; the @modelcontextprotocol/server root entry drops its node:stream reference. Node.js, Bun, and Deno consumers update the import path; runtime behavior is unchanged.

Patch Changes

  • #1897 434b2f1 Thanks @felixweinberger! - Stop bundling @cfworker/json-schema into the main package barrel. Previously CfWorkerJsonSchemaValidator was re-exported from the core internal barrel, so tsdown inlined the @cfworker/json-schema dependency into every consumer's bundle even when it was never used. The named validator classes are now reachable only via the explicit @modelcontextprotocol/{client,server}/validators/{ajv,cf-worker} subpaths and the runtime _shims conditional, so consumers that import only from the root entry point no longer ship the validator dep.

  • #2269 e84c3e9 Thanks @mattzcarey! - Non-SEP draft spec conformance fixes

    • McpServer now eagerly installs list/read/call handlers for every primitive capability (tools, resources, prompts) declared in ServerOptions.capabilities. Per the draft spec, a server that declares a capability MUST respond to its list method (potentially with an empty result) instead of returning "Method not found". Previously, handlers were only installed lazily on first registration, so a server constructed with e.g. capabilities: { tools: {} } and zero registered tools answered tools/list with -32601. Low-level Server users remain responsible for registering handlers for declared capabilities (documented on ServerOptions.capabilities).
    • Fixed pagination doc examples on Client.listTools/listPrompts/listResources to loop while (cursor !== undefined) instead of while (cursor) — per the draft spec, clients MUST NOT treat an empty-string cursor as the end of results.
  • #1834 42cb6b2 Thanks @felixweinberger! - Export InMemoryTransport for in-process testing.

  • #1898 2a7611d Thanks @felixweinberger! - Add top-level types field (and typesVersions on client/server for their subpath exports) so consumers on legacy moduleResolution: "node" can resolve type declarations. The exports map remains the source of truth for nodenext/bundler resolution. The typesVersions map includes entries for subpaths added by sibling PRs in this series (zod-schemas, stdio); those entries are no-ops until the corresponding dist/*.d.mts files exist.

  • #1655 1eb3123 Thanks @nielskaspers! - fix(client): append custom Accept headers to spec-required defaults in StreamableHTTPClientTransport

    Custom Accept headers provided via requestInit.headers are now appended to the spec-mandated Accept types instead of being overwritten. This ensures the required media types (application/json, text/event-stream for POST; text/event-stream for GET SSE) are always present while allowing users to include additional types for proxy/gateway routing.

  • #2268 49c0a71 Thanks @mattzcarey! - Mark the roots, sampling, and logging runtime APIs as @deprecated per SEP-2577 (deprecated as of protocol version 2026-07-28; functional for at least twelve months). Annotates Server.createMessage/listRoots/sendLoggingMessage, McpServer.sendLoggingMessage, Client.setLoggingLevel/sendRootsListChanged, the ServerContext.mcpReq.log/requestSampling helpers, and the roots/sampling/logging capability schema fields. JSDoc/docs only — no behavior change.

  • #2275 1b53a41 Thanks @KKonstantinov! - Add a configurable maxBufferSize (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an onerror and closes instead of growing the buffer unbounded. Configure via new StdioClientTransport({ ..., maxBufferSize }) or new StdioServerTransport(stdin, stdout, { maxBufferSize }). The default is exported from @modelcontextprotocol/client / @modelcontextprotocol/server as STDIO_DEFAULT_MAX_BUFFER_SIZE.

  • #2088 16d13ab Thanks @mattzcarey! - Bundle automatic JSON Schema validator defaults in @modelcontextprotocol/client and @modelcontextprotocol/server runtime shims.

    Client and server pick the right validator automatically based on the runtime: the Node shim uses AJV, the browser/workerd shim uses @cfworker/json-schema. Both backends are bundled into the shim chunks that select them, so the default code path needs no extra installs — import { McpServer } from '@modelcontextprotocol/server' does not pull ajv or @cfworker/json-schema into the root entry chunk.

    The named validator classes remain part of the public surface for consumers who want to customize the built-in backend (pre-register schemas by $id, register custom AJV formats, switch dialects, change @cfworker/json-schema draft). They are exposed through explicit subpaths so they do not bloat the root index chunk:

    • import { AjvJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/ajv'
    • import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/cf-worker'

    Importing from one of these subpaths means the corresponding peer dep (ajv + ajv-formats, or @cfworker/json-schema) must be in your package.json. The shim keeps its own vendored copy for the default path, so a project can use the subpath in some files and rely on the default in others.

    The jsonSchemaValidator interface remains the public extension point for replacing validation entirely with a custom implementation.

  • #1976 55b1f06 Thanks @felixweinberger! - refactor: subclasses override _wrapHandler hook instead of redeclaring setRequestHandler.

  • #1895 b256546 Thanks @felixweinberger! - Fix runtime crash on tools/list when a tool's inputSchema comes from zod 4.0–4.1. The SDK requires ~standard.jsonSchema (StandardJSONSchemaV1, added in zod 4.2.0); previously a missing jsonSchema crashed at undefined[io]. standardSchemaToJsonSchema now detects zod 4 schemas lacking jsonSchema and falls back to the SDK-bundled z.toJSONSchema(), emitting a one-time console warning. zod 3 schemas (which the bundled zod 4 converter cannot introspect) and non-zod schema libraries without jsonSchema get a clear error pointing to fromJsonSchema(). The workspace zod catalog is also bumped to ^4.2.0.

2.0.0-alpha.2

Patch Changes

2.0.0-alpha.1

Major Changes

  • #1783 045c62a Thanks @felixweinberger! - Remove WebSocketClientTransport. WebSocket is not a spec-defined transport; use stdio or Streamable HTTP. The Transport interface remains exported for custom implementations. See #142.

Minor Changes

  • #1527 dc896e1 Thanks @felixweinberger! - Add discoverOAuthServerInfo() function and unified discovery state caching for OAuth

    • New discoverOAuthServerInfo(serverUrl) export that performs RFC 9728 protected resource metadata discovery followed by authorization server metadata discovery in a single call. Use this for operations like token refresh and revocation that need the authorization server URL outside of auth().
    • New OAuthDiscoveryState type and optional OAuthClientProvider methods saveDiscoveryState() / discoveryState() allow providers to persist all discovery results (auth server URL, resource metadata URL, resource metadata, auth server metadata) across sessions. This avoids redundant discovery requests and handles browser redirect scenarios where discovery state would otherwise be lost.
    • New 'discovery' scope for invalidateCredentials() to clear cached discovery state.
    • New OAuthServerInfo type exported for the return value of discoverOAuthServerInfo().
  • #1673 462c3fc Thanks @KKonstantinov! - refactor: extract task orchestration from Protocol into TaskManager

    Breaking changes:

    • taskStore, taskMessageQueue, defaultTaskPollInterval, and maxTaskQueueSize moved from ProtocolOptions to capabilities.tasks on ClientOptions/ServerOptions
  • #1763 6711ed9 Thanks @felixweinberger! - Add reconnectionScheduler option to StreamableHTTPClientTransport. Lets non-persistent environments (serverless, mobile, desktop sleep/wake) override the default setTimeout-based SSE reconnection scheduling. The scheduler may return a cancel function that is invoked on transport.close().

  • #1443 4aec5f7 Thanks @NSeydoux! - The client credentials providers now support scopes being added to the token request.

  • #1689 0784be1 Thanks @felixweinberger! - Support Standard Schema for tool and prompt schemas

    Tool and prompt registration now accepts any schema library that implements the Standard Schema spec: Zod v4, Valibot, ArkType, and others. RegisteredTool.inputSchema, RegisteredTool.outputSchema, and RegisteredPrompt.argsSchema now use StandardSchemaWithJSON (requires both ~standard.validate and ~standard.jsonSchema) instead of the Zod-specific AnySchema type.

    Zod v4 schemas continue to work unchanged — Zod v4 implements the required interfaces natively.

    import { type } from 'arktype';
    
    server.registerTool(
        'greet',
        {
            inputSchema: type({ name: 'string' })
        },
        async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}!` }] })
    );
    

    For raw JSON Schema (e.g. TypeBox output), use the new fromJsonSchema adapter:

    import { fromJsonSchema } from '@modelcontextprotocol/server';
    import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';
    
    server.registerTool(
        'greet',
        {
            inputSchema: fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } } }, new AjvJsonSchemaValidator())
        },
        handler
    );
    

    Breaking changes:

    • experimental.tasks.getTaskResult() no longer accepts a resultSchema parameter. Returns GetTaskPayloadResult (a loose Result); cast to the expected type at the call site.
    • Removed unused exports from @modelcontextprotocol/core-internal: SchemaInput, schemaToJson, parseSchemaAsync, getSchemaShape, getSchemaDescription, isOptionalSchema, unwrapOptionalSchema. Use the new standardSchemaToJsonSchema and validateStandardSchema instead.
    • completable() remains Zod-specific (it relies on Zod's .shape introspection).
  • #1710 e563e63 Thanks @felixweinberger! - Add AuthProvider for composable bearer-token auth; transports adapt OAuthClientProvider automatically

    • New AuthProvider interface: { token(): Promise<string | undefined>; onUnauthorized?(ctx): Promise<void> }. Transports call token() before every request and onUnauthorized() on 401 (then retry once).
    • Transport authProvider option now accepts AuthProvider | OAuthClientProvider. OAuth providers are adapted internally via adaptOAuthProvider() — no changes needed to existing OAuthClientProvider implementations.
    • For simple bearer tokens (API keys, gateway-managed tokens, service accounts): { authProvider: { token: async () => myKey } } — one-line object literal, no class.
    • New adaptOAuthProvider(provider) export for explicit adaptation.
    • New handleOAuthUnauthorized(provider, ctx) helper — the standard OAuth onUnauthorized behavior.
    • New isOAuthClientProvider() type guard.
    • New UnauthorizedContext type.
    • Exported previously-internal auth helpers for building custom flows: applyBasicAuth, applyPostAuth, applyPublicAuth, executeTokenRequest.

    Transports are simplified internally — ~50 lines of inline OAuth orchestration (auth() calls, WWW-Authenticate parsing, circuit-breaker state) moved into the adapter's onUnauthorized() implementation. OAuthClientProvider itself is unchanged.

  • #1614 1a78b01 Thanks @pcarleton! - Apply resolved scope consistently to both DCR and the authorization URL (SEP-835)

    When scopes_supported is present in the protected resource metadata (/.well-known/oauth-protected-resource), the SDK already uses it as the default scope for the authorization URL. This change applies the same resolved scope to the dynamic client registration request body, ensuring both use a consistent value.

    • registerClient() now accepts an optional scope parameter that overrides clientMetadata.scope in the registration body.
    • auth() now computes the resolved scope once (WWW-Authenticate → PRM scopes_supported → clientMetadata.scope) and passes it to both DCR and the authorization request.

Patch Changes

  • #1758 e86b183 Thanks @KKonstantinov! - tasks - disallow requesting a null TTL

  • #1824 fcde488 Thanks @felixweinberger! - Drop zod from peerDependencies (kept as direct dependency)

    Since Standard Schema support landed, zod is purely an internal runtime dependency used for protocol message parsing. User-facing schemas (registerTool, registerPrompt) accept any Standard Schema library. zod remains in dependencies and auto-installs; users no longer need to install it alongside the SDK.

  • #1761 01954e6 Thanks @felixweinberger! - Convert remaining capability-assertion throws to SdkError(SdkErrorCode.CapabilityNotSupported, ...). Follow-up to #1454 which missed Client.assertCapability(), the task capability helpers in experimental/tasks/helpers.ts, and the sampling/elicitation capability checks in experimental/tasks/server.ts.

  • #1632 d99f3ee Thanks @matantsach! - Continue OAuth metadata discovery on 502 (Bad Gateway) responses, matching the existing behavior for 4xx. This fixes MCP servers behind reverse proxies that return 502 for path-aware metadata URLs. Other 5xx errors still throw to avoid retrying against overloaded servers.

  • #1772 5276439 Thanks @felixweinberger! - Always set windowsHide when spawning stdio server processes on Windows, not just in Electron environments. Prevents unwanted console windows in non-Electron Windows applications.

  • #1390 9bc9abc Thanks @DePasqualeOrg! - Fix StreamableHTTPClientTransport to handle error responses in SSE streams

  • #1343 4b5fdcb Thanks @christso! - Fix OAuth error handling for servers returning errors with HTTP 200 status

    Some OAuth servers (e.g., GitHub) return error responses with HTTP 200 status instead of 4xx. The SDK now checks for an error field in the JSON response before attempting to parse it as tokens, providing users with meaningful error messages.

  • #1534 69a0626 Thanks @josefaidt! - remove npm references, use pnpm

  • #1386 00249ce Thanks @PederHP! - Respect capability negotiation in list methods by returning empty lists when server lacks capability

    The Client now returns empty lists instead of sending requests to servers that don't advertise the corresponding capability:

    • listPrompts() returns { prompts: [] } if server lacks prompts capability
    • listResources() returns { resources: [] } if server lacks resources capability
    • listResourceTemplates() returns { resourceTemplates: [] } if server lacks resources capability
    • listTools() returns { tools: [] } if server lacks tools capability

    This respects the MCP spec requirement that "Both parties SHOULD respect capability negotiation" and avoids unnecessary server warnings and traffic. The existing enforceStrictCapabilities option continues to throw errors when set to true.

  • #1534 69a0626 Thanks @josefaidt! - clean up package manager usage, all pnpm

  • #1595 13a0d34 Thanks @bhosmer-ant! - Don't swallow fetch TypeError as CORS in non-browser environments. Network errors (DNS resolution failure, connection refused, invalid URL) in Node.js and Cloudflare Workers now propagate from OAuth discovery instead of being silently misattributed to CORS and returning undefined. This surfaces the real error to callers rather than masking it as "metadata not found."

  • #1279 71ae3ac Thanks @KKonstantinov! - Initial 2.0.0-alpha.0 client and server package