Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/spec-anchor-repin-2fb207da.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@modelcontextprotocol/core': patch
'@modelcontextprotocol/client': patch
'@modelcontextprotocol/server': patch
---

Re-pin the 2026-07-28 draft references (spec reference types, vendored schema.json twins, example corpus) to the latest spec commit and align the 2026-era wire surface with it. Deliberate 2026-era wire behavior changes (the released 2025-11-25 surface is untouched):

- `notifications/elicitation/complete` is no longer part of the 2026-07-28 wire registry (the draft removed the notification together with `elicitationId` on URL-mode elicitation). On connections negotiated at 2026-07-28, sending it — including via `Server.createElicitationCompletionNotifier()` — now fails locally with `SdkErrorCode.MethodNotSupportedByProtocolVersion`, and inbound copies are dropped as unknown notifications. Both remain fully supported on 2025-11-25.
- `notifications/cancelled` on 2026-era connections now parses with a revision-exact schema that requires `requestId` (the draft made it required); the notification `_meta` shape types the `io.modelcontextprotocol/subscriptionId` key. 2025-era parsing is unchanged.
- The error code `-32001` emitted for HTTP header/body mismatches is now defined by the draft schema (`HEADER_MISMATCH`); the emitted behavior is unchanged (documentation only).

No public API surface changes; the regenerated reference artifacts are internal/test-only.
5 changes: 3 additions & 2 deletions packages/core/src/shared/inboundClassification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ export type InboundClassificationOutcome = InboundLegacyRoute | InboundModernRou
* with the body's classification), and the `Mcp-Method` header disagreeing
* with the body method.
*
* `-32001` is the SEP-2243 `HeaderMismatch` code, as asserted by the published
* conformance suite for header-validation failures. It has no
* `-32001` is the draft schema's `HEADER_MISMATCH` constant (the SEP-2243
* `HeaderMismatch` code; the spec requires HTTP 400 for it), as also asserted
* by the published conformance suite for header-validation failures. It has no
* {@linkcode ProtocolErrorCode} member because it is not part of the 2025-era
* wire vocabulary; the validation ladder is its only emitter.
*/
Expand Down
122 changes: 75 additions & 47 deletions packages/core/src/types/spec.types.2026-07-28.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* Source: https://github.com/modelcontextprotocol/modelcontextprotocol
* Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/draft/schema.ts
* Last updated from commit: 77cb26481e439d3437bc2bd6ccd19fcae86bb1ec
* Last updated from commit: 91b403f8d8e7bb545b51bf45b1e26c6c889cc328
*
* DO NOT EDIT THIS FILE MANUALLY. Changes will be overwritten by automated updates.
* To update this file, run: pnpm run fetch:spec-types 2026-07-28
Expand Down Expand Up @@ -110,6 +110,29 @@ export interface RequestMetaObject extends MetaObject {
'io.modelcontextprotocol/logLevel'?: LoggingLevel;
}

/**
* Extends {@link MetaObject} with additional notification-specific fields. All key naming rules from `MetaObject` apply.
*
* @see {@link MetaObject} for key naming rules and reserved prefixes.
* @see [General fields: `_meta`](/specification/draft/basic/index#meta) for more details.
* @category Common Types
*/
export interface NotificationMetaObject extends MetaObject {
/**
* Identifies the subscription stream a notification was delivered on. The
* server MUST include this key on every notification delivered via a
* {@link SubscriptionsListenRequest | subscriptions/listen} stream, so the
* client can correlate the notification with the originating subscription.
* The key is absent on notifications not delivered via a subscription
* stream (e.g. progress notifications for an in-flight request), which is
* why it is optional here.
*
* The value is the JSON-RPC ID of the `subscriptions/listen` request that
* opened the stream.
*/
'io.modelcontextprotocol/subscriptionId'?: RequestId;
}

/**
* A progress token, used to associate progress notifications with the original request.
*
Expand Down Expand Up @@ -147,7 +170,7 @@ export interface Request {
* @category Common Types
*/
export interface NotificationParams {
_meta?: MetaObject;
_meta?: NotificationMetaObject;
}

/** @internal */
Expand Down Expand Up @@ -357,6 +380,15 @@ export interface InternalError extends Error {
code: typeof INTERNAL_ERROR;
}

/**
* Error code returned when the HTTP headers of a request do not match the
* corresponding values in the request body, or required headers are
* missing or malformed.
*
* @category Errors
*/
export const HEADER_MISMATCH = -32001;

/**
* Error code returned when a server requires a client capability that was
* not declared in the request's `clientCapabilities`.
Expand All @@ -373,6 +405,23 @@ export const MISSING_REQUIRED_CLIENT_CAPABILITY = -32003;
*/
export const UNSUPPORTED_PROTOCOL_VERSION = -32004;

/**
* Returned when a server rejects a request because the values in the HTTP
* headers do not match the corresponding values in the request body, or
* because required headers are missing or malformed. For HTTP, the response
* status code MUST be `400 Bad Request`.
*
* @example Header mismatch
* {@includeCode ./examples/HeaderMismatchError/header-mismatch.json}
*
* @category Errors
*/
export interface HeaderMismatchError extends Omit<JSONRPCErrorResponse, 'error'> {
error: Error & {
code: typeof HEADER_MISMATCH;
};
}

/**
* Returned when the request's protocol version is unknown to the server or
* unsupported (e.g., a known experimental or draft version the server has
Expand Down Expand Up @@ -517,9 +566,9 @@ export interface CancelledNotificationParams extends NotificationParams {
/**
* The ID of the request to cancel.
*
* This MUST correspond to the ID of a request previously issued in the same direction.
* This MUST correspond to the ID of a request the client previously issued.
*/
requestId?: RequestId;
requestId: RequestId;

/**
* An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
Expand All @@ -528,7 +577,9 @@ export interface CancelledNotificationParams extends NotificationParams {
}

/**
* This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
* This notification is sent by the client to indicate that it is cancelling a request it previously issued.
*
* On stdio, the server also sends this notification, solely to terminate a {@link SubscriptionsListenRequest | subscriptions/listen} stream: it references the ID of the `subscriptions/listen` request that opened the stream. Servers MUST NOT use this notification to cancel any other request.
*
* The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
*
Expand Down Expand Up @@ -995,11 +1046,13 @@ export interface CacheableResult extends Result {
* Indicates the intended scope of the cached response, analogous to HTTP
* `Cache-Control: public` vs `Cache-Control: private`.
*
* - `"public"`: Any client or intermediary (e.g., shared gateway, proxy)
* MAY cache the response and serve it to any user.
* - `"private"`: Only the requesting user's client MAY cache the response.
* Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached
* copy to a different user.
* - `"public"`: The response does not contain user-specific data. Any
* client or intermediary (e.g., shared gateway, caching proxy) MAY cache
* the response and serve it across authorization contexts.
* - `"private"`: The response MAY be cached and reused only within the
* same authorization context. Caches MUST NOT be shared across
* authorization contexts (e.g., a different access token requires a
* different cache).
*
*/
cacheScope: 'public' | 'private';
Expand Down Expand Up @@ -1140,7 +1193,7 @@ export interface ReadResourceResultResponse extends JSONRPCResultResponse {
}

/**
* An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
* An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This is only delivered on a {@link SubscriptionsListenRequest | subscriptions/listen} stream when the client requested it via the `resourcesListChanged` filter field.
*
* @example Resources list changed
* {@includeCode ./examples/ResourceListChangedNotification/resources-list-changed.json}
Expand Down Expand Up @@ -1584,7 +1637,7 @@ export interface EmbeddedResource {
_meta?: MetaObject;
}
/**
* An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
* An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This is only delivered on a {@link SubscriptionsListenRequest | subscriptions/listen} stream when the client requested it via the `promptsListChanged` filter field.
*
* @example Prompts list changed
* {@includeCode ./examples/PromptListChangedNotification/prompts-list-changed.json}
Expand Down Expand Up @@ -1726,7 +1779,7 @@ export interface CallToolRequest extends JSONRPCRequest {
}

/**
* An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
* An optional notification from the server to the client, informing it that the list of tools it offers has changed. This is only delivered on a {@link SubscriptionsListenRequest | subscriptions/listen} stream when the client requested it via the `toolsListChanged` filter field.
*
* @example Tools list changed
* {@includeCode ./examples/ToolListChangedNotification/tools-list-changed.json}
Expand Down Expand Up @@ -1828,6 +1881,11 @@ export interface Tool extends BaseMetadata, Icons {
* (`if`/`then`/`else`), reference keywords (`$ref`, `$defs`, `$anchor`), and any other
* standard validation or annotation keywords.
*
* Property schemas may carry an `x-mcp-header` annotation to mirror the
* argument value into an HTTP header on the Streamable HTTP transport. See
* the Streamable HTTP transport specification for the validity and
* extraction rules.
*
* Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided.
*/
inputSchema: { $schema?: string; type: 'object'; [key: string]: unknown };
Expand Down Expand Up @@ -2539,7 +2597,9 @@ export interface PromptReference extends BaseMetadata {
*/
export interface ListRootsRequest {
method: 'roots/list';
params?: RequestParams;
params?: {
_meta?: MetaObject;
};
}

/**
Expand Down Expand Up @@ -2649,12 +2709,6 @@ export interface ElicitRequestURLParams {
*/
message: string;

/**
* The ID of the elicitation, which must be unique within the context of the server.
* The client MUST treat this ID as an opaque value.
*/
elicitationId: string;

/**
* The URL that the user should navigate to.
*
Expand Down Expand Up @@ -2969,31 +3023,6 @@ export interface ElicitResult {
content?: { [key: string]: string | number | boolean | string[] };
}

/**
* Parameters for a {@link ElicitationCompleteNotification | notifications/elicitation/complete} notification.
*
* @category `notifications/elicitation/complete`
*/
export interface ElicitationCompleteNotificationParams extends NotificationParams {
/**
* The ID of the elicitation that completed.
*/
elicitationId: string;
}

/**
* An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request.
*
* @example Elicitation complete
* {@includeCode ./examples/ElicitationCompleteNotification/elicitation-complete.json}
*
* @category `notifications/elicitation/complete`
*/
export interface ElicitationCompleteNotification extends JSONRPCNotification {
method: 'notifications/elicitation/complete';
params: ElicitationCompleteNotificationParams;
}

/* Client messages */
/** @internal */
export type ClientRequest =
Expand All @@ -3009,7 +3038,7 @@ export type ClientRequest =
| ListToolsRequest;

/** @internal */
export type ClientNotification = CancelledNotification | ProgressNotification;
export type ClientNotification = CancelledNotification;

/** @internal */
export type ClientResult = EmptyResult;
Expand All @@ -3025,7 +3054,6 @@ export type ServerNotification =
| ResourceListChangedNotification
| ToolListChangedNotification
| PromptListChangedNotification
| ElicitationCompleteNotification
| SubscriptionsAcknowledgedNotification;

/** @internal */
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/wire/rev2026-07-28/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
* Registry membership IS the deletion story: there are NO entries for
* `initialize`, `notifications/initialized`, `ping`, `logging/setLevel`,
* `resources/subscribe`, `resources/unsubscribe`,
* `notifications/roots/list_changed`, the task family, or the server→client
* wire-request channel — so an era-mismatched method falls to −32601 by
* absence inbound and a typed local error outbound, with no table to forget.
* `notifications/roots/list_changed`, `notifications/elicitation/complete`
* (removed from the draft schema; 2025-11-25-only vocabulary), the task
* family, or the server→client wire-request channel — so an era-mismatched
* method falls to −32601 by absence inbound and a typed local error outbound,
* with no table to forget.
*
* HAND-REGISTRY SEED DECISIONS (pinned by the CI registry-diff oracle, which
* fails LOUD if this list and the anchor diff ever disagree):
Expand Down
63 changes: 53 additions & 10 deletions packages/core/src/wire/rev2026-07-28/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ import {
AudioContentSchema,
BaseMetadataSchema,
BlobResourceContentsSchema,
CancelledNotificationSchema,
ClientCapabilitiesSchema,
ContentBlockSchema,
CursorSchema,
ElicitationCompleteNotificationSchema,
IconsSchema,
ImageContentSchema,
ImplementationSchema,
Expand All @@ -41,6 +39,7 @@ import {
PromptMessageSchema,
PromptReferenceSchema,
PromptSchema,
RequestIdSchema,
ResourceContentsSchema,
ResourceListChangedNotificationSchema,
ResourceSchema,
Expand Down Expand Up @@ -434,11 +433,57 @@ export const dispatchResultSchemas: { readonly [M in Rev2026RequestMethod]: z.Zo
/* ------------------------------------------------------------------------ *
* Notifications. The 2026 notification set: cancelled, progress, message,
* resources/updated, resources/list_changed, tools/list_changed,
* prompts/list_changed, elicitation/complete. Deleted: initialized,
* roots/list_changed, tasks/status. The shapes are revision-identical to the
* shared schemas, which are composed by reference. (The 2026-only
* subscriptions/acknowledged notification is #14 scope — see registry.ts.)
* prompts/list_changed. Deleted: initialized, roots/list_changed,
* tasks/status, elicitation/complete (removed from the draft together with
* URL-elicitation's elicitationId — both remain 2025-11-25 vocabulary only).
* The shapes are revision-identical to the shared schemas, which are
* composed by reference, EXCEPT cancelled, which forks below: this revision
* requires `requestId`. (The 2026-only subscriptions/acknowledged
* notification is #14 scope — see registry.ts.)
* ------------------------------------------------------------------------ */

/**
* Notification `_meta` (anchor `NotificationMetaObject`): loose, with the
* subscriptions/listen demux key typed when present. Only the anchor-exact
* SHAPE is modeled here — listen delivery itself (filter gating, demux,
* teardown) is #14 scope and not implemented by this module.
*/
export const NotificationMetaSchema = z.looseObject({
/**
* The JSON-RPC ID of the `subscriptions/listen` request that opened the
* stream a notification was delivered on; absent on notifications not
* delivered via a subscription stream.
*/
'io.modelcontextprotocol/subscriptionId': RequestIdSchema.optional()
});

/**
* 2026-era `notifications/cancelled` params (anchor-exact fork): `requestId`
* is REQUIRED on this revision — the shared schema keeps it optional because
* the frozen 2025-11-25 shape declares it optional (task cancellation goes
* through `tasks/cancel` there). Requiredness is bare because no 2025-era
* traffic touches this module.
*/
export const CancelledNotificationParamsSchema = z.object({
_meta: NotificationMetaSchema.optional(),
/**
* The ID of the request to cancel. This MUST correspond to the ID of a
* request the client previously issued.
*/
requestId: RequestIdSchema,
/**
* An optional string describing the reason for the cancellation. This MAY
* be logged or presented to the user.
*/
reason: z.string().optional()
});

/** 2026-era `notifications/cancelled` (see the params fork above). */
export const CancelledNotificationSchema = z.object({
method: z.literal('notifications/cancelled'),
params: CancelledNotificationParamsSchema
});

/** The 2026-era notification-method set (the hand-registry seed; see the deletion list above). */
export type Rev2026NotificationMethod =
| 'notifications/cancelled'
Expand All @@ -447,8 +492,7 @@ export type Rev2026NotificationMethod =
| 'notifications/resources/updated'
| 'notifications/resources/list_changed'
| 'notifications/tools/list_changed'
| 'notifications/prompts/list_changed'
| 'notifications/elicitation/complete';
| 'notifications/prompts/list_changed';

export const notificationSchemas2026: { readonly [M in Rev2026NotificationMethod]: z.ZodType<{ method: M }> } = {
'notifications/cancelled': CancelledNotificationSchema,
Expand All @@ -457,8 +501,7 @@ export const notificationSchemas2026: { readonly [M in Rev2026NotificationMethod
'notifications/resources/updated': ResourceUpdatedNotificationSchema,
'notifications/resources/list_changed': ResourceListChangedNotificationSchema,
'notifications/tools/list_changed': ToolListChangedNotificationSchema,
'notifications/prompts/list_changed': PromptListChangedNotificationSchema,
'notifications/elicitation/complete': ElicitationCompleteNotificationSchema
'notifications/prompts/list_changed': PromptListChangedNotificationSchema
};

/* ------------------------------------------------------------------------ *
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"mode": "url",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://mcp.example.com/ui/set_api_key",
"message": "Please provide your API key to continue."
}

This file was deleted.

Loading
Loading