feat(core): per-revision spec reference types and the 2026-07-28 wire contract surface (#2252)
This commit is contained in:
parent
ab552c30d5
commit
8d55531dab
20 changed files with 4146 additions and 1005 deletions
6
.changeset/spec-reference-types-2026-07-28.md
Normal file
6
.changeset/spec-reference-types-2026-07-28.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@modelcontextprotocol/core': patch
|
||||
'@modelcontextprotocol/codemod': patch
|
||||
---
|
||||
|
||||
Add per-revision spec reference types (2025-11-25 and 2026-07-28) with split comparison tests, and the 2026-07-28 wire contract surface: request-meta key constants, `RequestMetaEnvelopeSchema`, `server/discover` shapes, the typed `-32004` error, the `-32003` code constant, and a `resultType` passthrough on the base result. Types and constants only — no behavior changes.
|
||||
14
.github/workflows/update-spec-types.yml
vendored
14
.github/workflows/update-spec-types.yml
vendored
|
|
@ -34,16 +34,16 @@ jobs:
|
|||
run: pnpm install
|
||||
|
||||
- name: Fetch latest spec types
|
||||
run: pnpm run fetch:spec-types
|
||||
run: pnpm run fetch:spec-types 2026-07-28
|
||||
|
||||
- name: Check for changes
|
||||
id: check_changes
|
||||
run: |
|
||||
if git diff --quiet packages/core/src/types/spec.types.ts; then
|
||||
if git diff --quiet packages/core/src/types/spec.types.2026-07-28.ts; then
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
LATEST_SHA=$(grep "Last updated from commit:" packages/core/src/types/spec.types.ts | cut -d: -f2 | tr -d ' ')
|
||||
LATEST_SHA=$(grep "Last updated from commit:" packages/core/src/types/spec.types.2026-07-28.ts | cut -d: -f2 | tr -d ' ')
|
||||
echo "sha=$LATEST_SHA" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
|
|
@ -59,12 +59,12 @@ jobs:
|
|||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
git checkout -B update-spec-types
|
||||
git add packages/core/src/types/spec.types.ts
|
||||
git commit -m "chore: update spec.types.ts from upstream"
|
||||
git add packages/core/src/types/spec.types.2026-07-28.ts
|
||||
git commit -m "chore: update spec.types.2026-07-28.ts from upstream"
|
||||
git push -f --no-verify origin update-spec-types
|
||||
|
||||
# Create PR if it doesn't exist, or update if it does
|
||||
PR_BODY="This PR updates \`packages/core/src/types/spec.types.ts\` from the Model Context Protocol specification.
|
||||
PR_BODY="This PR updates \`packages/core/src/types/spec.types.2026-07-28.ts\` from the Model Context Protocol specification.
|
||||
|
||||
Source file: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/${{ steps.check_changes.outputs.sha }}/schema/draft/schema.ts
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ jobs:
|
|||
gh pr edit "$EXISTING_PR" --body "$PR_BODY"
|
||||
else
|
||||
gh pr create \
|
||||
--title "chore: update spec.types.ts from upstream" \
|
||||
--title "chore: update spec.types.2026-07-28.ts from upstream" \
|
||||
--body "$PR_BODY" \
|
||||
--base main \
|
||||
--head update-spec-types
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ node_modules
|
|||
pnpm-lock.yaml
|
||||
|
||||
# Ignore generated files
|
||||
src/spec.types.ts
|
||||
**/src/types/spec.types.2025-11-25.ts
|
||||
**/src/types/spec.types.2026-07-28.ts
|
||||
|
||||
# Batch test cloned repos and results
|
||||
packages/codemod/batch-test/repos
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ When verifying spec compliance, consult the spec directly rather than relying on
|
|||
|
||||
### Schema Compliance
|
||||
|
||||
- When editing Zod protocol schemas in `schemas.ts`, verify unknown-key handling matches the spec `schema.ts`: if the spec type has no `additionalProperties: false`, the SDK schema must use `z.looseObject()` / `.catchall(z.unknown())` rather than implicit strict — over-strict Zod (incl. `z.literal('object')` on `type`) rejects spec-valid payloads from other SDKs. Also confirm `spec.types.test.ts` still passes bidirectionally. (#1768, #1849, #1169)
|
||||
- When editing Zod protocol schemas in `schemas.ts`, verify unknown-key handling matches the spec `schema.ts`: if the spec type has no `additionalProperties: false`, the SDK schema must use `z.looseObject()` / `.catchall(z.unknown())` rather than implicit strict — over-strict Zod (incl. `z.literal('object')` on `type`) rejects spec-valid payloads from other SDKs. Also confirm the `spec.types.*.test.ts` comparisons still pass bidirectionally. (#1768, #1849, #1169)
|
||||
|
||||
### Async / Lifecycle
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export default defineConfig(
|
|||
},
|
||||
{
|
||||
// Ignore generated protocol types everywhere
|
||||
ignores: ['**/spec.types.ts']
|
||||
ignores: ['**/spec.types.2025-11-25.ts', '**/spec.types.2026-07-28.ts']
|
||||
},
|
||||
{
|
||||
files: ['packages/client/**/*.ts', 'packages/server/**/*.ts'],
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
|
|||
'CreateMessageResultWithToolsSchema',
|
||||
'CreateTaskResultSchema',
|
||||
'CursorSchema',
|
||||
'DiscoverRequestSchema',
|
||||
'DiscoverResultSchema',
|
||||
'ElicitRequestFormParamsSchema',
|
||||
'ElicitRequestParamsSchema',
|
||||
'ElicitRequestSchema',
|
||||
|
|
@ -112,6 +114,7 @@ export const SPEC_SCHEMA_NAMES: ReadonlySet<string> = new Set([
|
|||
'ReadResourceResultSchema',
|
||||
'RelatedTaskMetadataSchema',
|
||||
'RequestIdSchema',
|
||||
'RequestMetaEnvelopeSchema',
|
||||
'RequestMetaSchema',
|
||||
'RequestSchema',
|
||||
'ResourceContentsSchema',
|
||||
|
|
|
|||
|
|
@ -71,14 +71,18 @@ export * from '../../types/types.js';
|
|||
|
||||
// Constants
|
||||
export {
|
||||
CLIENT_CAPABILITIES_META_KEY,
|
||||
CLIENT_INFO_META_KEY,
|
||||
DEFAULT_NEGOTIATED_PROTOCOL_VERSION,
|
||||
INTERNAL_ERROR,
|
||||
INVALID_PARAMS,
|
||||
INVALID_REQUEST,
|
||||
JSONRPC_VERSION,
|
||||
LATEST_PROTOCOL_VERSION,
|
||||
LOG_LEVEL_META_KEY,
|
||||
METHOD_NOT_FOUND,
|
||||
PARSE_ERROR,
|
||||
PROTOCOL_VERSION_META_KEY,
|
||||
RELATED_TASK_META_KEY,
|
||||
SUPPORTED_PROTOCOL_VERSIONS
|
||||
} from '../../types/constants.js';
|
||||
|
|
@ -87,7 +91,7 @@ export {
|
|||
export { ProtocolErrorCode } from '../../types/enums.js';
|
||||
|
||||
// Error classes
|
||||
export { ProtocolError, UrlElicitationRequiredError } from '../../types/errors.js';
|
||||
export { ProtocolError, UnsupportedProtocolVersionError, UrlElicitationRequiredError } from '../../types/errors.js';
|
||||
|
||||
// Type guards and message parsing
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,39 @@ export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, '2025-06-18
|
|||
|
||||
export const RELATED_TASK_META_KEY = 'io.modelcontextprotocol/related-task';
|
||||
|
||||
/* Reserved `_meta` keys for the per-request envelope (protocol revision 2026-07-28) */
|
||||
|
||||
/**
|
||||
* `_meta` key carrying the MCP protocol version governing a request.
|
||||
*
|
||||
* For the HTTP transport, the value must match the `MCP-Protocol-Version` header.
|
||||
*/
|
||||
export const PROTOCOL_VERSION_META_KEY = 'io.modelcontextprotocol/protocolVersion';
|
||||
|
||||
/**
|
||||
* `_meta` key identifying the client software making a request.
|
||||
*/
|
||||
export const CLIENT_INFO_META_KEY = 'io.modelcontextprotocol/clientInfo';
|
||||
|
||||
/**
|
||||
* `_meta` key carrying the client's capabilities for a request.
|
||||
*
|
||||
* Capabilities are declared per request rather than once at initialization;
|
||||
* servers must not infer capabilities from prior requests.
|
||||
*/
|
||||
export const CLIENT_CAPABILITIES_META_KEY = 'io.modelcontextprotocol/clientCapabilities';
|
||||
|
||||
/**
|
||||
* `_meta` key carrying the desired log level for a request.
|
||||
*
|
||||
* When absent, the server must not send `notifications/message` notifications
|
||||
* for the request.
|
||||
*
|
||||
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577); remains
|
||||
* in the specification for at least twelve months.
|
||||
*/
|
||||
export const LOG_LEVEL_META_KEY = 'io.modelcontextprotocol/logLevel';
|
||||
|
||||
/* JSON-RPC types */
|
||||
export const JSONRPC_VERSION = '2.0';
|
||||
|
||||
|
|
|
|||
|
|
@ -12,5 +12,15 @@ export enum ProtocolErrorCode {
|
|||
|
||||
// MCP-specific error codes
|
||||
ResourceNotFound = -32_002,
|
||||
/**
|
||||
* Processing the request requires a capability the client did not declare
|
||||
* in the request's `clientCapabilities` (protocol revision 2026-07-28).
|
||||
*/
|
||||
MissingRequiredClientCapability = -32_003,
|
||||
/**
|
||||
* The request's protocol version is unknown to the server or unsupported
|
||||
* by it (protocol revision 2026-07-28).
|
||||
*/
|
||||
UnsupportedProtocolVersion = -32_004,
|
||||
UrlElicitationRequired = -32_042
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ProtocolErrorCode } from './enums.js';
|
||||
import type { ElicitRequestURLParams } from './types.js';
|
||||
import type { ElicitRequestURLParams, UnsupportedProtocolVersionErrorData } from './types.js';
|
||||
|
||||
/**
|
||||
* Protocol errors are JSON-RPC errors that cross the wire as error responses.
|
||||
|
|
@ -27,6 +27,13 @@ export class ProtocolError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
if (code === ProtocolErrorCode.UnsupportedProtocolVersion && data) {
|
||||
const errorData = data as Partial<UnsupportedProtocolVersionErrorData>;
|
||||
if (Array.isArray(errorData.supported) && typeof errorData.requested === 'string') {
|
||||
return new UnsupportedProtocolVersionError({ supported: errorData.supported, requested: errorData.requested }, message);
|
||||
}
|
||||
}
|
||||
|
||||
// Default to generic ProtocolError
|
||||
return new ProtocolError(code, message, data);
|
||||
}
|
||||
|
|
@ -47,3 +54,32 @@ export class UrlElicitationRequiredError extends ProtocolError {
|
|||
return (this.data as { elicitations: ElicitRequestURLParams[] })?.elicitations ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error type for the `-32004` UnsupportedProtocolVersion protocol error (protocol
|
||||
* revision 2026-07-28): the request's protocol version is unknown to the server or
|
||||
* unsupported by it.
|
||||
*
|
||||
* The error data lists the protocol versions the receiver supports (`supported`),
|
||||
* so the sender can choose a mutually supported version and retry, and echoes the
|
||||
* version that was requested (`requested`).
|
||||
*/
|
||||
export class UnsupportedProtocolVersionError extends ProtocolError {
|
||||
constructor(data: UnsupportedProtocolVersionErrorData, message: string = `Unsupported protocol version: ${data.requested}`) {
|
||||
super(ProtocolErrorCode.UnsupportedProtocolVersion, message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol versions the receiver supports.
|
||||
*/
|
||||
get supported(): string[] {
|
||||
return (this.data as UnsupportedProtocolVersionErrorData).supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* The protocol version that was requested.
|
||||
*/
|
||||
get requested(): string {
|
||||
return (this.data as UnsupportedProtocolVersionErrorData).requested;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
import * as z from 'zod/v4';
|
||||
|
||||
import { JSONRPC_VERSION, RELATED_TASK_META_KEY } from './constants.js';
|
||||
import {
|
||||
CLIENT_CAPABILITIES_META_KEY,
|
||||
CLIENT_INFO_META_KEY,
|
||||
JSONRPC_VERSION,
|
||||
LOG_LEVEL_META_KEY,
|
||||
PROTOCOL_VERSION_META_KEY,
|
||||
RELATED_TASK_META_KEY
|
||||
} from './constants.js';
|
||||
import type {
|
||||
JSONArray,
|
||||
JSONObject,
|
||||
|
|
@ -113,7 +120,14 @@ export const ResultSchema = z.looseObject({
|
|||
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
|
||||
* for notes on `_meta` usage.
|
||||
*/
|
||||
_meta: RequestMetaSchema.optional()
|
||||
_meta: RequestMetaSchema.optional(),
|
||||
/**
|
||||
* Indicates the type of the result, allowing the receiver to determine how to
|
||||
* parse the result object. Servers implementing protocol revision 2026-07-28 or
|
||||
* later always include this field; results from earlier revisions omit it, and
|
||||
* an absent value must be treated as `"complete"`.
|
||||
*/
|
||||
resultType: z.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -552,6 +566,43 @@ export const InitializedNotificationSchema = NotificationSchema.extend({
|
|||
params: NotificationsParamsSchema.optional()
|
||||
});
|
||||
|
||||
/* Discovery */
|
||||
/**
|
||||
* A request from the client asking the server to advertise its supported protocol
|
||||
* versions, capabilities, and other metadata (protocol revision 2026-07-28). Servers
|
||||
* MUST implement `server/discover`. Clients MAY call it but are not required to —
|
||||
* version negotiation can also happen inline via the per-request `_meta` envelope.
|
||||
*/
|
||||
export const DiscoverRequestSchema = RequestSchema.extend({
|
||||
method: z.literal('server/discover'),
|
||||
params: BaseRequestParamsSchema.optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* The result returned by the server for a `server/discover` request.
|
||||
*/
|
||||
export const DiscoverResultSchema = ResultSchema.extend({
|
||||
/**
|
||||
* MCP protocol versions this server supports. The client should choose a
|
||||
* version from this list for use in subsequent requests.
|
||||
*/
|
||||
supportedVersions: z.array(z.string()),
|
||||
/**
|
||||
* The capabilities of the server.
|
||||
*/
|
||||
capabilities: ServerCapabilitiesSchema,
|
||||
/**
|
||||
* Information about the server software implementation.
|
||||
*/
|
||||
serverInfo: ImplementationSchema,
|
||||
/**
|
||||
* Instructions describing how to use the server and its features.
|
||||
*
|
||||
* This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt.
|
||||
*/
|
||||
instructions: z.string().optional()
|
||||
});
|
||||
|
||||
/* Ping */
|
||||
/**
|
||||
* A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
|
||||
|
|
@ -1509,6 +1560,48 @@ export const LoggingMessageNotificationSchema = NotificationSchema.extend({
|
|||
params: LoggingMessageNotificationParamsSchema
|
||||
});
|
||||
|
||||
/* Per-request `_meta` envelope */
|
||||
/**
|
||||
* The per-request `_meta` envelope carried by every request under protocol revision
|
||||
* 2026-07-28: the protocol version governing the request, the client implementation
|
||||
* info, and the client's capabilities — declared per request rather than once at
|
||||
* initialization — plus the optional log-level opt-in.
|
||||
*
|
||||
* This schema models the complete envelope on its own. The base request schemas
|
||||
* ({@linkcode RequestMetaSchema}) deliberately stay lenient so the same wire schemas
|
||||
* parse requests from earlier protocol revisions (no envelope) as well; envelope
|
||||
* requiredness is enforced per request at dispatch time, not here.
|
||||
*/
|
||||
export const RequestMetaEnvelopeSchema = z.looseObject({
|
||||
/**
|
||||
* If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
|
||||
*/
|
||||
progressToken: ProgressTokenSchema.optional(),
|
||||
/**
|
||||
* The MCP protocol version being used for this request. For the HTTP transport,
|
||||
* the value must match the `MCP-Protocol-Version` header.
|
||||
*/
|
||||
[PROTOCOL_VERSION_META_KEY]: z.string(),
|
||||
/**
|
||||
* Identifies the client software making the request.
|
||||
*/
|
||||
[CLIENT_INFO_META_KEY]: ImplementationSchema,
|
||||
/**
|
||||
* The client's capabilities for this specific request. An empty object means the
|
||||
* client supports no optional capabilities. Servers must not infer capabilities
|
||||
* from prior requests.
|
||||
*/
|
||||
[CLIENT_CAPABILITIES_META_KEY]: ClientCapabilitiesSchema,
|
||||
/**
|
||||
* The desired log level for this request. When absent, the server must not send
|
||||
* `notifications/message` notifications for the request.
|
||||
*
|
||||
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577); remains
|
||||
* in the specification for at least twelve months.
|
||||
*/
|
||||
[LOG_LEVEL_META_KEY]: LoggingLevelSchema.optional()
|
||||
});
|
||||
|
||||
/* Sampling */
|
||||
/**
|
||||
* Hints to use for model selection.
|
||||
|
|
|
|||
2559
packages/core/src/types/spec.types.2025-11-25.ts
Normal file
2559
packages/core/src/types/spec.types.2025-11-25.ts
Normal file
File diff suppressed because it is too large
Load diff
3030
packages/core/src/types/spec.types.2026-07-28.ts
Normal file
3030
packages/core/src/types/spec.types.2026-07-28.ts
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -58,6 +58,8 @@ const SPEC_SCHEMA_KEYS = [
|
|||
'CreateMessageResultWithToolsSchema',
|
||||
'CreateTaskResultSchema',
|
||||
'CursorSchema',
|
||||
'DiscoverRequestSchema',
|
||||
'DiscoverResultSchema',
|
||||
'ElicitationCompleteNotificationSchema',
|
||||
'ElicitationCompleteNotificationParamsSchema',
|
||||
'ElicitRequestSchema',
|
||||
|
|
@ -133,6 +135,7 @@ const SPEC_SCHEMA_KEYS = [
|
|||
'RelatedTaskMetadataSchema',
|
||||
'RequestSchema',
|
||||
'RequestIdSchema',
|
||||
'RequestMetaEnvelopeSchema',
|
||||
'RequestMetaSchema',
|
||||
'ResourceSchema',
|
||||
'ResourceContentsSchema',
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ import type {
|
|||
CreateMessageResultWithToolsSchema,
|
||||
CreateTaskResultSchema,
|
||||
CursorSchema,
|
||||
DiscoverRequestSchema,
|
||||
DiscoverResultSchema,
|
||||
ElicitationCompleteNotificationParamsSchema,
|
||||
ElicitationCompleteNotificationSchema,
|
||||
ElicitRequestFormParamsSchema,
|
||||
|
|
@ -106,6 +108,7 @@ import type {
|
|||
ReadResourceResultSchema,
|
||||
RelatedTaskMetadataSchema,
|
||||
RequestIdSchema,
|
||||
RequestMetaEnvelopeSchema,
|
||||
RequestMetaSchema,
|
||||
RequestSchema,
|
||||
ResourceContentsSchema,
|
||||
|
|
@ -200,6 +203,11 @@ export type JSONRPCResultResponse = Infer<typeof JSONRPCResultResponseSchema>;
|
|||
export type JSONRPCMessage = Infer<typeof JSONRPCMessageSchema>;
|
||||
export type RequestParams = Infer<typeof BaseRequestParamsSchema>;
|
||||
export type NotificationParams = Infer<typeof NotificationsParamsSchema>;
|
||||
/**
|
||||
* The per-request `_meta` envelope carried by every request under protocol revision
|
||||
* 2026-07-28 (protocol version, client info, client capabilities, optional log level).
|
||||
*/
|
||||
export type RequestMetaEnvelope = Infer<typeof RequestMetaEnvelopeSchema>;
|
||||
|
||||
/* Empty result */
|
||||
export type EmptyResult = Infer<typeof EmptyResultSchema>;
|
||||
|
|
@ -224,6 +232,10 @@ export type ServerCapabilities = Infer<typeof ServerCapabilitiesSchema>;
|
|||
export type InitializeResult = Infer<typeof InitializeResultSchema>;
|
||||
export type InitializedNotification = Infer<typeof InitializedNotificationSchema>;
|
||||
|
||||
/* Discovery */
|
||||
export type DiscoverRequest = Infer<typeof DiscoverRequestSchema>;
|
||||
export type DiscoverResult = Infer<typeof DiscoverResultSchema>;
|
||||
|
||||
/* Ping */
|
||||
export type PingRequest = Infer<typeof PingRequestSchema>;
|
||||
|
||||
|
|
@ -458,6 +470,22 @@ export interface InternalError extends JSONRPCErrorObject {
|
|||
code: typeof INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data carried by a `-32004` UnsupportedProtocolVersion protocol error
|
||||
* (protocol revision 2026-07-28).
|
||||
*/
|
||||
export interface UnsupportedProtocolVersionErrorData {
|
||||
/**
|
||||
* Protocol versions the receiver supports. The sender should choose a
|
||||
* mutually supported version from this list and retry.
|
||||
*/
|
||||
supported: string[];
|
||||
/**
|
||||
* The protocol version that was requested.
|
||||
*/
|
||||
requested: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback type for list changed notifications.
|
||||
*/
|
||||
|
|
|
|||
950
packages/core/test/spec.types.2025-11-25.test.ts
Normal file
950
packages/core/test/spec.types.2025-11-25.test.ts
Normal file
|
|
@ -0,0 +1,950 @@
|
|||
/**
|
||||
* Compares the SDK's types against the frozen 2025-11-25 release schema
|
||||
* (spec.types.2025-11-25.ts). The 2026-07-28 comparison lives in
|
||||
* spec.types.2026-07-28.test.ts.
|
||||
*
|
||||
* This contains:
|
||||
* - Static type checks to verify the Spec's types are compatible with the SDK's types
|
||||
* (mutually assignable — no type-level workarounds should be needed)
|
||||
* - Runtime checks to verify each Spec type has a static check
|
||||
* (note: a few don't have SDK types, see MISSING_SDK_TYPES below)
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import type * as SpecTypes from '../src/types/spec.types.2025-11-25.js';
|
||||
import type * as SDKTypes from '../src/types/index.js';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
||||
// Adds the `jsonrpc` property to a type, to match the on-wire format of notifications.
|
||||
type WithJSONRPC<T> = T & { jsonrpc: '2.0' };
|
||||
|
||||
// Adds the `jsonrpc` and `id` properties to a type, to match the on-wire format of requests.
|
||||
type WithJSONRPCRequest<T> = T & { jsonrpc: '2.0'; id: SDKTypes.RequestId };
|
||||
|
||||
const sdkTypeChecks = {
|
||||
RequestParams: (sdk: SDKTypes.RequestParams, spec: SpecTypes.RequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
NotificationParams: (sdk: SDKTypes.NotificationParams, spec: SpecTypes.NotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelledNotificationParams: (sdk: SDKTypes.CancelledNotificationParams, spec: SpecTypes.CancelledNotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InitializeRequestParams: (sdk: SDKTypes.InitializeRequestParams, spec: SpecTypes.InitializeRequestParams) => {
|
||||
// @ts-expect-error 2025-11-25 types capabilities.experimental values as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressNotificationParams: (sdk: SDKTypes.ProgressNotificationParams, spec: SpecTypes.ProgressNotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceRequestParams: (sdk: SDKTypes.ResourceRequestParams, spec: SpecTypes.ResourceRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ReadResourceRequestParams: (sdk: SDKTypes.ReadResourceRequestParams, spec: SpecTypes.ReadResourceRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SubscribeRequestParams: (sdk: SDKTypes.SubscribeRequestParams, spec: SpecTypes.SubscribeRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UnsubscribeRequestParams: (sdk: SDKTypes.UnsubscribeRequestParams, spec: SpecTypes.UnsubscribeRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceUpdatedNotificationParams: (
|
||||
sdk: SDKTypes.ResourceUpdatedNotificationParams,
|
||||
spec: SpecTypes.ResourceUpdatedNotificationParams
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetPromptRequestParams: (sdk: SDKTypes.GetPromptRequestParams, spec: SpecTypes.GetPromptRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CallToolRequestParams: (sdk: SDKTypes.CallToolRequestParams, spec: SpecTypes.CallToolRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SetLevelRequestParams: (sdk: SDKTypes.SetLevelRequestParams, spec: SpecTypes.SetLevelRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingMessageNotificationParams: (
|
||||
sdk: SDKTypes.LoggingMessageNotificationParams,
|
||||
spec: SpecTypes.LoggingMessageNotificationParams
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CreateMessageRequestParams: (sdk: SDKTypes.CreateMessageRequestParams, spec: SpecTypes.CreateMessageRequestParams) => {
|
||||
// @ts-expect-error 2025-11-25 types `metadata` as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
// @ts-expect-error the SDK's JSONValue-typed tool inputSchema properties are not assignable to 2025-11-25's `object`
|
||||
spec = sdk;
|
||||
},
|
||||
CompleteRequestParams: (sdk: SDKTypes.CompleteRequestParams, spec: SpecTypes.CompleteRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestParams: (sdk: SDKTypes.ElicitRequestParams, spec: SpecTypes.ElicitRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestFormParams: (sdk: SDKTypes.ElicitRequestFormParams, spec: SpecTypes.ElicitRequestFormParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestURLParams: (sdk: SDKTypes.ElicitRequestURLParams, spec: SpecTypes.ElicitRequestURLParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitationCompleteNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.ElicitationCompleteNotification>,
|
||||
spec: SpecTypes.ElicitationCompleteNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PaginatedRequestParams: (sdk: SDKTypes.PaginatedRequestParams, spec: SpecTypes.PaginatedRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelledNotification: (sdk: WithJSONRPC<SDKTypes.CancelledNotification>, spec: SpecTypes.CancelledNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BaseMetadata: (sdk: SDKTypes.BaseMetadata, spec: SpecTypes.BaseMetadata) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Implementation: (sdk: SDKTypes.Implementation, spec: SpecTypes.Implementation) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressNotification: (sdk: WithJSONRPC<SDKTypes.ProgressNotification>, spec: SpecTypes.ProgressNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SubscribeRequest: (sdk: WithJSONRPCRequest<SDKTypes.SubscribeRequest>, spec: SpecTypes.SubscribeRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UnsubscribeRequest: (sdk: WithJSONRPCRequest<SDKTypes.UnsubscribeRequest>, spec: SpecTypes.UnsubscribeRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PaginatedRequest: (sdk: WithJSONRPCRequest<SDKTypes.PaginatedRequest>, spec: SpecTypes.PaginatedRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PaginatedResult: (sdk: SDKTypes.PaginatedResult, spec: SpecTypes.PaginatedResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListRootsRequest: (sdk: WithJSONRPCRequest<SDKTypes.ListRootsRequest>, spec: SpecTypes.ListRootsRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListRootsResult: (sdk: SDKTypes.ListRootsResult, spec: SpecTypes.ListRootsResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Root: (sdk: SDKTypes.Root, spec: SpecTypes.Root) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequest: (sdk: WithJSONRPCRequest<SDKTypes.ElicitRequest>, spec: SpecTypes.ElicitRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitResult: (sdk: SDKTypes.ElicitResult, spec: SpecTypes.ElicitResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CompleteRequest: (sdk: WithJSONRPCRequest<SDKTypes.CompleteRequest>, spec: SpecTypes.CompleteRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CompleteResult: (sdk: SDKTypes.CompleteResult, spec: SpecTypes.CompleteResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressToken: (sdk: SDKTypes.ProgressToken, spec: SpecTypes.ProgressToken) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Cursor: (sdk: SDKTypes.Cursor, spec: SpecTypes.Cursor) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Request: (sdk: SDKTypes.Request, spec: SpecTypes.Request) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Result: (sdk: SDKTypes.Result, spec: SpecTypes.Result) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
RequestId: (sdk: SDKTypes.RequestId, spec: SpecTypes.RequestId) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCRequest: (sdk: SDKTypes.JSONRPCRequest, spec: SpecTypes.JSONRPCRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCNotification: (sdk: SDKTypes.JSONRPCNotification, spec: SpecTypes.JSONRPCNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCResponse: (sdk: SDKTypes.JSONRPCResponse, spec: SpecTypes.JSONRPCResponse) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
EmptyResult: (sdk: SDKTypes.EmptyResult, spec: SpecTypes.EmptyResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Notification: (sdk: SDKTypes.Notification, spec: SpecTypes.Notification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientResult: (sdk: SDKTypes.ClientResult, spec: SpecTypes.ClientResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientNotification: (sdk: WithJSONRPC<SDKTypes.ClientNotification>, spec: SpecTypes.ClientNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ServerResult: (sdk: SDKTypes.ServerResult, spec: SpecTypes.ServerResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceTemplateReference: (sdk: SDKTypes.ResourceTemplateReference, spec: SpecTypes.ResourceTemplateReference) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptReference: (sdk: SDKTypes.PromptReference, spec: SpecTypes.PromptReference) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolAnnotations: (sdk: SDKTypes.ToolAnnotations, spec: SpecTypes.ToolAnnotations) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Tool: (sdk: SDKTypes.Tool, spec: SpecTypes.Tool) => {
|
||||
// @ts-expect-error 2025-11-25 types inputSchema/outputSchema properties as `object`; the SDK follows the 2026-07-28 schema's JSONValue
|
||||
sdk = spec;
|
||||
// @ts-expect-error the SDK's JSONValue-typed inputSchema/outputSchema properties are not assignable to 2025-11-25's `object`
|
||||
spec = sdk;
|
||||
},
|
||||
ListToolsRequest: (sdk: WithJSONRPCRequest<SDKTypes.ListToolsRequest>, spec: SpecTypes.ListToolsRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListToolsResult: (sdk: SDKTypes.ListToolsResult, spec: SpecTypes.ListToolsResult) => {
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 Tool typing; see the Tool check above
|
||||
sdk = spec;
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 Tool typing; see the Tool check above
|
||||
spec = sdk;
|
||||
},
|
||||
CallToolResult: (sdk: SDKTypes.CallToolResult, spec: SpecTypes.CallToolResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CallToolRequest: (sdk: WithJSONRPCRequest<SDKTypes.CallToolRequest>, spec: SpecTypes.CallToolRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolListChangedNotification: (sdk: WithJSONRPC<SDKTypes.ToolListChangedNotification>, spec: SpecTypes.ToolListChangedNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceListChangedNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.ResourceListChangedNotification>,
|
||||
spec: SpecTypes.ResourceListChangedNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptListChangedNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.PromptListChangedNotification>,
|
||||
spec: SpecTypes.PromptListChangedNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
RootsListChangedNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.RootsListChangedNotification>,
|
||||
spec: SpecTypes.RootsListChangedNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceUpdatedNotification: (sdk: WithJSONRPC<SDKTypes.ResourceUpdatedNotification>, spec: SpecTypes.ResourceUpdatedNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SamplingMessage: (sdk: SDKTypes.SamplingMessage, spec: SpecTypes.SamplingMessage) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CreateMessageResult: (sdk: SDKTypes.CreateMessageResultWithTools, spec: SpecTypes.CreateMessageResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SetLevelRequest: (sdk: WithJSONRPCRequest<SDKTypes.SetLevelRequest>, spec: SpecTypes.SetLevelRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PingRequest: (sdk: WithJSONRPCRequest<SDKTypes.PingRequest>, spec: SpecTypes.PingRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InitializedNotification: (sdk: WithJSONRPC<SDKTypes.InitializedNotification>, spec: SpecTypes.InitializedNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListResourcesRequest: (sdk: WithJSONRPCRequest<SDKTypes.ListResourcesRequest>, spec: SpecTypes.ListResourcesRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListResourcesResult: (sdk: SDKTypes.ListResourcesResult, spec: SpecTypes.ListResourcesResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListResourceTemplatesRequest: (
|
||||
sdk: WithJSONRPCRequest<SDKTypes.ListResourceTemplatesRequest>,
|
||||
spec: SpecTypes.ListResourceTemplatesRequest
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListResourceTemplatesResult: (sdk: SDKTypes.ListResourceTemplatesResult, spec: SpecTypes.ListResourceTemplatesResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ReadResourceRequest: (sdk: WithJSONRPCRequest<SDKTypes.ReadResourceRequest>, spec: SpecTypes.ReadResourceRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ReadResourceResult: (sdk: SDKTypes.ReadResourceResult, spec: SpecTypes.ReadResourceResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceContents: (sdk: SDKTypes.ResourceContents, spec: SpecTypes.ResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TextResourceContents: (sdk: SDKTypes.TextResourceContents, spec: SpecTypes.TextResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BlobResourceContents: (sdk: SDKTypes.BlobResourceContents, spec: SpecTypes.BlobResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Resource: (sdk: SDKTypes.Resource, spec: SpecTypes.Resource) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceTemplate: (sdk: SDKTypes.ResourceTemplateType, spec: SpecTypes.ResourceTemplate) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptArgument: (sdk: SDKTypes.PromptArgument, spec: SpecTypes.PromptArgument) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Prompt: (sdk: SDKTypes.Prompt, spec: SpecTypes.Prompt) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListPromptsRequest: (sdk: WithJSONRPCRequest<SDKTypes.ListPromptsRequest>, spec: SpecTypes.ListPromptsRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListPromptsResult: (sdk: SDKTypes.ListPromptsResult, spec: SpecTypes.ListPromptsResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetPromptRequest: (sdk: WithJSONRPCRequest<SDKTypes.GetPromptRequest>, spec: SpecTypes.GetPromptRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TextContent: (sdk: SDKTypes.TextContent, spec: SpecTypes.TextContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ImageContent: (sdk: SDKTypes.ImageContent, spec: SpecTypes.ImageContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
AudioContent: (sdk: SDKTypes.AudioContent, spec: SpecTypes.AudioContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
EmbeddedResource: (sdk: SDKTypes.EmbeddedResource, spec: SpecTypes.EmbeddedResource) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceLink: (sdk: SDKTypes.ResourceLink, spec: SpecTypes.ResourceLink) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ContentBlock: (sdk: SDKTypes.ContentBlock, spec: SpecTypes.ContentBlock) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptMessage: (sdk: SDKTypes.PromptMessage, spec: SpecTypes.PromptMessage) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetPromptResult: (sdk: SDKTypes.GetPromptResult, spec: SpecTypes.GetPromptResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BooleanSchema: (sdk: SDKTypes.BooleanSchema, spec: SpecTypes.BooleanSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
StringSchema: (sdk: SDKTypes.StringSchema, spec: SpecTypes.StringSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
NumberSchema: (sdk: SDKTypes.NumberSchema, spec: SpecTypes.NumberSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
EnumSchema: (sdk: SDKTypes.EnumSchema, spec: SpecTypes.EnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UntitledSingleSelectEnumSchema: (sdk: SDKTypes.UntitledSingleSelectEnumSchema, spec: SpecTypes.UntitledSingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TitledSingleSelectEnumSchema: (sdk: SDKTypes.TitledSingleSelectEnumSchema, spec: SpecTypes.TitledSingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SingleSelectEnumSchema: (sdk: SDKTypes.SingleSelectEnumSchema, spec: SpecTypes.SingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UntitledMultiSelectEnumSchema: (sdk: SDKTypes.UntitledMultiSelectEnumSchema, spec: SpecTypes.UntitledMultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TitledMultiSelectEnumSchema: (sdk: SDKTypes.TitledMultiSelectEnumSchema, spec: SpecTypes.TitledMultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
MultiSelectEnumSchema: (sdk: SDKTypes.MultiSelectEnumSchema, spec: SpecTypes.MultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LegacyTitledEnumSchema: (sdk: SDKTypes.LegacyTitledEnumSchema, spec: SpecTypes.LegacyTitledEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PrimitiveSchemaDefinition: (sdk: SDKTypes.PrimitiveSchemaDefinition, spec: SpecTypes.PrimitiveSchemaDefinition) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCErrorResponse: (sdk: SDKTypes.JSONRPCErrorResponse, spec: SpecTypes.JSONRPCErrorResponse) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCResultResponse: (sdk: SDKTypes.JSONRPCResultResponse, spec: SpecTypes.JSONRPCResultResponse) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCMessage: (sdk: SDKTypes.JSONRPCMessage, spec: SpecTypes.JSONRPCMessage) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CreateMessageRequest: (sdk: WithJSONRPCRequest<SDKTypes.CreateMessageRequest>, spec: SpecTypes.CreateMessageRequest) => {
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 typing of params metadata/tools; see the CreateMessageRequestParams check above
|
||||
sdk = spec;
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 typing of params metadata/tools; see the CreateMessageRequestParams check above
|
||||
spec = sdk;
|
||||
},
|
||||
InitializeRequest: (sdk: WithJSONRPCRequest<SDKTypes.InitializeRequest>, spec: SpecTypes.InitializeRequest) => {
|
||||
// @ts-expect-error 2025-11-25 types capabilities.experimental values as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InitializeResult: (sdk: SDKTypes.InitializeResult, spec: SpecTypes.InitializeResult) => {
|
||||
// @ts-expect-error 2025-11-25 types capabilities.experimental values as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientCapabilities: (sdk: SDKTypes.ClientCapabilities, spec: SpecTypes.ClientCapabilities) => {
|
||||
// @ts-expect-error 2025-11-25 types experimental/sampling/elicitation/tasks blobs as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ServerCapabilities: (sdk: SDKTypes.ServerCapabilities, spec: SpecTypes.ServerCapabilities) => {
|
||||
// @ts-expect-error 2025-11-25 types experimental/logging/completions/tasks blobs as `object`; the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientRequest: (sdk: WithJSONRPCRequest<SDKTypes.ClientRequest>, spec: SpecTypes.ClientRequest) => {
|
||||
// @ts-expect-error 2025-11-25 types capabilities.experimental values as `object` (via the InitializeRequest member); the SDK follows the 2026-07-28 schema's JSONObject
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ServerRequest: (sdk: WithJSONRPCRequest<SDKTypes.ServerRequest>, spec: SpecTypes.ServerRequest) => {
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 typing of CreateMessageRequest params; see the CreateMessageRequestParams check above
|
||||
sdk = spec;
|
||||
// @ts-expect-error 2025-11-25 vs 2026-07-28 typing of CreateMessageRequest params; see the CreateMessageRequestParams check above
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingMessageNotification: (sdk: WithJSONRPC<SDKTypes.LoggingMessageNotification>, spec: SpecTypes.LoggingMessageNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ServerNotification: (sdk: WithJSONRPC<SDKTypes.ServerNotification>, spec: SpecTypes.ServerNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingLevel: (sdk: SDKTypes.LoggingLevel, spec: SpecTypes.LoggingLevel) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Icon: (sdk: SDKTypes.Icon, spec: SpecTypes.Icon) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Icons: (sdk: SDKTypes.Icons, spec: SpecTypes.Icons) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ModelHint: (sdk: SDKTypes.ModelHint, spec: SpecTypes.ModelHint) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ModelPreferences: (sdk: SDKTypes.ModelPreferences, spec: SpecTypes.ModelPreferences) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolChoice: (sdk: SDKTypes.ToolChoice, spec: SpecTypes.ToolChoice) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolUseContent: (sdk: SDKTypes.ToolUseContent, spec: SpecTypes.ToolUseContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolResultContent: (sdk: SDKTypes.ToolResultContent, spec: SpecTypes.ToolResultContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SamplingMessageContentBlock: (sdk: SDKTypes.SamplingMessageContentBlock, spec: SpecTypes.SamplingMessageContentBlock) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Annotations: (sdk: SDKTypes.Annotations, spec: SpecTypes.Annotations) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Role: (sdk: SDKTypes.Role, spec: SpecTypes.Role) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolExecution: (sdk: SDKTypes.ToolExecution, spec: SpecTypes.ToolExecution) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TaskStatus: (sdk: SDKTypes.TaskStatus, spec: SpecTypes.TaskStatus) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TaskMetadata: (sdk: SDKTypes.TaskMetadata, spec: SpecTypes.TaskMetadata) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
RelatedTaskMetadata: (sdk: SDKTypes.RelatedTaskMetadata, spec: SpecTypes.RelatedTaskMetadata) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TaskAugmentedRequestParams: (sdk: SDKTypes.TaskAugmentedRequestParams, spec: SpecTypes.TaskAugmentedRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Task: (sdk: SDKTypes.Task, spec: SpecTypes.Task) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CreateTaskResult: (sdk: SDKTypes.CreateTaskResult, spec: SpecTypes.CreateTaskResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetTaskRequest: (sdk: WithJSONRPCRequest<SDKTypes.GetTaskRequest>, spec: SpecTypes.GetTaskRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetTaskResult: (sdk: SDKTypes.GetTaskResult, spec: SpecTypes.GetTaskResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetTaskPayloadRequest: (sdk: WithJSONRPCRequest<SDKTypes.GetTaskPayloadRequest>, spec: SpecTypes.GetTaskPayloadRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
GetTaskPayloadResult: (sdk: SDKTypes.GetTaskPayloadResult, spec: SpecTypes.GetTaskPayloadResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListTasksRequest: (sdk: WithJSONRPCRequest<SDKTypes.ListTasksRequest>, spec: SpecTypes.ListTasksRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ListTasksResult: (sdk: SDKTypes.ListTasksResult, spec: SpecTypes.ListTasksResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelTaskRequest: (sdk: WithJSONRPCRequest<SDKTypes.CancelTaskRequest>, spec: SpecTypes.CancelTaskRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelTaskResult: (sdk: SDKTypes.CancelTaskResult, spec: SpecTypes.CancelTaskResult) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TaskStatusNotificationParams: (sdk: SDKTypes.TaskStatusNotificationParams, spec: SpecTypes.TaskStatusNotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TaskStatusNotification: (sdk: WithJSONRPC<SDKTypes.TaskStatusNotification>, spec: SpecTypes.TaskStatusNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Key-level assertions: verify that each SDK type and its corresponding spec
|
||||
// type expose exactly the same set of named property keys. This catches cases
|
||||
// where a Zod schema marks a field as `.optional()` but the spec does not (or
|
||||
// vice-versa), which the mutual-assignability checks above cannot detect
|
||||
// because optional fields satisfy structural subtyping in both directions.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Strip index signatures, keeping only explicitly-named keys. */
|
||||
type KnownKeys<T> = keyof {
|
||||
[K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
|
||||
};
|
||||
|
||||
/**
|
||||
* Assert that A and B have exactly the same set of known (named) keys.
|
||||
* Resolves to `true` on match; a descriptive error type on mismatch.
|
||||
*/
|
||||
type AssertExactKeys<
|
||||
A,
|
||||
B,
|
||||
Extra extends PropertyKey = Exclude<KnownKeys<A>, KnownKeys<B>>,
|
||||
Missing extends PropertyKey = Exclude<KnownKeys<B>, KnownKeys<A>>
|
||||
> = [Extra, Missing] extends [never, never] ? true : { _brand: 'KeyMismatch'; extra: Extra; missing: Missing };
|
||||
|
||||
/** Constraint: T must resolve to `true`. */
|
||||
type Assert<T extends true> = T;
|
||||
|
||||
/**
|
||||
* Same as {@link AssertExactKeys}, but tolerates the SDK's `resultType` key on
|
||||
* result shapes: the SDK follows the 2026-07-28 schema's optional `resultType`
|
||||
* passthrough (absent means "complete"), which is not in released 2025-11-25.
|
||||
* Every other key still has to match exactly.
|
||||
*/
|
||||
type AssertExactKeysWithResultType<A, B> = AssertExactKeys<A, B & { resultType?: unknown }>;
|
||||
|
||||
/*
|
||||
* Excluded from key-level assertions (21 entries):
|
||||
*
|
||||
* Union types — KnownKeys cannot meaningfully enumerate their members (15):
|
||||
* ClientRequest, ServerRequest, ClientNotification, ServerNotification,
|
||||
* ClientResult, ServerResult, JSONRPCMessage, JSONRPCResponse, ContentBlock,
|
||||
* SamplingMessageContentBlock, ElicitRequestParams, PrimitiveSchemaDefinition,
|
||||
* SingleSelectEnumSchema, MultiSelectEnumSchema, EnumSchema
|
||||
*
|
||||
* Primitive type aliases — no object keys to compare (6):
|
||||
* Role, LoggingLevel, ProgressToken, RequestId, Cursor, TaskStatus
|
||||
*/
|
||||
|
||||
// -- Simple types (88) --
|
||||
|
||||
type _K_RequestParams = Assert<AssertExactKeys<SDKTypes.RequestParams, SpecTypes.RequestParams>>;
|
||||
type _K_NotificationParams = Assert<AssertExactKeys<SDKTypes.NotificationParams, SpecTypes.NotificationParams>>;
|
||||
type _K_CancelledNotificationParams = Assert<AssertExactKeys<SDKTypes.CancelledNotificationParams, SpecTypes.CancelledNotificationParams>>;
|
||||
type _K_InitializeRequestParams = Assert<AssertExactKeys<SDKTypes.InitializeRequestParams, SpecTypes.InitializeRequestParams>>;
|
||||
type _K_ProgressNotificationParams = Assert<AssertExactKeys<SDKTypes.ProgressNotificationParams, SpecTypes.ProgressNotificationParams>>;
|
||||
type _K_ResourceRequestParams = Assert<AssertExactKeys<SDKTypes.ResourceRequestParams, SpecTypes.ResourceRequestParams>>;
|
||||
type _K_ReadResourceRequestParams = Assert<AssertExactKeys<SDKTypes.ReadResourceRequestParams, SpecTypes.ReadResourceRequestParams>>;
|
||||
type _K_SubscribeRequestParams = Assert<AssertExactKeys<SDKTypes.SubscribeRequestParams, SpecTypes.SubscribeRequestParams>>;
|
||||
type _K_UnsubscribeRequestParams = Assert<AssertExactKeys<SDKTypes.UnsubscribeRequestParams, SpecTypes.UnsubscribeRequestParams>>;
|
||||
type _K_ResourceUpdatedNotificationParams = Assert<
|
||||
AssertExactKeys<SDKTypes.ResourceUpdatedNotificationParams, SpecTypes.ResourceUpdatedNotificationParams>
|
||||
>;
|
||||
type _K_GetPromptRequestParams = Assert<AssertExactKeys<SDKTypes.GetPromptRequestParams, SpecTypes.GetPromptRequestParams>>;
|
||||
type _K_CallToolRequestParams = Assert<AssertExactKeys<SDKTypes.CallToolRequestParams, SpecTypes.CallToolRequestParams>>;
|
||||
type _K_SetLevelRequestParams = Assert<AssertExactKeys<SDKTypes.SetLevelRequestParams, SpecTypes.SetLevelRequestParams>>;
|
||||
type _K_LoggingMessageNotificationParams = Assert<
|
||||
AssertExactKeys<SDKTypes.LoggingMessageNotificationParams, SpecTypes.LoggingMessageNotificationParams>
|
||||
>;
|
||||
type _K_CreateMessageRequestParams = Assert<AssertExactKeys<SDKTypes.CreateMessageRequestParams, SpecTypes.CreateMessageRequestParams>>;
|
||||
type _K_CompleteRequestParams = Assert<AssertExactKeys<SDKTypes.CompleteRequestParams, SpecTypes.CompleteRequestParams>>;
|
||||
type _K_ElicitRequestFormParams = Assert<AssertExactKeys<SDKTypes.ElicitRequestFormParams, SpecTypes.ElicitRequestFormParams>>;
|
||||
type _K_ElicitRequestURLParams = Assert<AssertExactKeys<SDKTypes.ElicitRequestURLParams, SpecTypes.ElicitRequestURLParams>>;
|
||||
type _K_PaginatedRequestParams = Assert<AssertExactKeys<SDKTypes.PaginatedRequestParams, SpecTypes.PaginatedRequestParams>>;
|
||||
type _K_BaseMetadata = Assert<AssertExactKeys<SDKTypes.BaseMetadata, SpecTypes.BaseMetadata>>;
|
||||
type _K_Implementation = Assert<AssertExactKeys<SDKTypes.Implementation, SpecTypes.Implementation>>;
|
||||
type _K_PaginatedResult = Assert<AssertExactKeysWithResultType<SDKTypes.PaginatedResult, SpecTypes.PaginatedResult>>;
|
||||
type _K_ListRootsResult = Assert<AssertExactKeysWithResultType<SDKTypes.ListRootsResult, SpecTypes.ListRootsResult>>;
|
||||
type _K_Root = Assert<AssertExactKeys<SDKTypes.Root, SpecTypes.Root>>;
|
||||
type _K_ElicitResult = Assert<AssertExactKeysWithResultType<SDKTypes.ElicitResult, SpecTypes.ElicitResult>>;
|
||||
type _K_CompleteResult = Assert<AssertExactKeysWithResultType<SDKTypes.CompleteResult, SpecTypes.CompleteResult>>;
|
||||
type _K_Request = Assert<AssertExactKeys<SDKTypes.Request, SpecTypes.Request>>;
|
||||
type _K_Result = Assert<AssertExactKeysWithResultType<SDKTypes.Result, SpecTypes.Result>>;
|
||||
type _K_JSONRPCRequest = Assert<AssertExactKeys<SDKTypes.JSONRPCRequest, SpecTypes.JSONRPCRequest>>;
|
||||
type _K_JSONRPCNotification = Assert<AssertExactKeys<SDKTypes.JSONRPCNotification, SpecTypes.JSONRPCNotification>>;
|
||||
type _K_EmptyResult = Assert<AssertExactKeysWithResultType<SDKTypes.EmptyResult, SpecTypes.EmptyResult>>;
|
||||
type _K_Notification = Assert<AssertExactKeys<SDKTypes.Notification, SpecTypes.Notification>>;
|
||||
type _K_ResourceTemplateReference = Assert<AssertExactKeys<SDKTypes.ResourceTemplateReference, SpecTypes.ResourceTemplateReference>>;
|
||||
// @ts-expect-error Genuine mismatch: SDK PromptReference is missing 'title' from spec
|
||||
type _K_PromptReference = Assert<AssertExactKeys<SDKTypes.PromptReference, SpecTypes.PromptReference>>;
|
||||
type _K_ToolAnnotations = Assert<AssertExactKeys<SDKTypes.ToolAnnotations, SpecTypes.ToolAnnotations>>;
|
||||
type _K_Tool = Assert<AssertExactKeys<SDKTypes.Tool, SpecTypes.Tool>>;
|
||||
type _K_ListToolsResult = Assert<AssertExactKeysWithResultType<SDKTypes.ListToolsResult, SpecTypes.ListToolsResult>>;
|
||||
type _K_CallToolResult = Assert<AssertExactKeysWithResultType<SDKTypes.CallToolResult, SpecTypes.CallToolResult>>;
|
||||
type _K_ListResourcesResult = Assert<AssertExactKeysWithResultType<SDKTypes.ListResourcesResult, SpecTypes.ListResourcesResult>>;
|
||||
type _K_ListResourceTemplatesResult = Assert<
|
||||
AssertExactKeysWithResultType<SDKTypes.ListResourceTemplatesResult, SpecTypes.ListResourceTemplatesResult>
|
||||
>;
|
||||
type _K_ReadResourceResult = Assert<AssertExactKeysWithResultType<SDKTypes.ReadResourceResult, SpecTypes.ReadResourceResult>>;
|
||||
type _K_ResourceContents = Assert<AssertExactKeys<SDKTypes.ResourceContents, SpecTypes.ResourceContents>>;
|
||||
type _K_TextResourceContents = Assert<AssertExactKeys<SDKTypes.TextResourceContents, SpecTypes.TextResourceContents>>;
|
||||
type _K_BlobResourceContents = Assert<AssertExactKeys<SDKTypes.BlobResourceContents, SpecTypes.BlobResourceContents>>;
|
||||
type _K_Resource = Assert<AssertExactKeys<SDKTypes.Resource, SpecTypes.Resource>>;
|
||||
// @ts-expect-error Genuine mismatch: SDK PromptArgument is missing 'title' from spec
|
||||
type _K_PromptArgument = Assert<AssertExactKeys<SDKTypes.PromptArgument, SpecTypes.PromptArgument>>;
|
||||
type _K_Prompt = Assert<AssertExactKeys<SDKTypes.Prompt, SpecTypes.Prompt>>;
|
||||
type _K_ListPromptsResult = Assert<AssertExactKeysWithResultType<SDKTypes.ListPromptsResult, SpecTypes.ListPromptsResult>>;
|
||||
type _K_GetPromptResult = Assert<AssertExactKeysWithResultType<SDKTypes.GetPromptResult, SpecTypes.GetPromptResult>>;
|
||||
type _K_TextContent = Assert<AssertExactKeys<SDKTypes.TextContent, SpecTypes.TextContent>>;
|
||||
type _K_ImageContent = Assert<AssertExactKeys<SDKTypes.ImageContent, SpecTypes.ImageContent>>;
|
||||
type _K_AudioContent = Assert<AssertExactKeys<SDKTypes.AudioContent, SpecTypes.AudioContent>>;
|
||||
type _K_EmbeddedResource = Assert<AssertExactKeys<SDKTypes.EmbeddedResource, SpecTypes.EmbeddedResource>>;
|
||||
type _K_ResourceLink = Assert<AssertExactKeys<SDKTypes.ResourceLink, SpecTypes.ResourceLink>>;
|
||||
type _K_PromptMessage = Assert<AssertExactKeys<SDKTypes.PromptMessage, SpecTypes.PromptMessage>>;
|
||||
type _K_BooleanSchema = Assert<AssertExactKeys<SDKTypes.BooleanSchema, SpecTypes.BooleanSchema>>;
|
||||
type _K_StringSchema = Assert<AssertExactKeys<SDKTypes.StringSchema, SpecTypes.StringSchema>>;
|
||||
type _K_NumberSchema = Assert<AssertExactKeys<SDKTypes.NumberSchema, SpecTypes.NumberSchema>>;
|
||||
type _K_UntitledSingleSelectEnumSchema = Assert<
|
||||
AssertExactKeys<SDKTypes.UntitledSingleSelectEnumSchema, SpecTypes.UntitledSingleSelectEnumSchema>
|
||||
>;
|
||||
type _K_TitledSingleSelectEnumSchema = Assert<
|
||||
AssertExactKeys<SDKTypes.TitledSingleSelectEnumSchema, SpecTypes.TitledSingleSelectEnumSchema>
|
||||
>;
|
||||
type _K_UntitledMultiSelectEnumSchema = Assert<
|
||||
AssertExactKeys<SDKTypes.UntitledMultiSelectEnumSchema, SpecTypes.UntitledMultiSelectEnumSchema>
|
||||
>;
|
||||
type _K_TitledMultiSelectEnumSchema = Assert<AssertExactKeys<SDKTypes.TitledMultiSelectEnumSchema, SpecTypes.TitledMultiSelectEnumSchema>>;
|
||||
type _K_LegacyTitledEnumSchema = Assert<AssertExactKeys<SDKTypes.LegacyTitledEnumSchema, SpecTypes.LegacyTitledEnumSchema>>;
|
||||
type _K_JSONRPCErrorResponse = Assert<AssertExactKeys<SDKTypes.JSONRPCErrorResponse, SpecTypes.JSONRPCErrorResponse>>;
|
||||
type _K_JSONRPCResultResponse = Assert<AssertExactKeys<SDKTypes.JSONRPCResultResponse, SpecTypes.JSONRPCResultResponse>>;
|
||||
type _K_InitializeResult = Assert<AssertExactKeysWithResultType<SDKTypes.InitializeResult, SpecTypes.InitializeResult>>;
|
||||
// @ts-expect-error SDK follows the 2026-07-28 schema's `extensions` capability key; not in released 2025-11-25
|
||||
type _K_ClientCapabilities = Assert<AssertExactKeys<SDKTypes.ClientCapabilities, SpecTypes.ClientCapabilities>>;
|
||||
// @ts-expect-error SDK follows the 2026-07-28 schema's `extensions` capability key; not in released 2025-11-25
|
||||
type _K_ServerCapabilities = Assert<AssertExactKeys<SDKTypes.ServerCapabilities, SpecTypes.ServerCapabilities>>;
|
||||
type _K_SamplingMessage = Assert<AssertExactKeys<SDKTypes.SamplingMessage, SpecTypes.SamplingMessage>>;
|
||||
type _K_Icon = Assert<AssertExactKeys<SDKTypes.Icon, SpecTypes.Icon>>;
|
||||
type _K_Icons = Assert<AssertExactKeys<SDKTypes.Icons, SpecTypes.Icons>>;
|
||||
type _K_ModelHint = Assert<AssertExactKeys<SDKTypes.ModelHint, SpecTypes.ModelHint>>;
|
||||
type _K_ModelPreferences = Assert<AssertExactKeys<SDKTypes.ModelPreferences, SpecTypes.ModelPreferences>>;
|
||||
type _K_ToolChoice = Assert<AssertExactKeys<SDKTypes.ToolChoice, SpecTypes.ToolChoice>>;
|
||||
type _K_ToolUseContent = Assert<AssertExactKeys<SDKTypes.ToolUseContent, SpecTypes.ToolUseContent>>;
|
||||
type _K_ToolResultContent = Assert<AssertExactKeys<SDKTypes.ToolResultContent, SpecTypes.ToolResultContent>>;
|
||||
type _K_Annotations = Assert<AssertExactKeys<SDKTypes.Annotations, SpecTypes.Annotations>>;
|
||||
type _K_ToolExecution = Assert<AssertExactKeys<SDKTypes.ToolExecution, SpecTypes.ToolExecution>>;
|
||||
type _K_TaskMetadata = Assert<AssertExactKeys<SDKTypes.TaskMetadata, SpecTypes.TaskMetadata>>;
|
||||
type _K_RelatedTaskMetadata = Assert<AssertExactKeys<SDKTypes.RelatedTaskMetadata, SpecTypes.RelatedTaskMetadata>>;
|
||||
type _K_TaskAugmentedRequestParams = Assert<AssertExactKeys<SDKTypes.TaskAugmentedRequestParams, SpecTypes.TaskAugmentedRequestParams>>;
|
||||
type _K_Task = Assert<AssertExactKeys<SDKTypes.Task, SpecTypes.Task>>;
|
||||
type _K_CreateTaskResult = Assert<AssertExactKeysWithResultType<SDKTypes.CreateTaskResult, SpecTypes.CreateTaskResult>>;
|
||||
type _K_GetTaskResult = Assert<AssertExactKeysWithResultType<SDKTypes.GetTaskResult, SpecTypes.GetTaskResult>>;
|
||||
type _K_GetTaskPayloadResult = Assert<AssertExactKeysWithResultType<SDKTypes.GetTaskPayloadResult, SpecTypes.GetTaskPayloadResult>>;
|
||||
type _K_ListTasksResult = Assert<AssertExactKeysWithResultType<SDKTypes.ListTasksResult, SpecTypes.ListTasksResult>>;
|
||||
type _K_CancelTaskResult = Assert<AssertExactKeysWithResultType<SDKTypes.CancelTaskResult, SpecTypes.CancelTaskResult>>;
|
||||
type _K_TaskStatusNotificationParams = Assert<
|
||||
AssertExactKeys<SDKTypes.TaskStatusNotificationParams, SpecTypes.TaskStatusNotificationParams>
|
||||
>;
|
||||
|
||||
// -- WithJSONRPC-wrapped notification types (11) --
|
||||
// SDK notification types do not include `jsonrpc` — the spec types do. We wrap
|
||||
// with WithJSONRPC<> to add the missing field before comparing keys.
|
||||
|
||||
type _K_ElicitationCompleteNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.ElicitationCompleteNotification>, SpecTypes.ElicitationCompleteNotification>
|
||||
>;
|
||||
type _K_CancelledNotification = Assert<AssertExactKeys<WithJSONRPC<SDKTypes.CancelledNotification>, SpecTypes.CancelledNotification>>;
|
||||
type _K_ProgressNotification = Assert<AssertExactKeys<WithJSONRPC<SDKTypes.ProgressNotification>, SpecTypes.ProgressNotification>>;
|
||||
type _K_ToolListChangedNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.ToolListChangedNotification>, SpecTypes.ToolListChangedNotification>
|
||||
>;
|
||||
type _K_ResourceListChangedNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.ResourceListChangedNotification>, SpecTypes.ResourceListChangedNotification>
|
||||
>;
|
||||
type _K_PromptListChangedNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.PromptListChangedNotification>, SpecTypes.PromptListChangedNotification>
|
||||
>;
|
||||
type _K_RootsListChangedNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.RootsListChangedNotification>, SpecTypes.RootsListChangedNotification>
|
||||
>;
|
||||
type _K_ResourceUpdatedNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.ResourceUpdatedNotification>, SpecTypes.ResourceUpdatedNotification>
|
||||
>;
|
||||
type _K_LoggingMessageNotification = Assert<
|
||||
AssertExactKeys<WithJSONRPC<SDKTypes.LoggingMessageNotification>, SpecTypes.LoggingMessageNotification>
|
||||
>;
|
||||
type _K_InitializedNotification = Assert<AssertExactKeys<WithJSONRPC<SDKTypes.InitializedNotification>, SpecTypes.InitializedNotification>>;
|
||||
type _K_TaskStatusNotification = Assert<AssertExactKeys<WithJSONRPC<SDKTypes.TaskStatusNotification>, SpecTypes.TaskStatusNotification>>;
|
||||
|
||||
// -- WithJSONRPCRequest-wrapped request types (21) --
|
||||
// SDK request types do not include `jsonrpc` or `id` — the spec types do. We
|
||||
// wrap with WithJSONRPCRequest<> to add the missing fields before comparing keys.
|
||||
|
||||
type _K_SubscribeRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.SubscribeRequest>, SpecTypes.SubscribeRequest>>;
|
||||
type _K_UnsubscribeRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.UnsubscribeRequest>, SpecTypes.UnsubscribeRequest>>;
|
||||
type _K_PaginatedRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.PaginatedRequest>, SpecTypes.PaginatedRequest>>;
|
||||
type _K_ListRootsRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListRootsRequest>, SpecTypes.ListRootsRequest>>;
|
||||
type _K_ElicitRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ElicitRequest>, SpecTypes.ElicitRequest>>;
|
||||
type _K_CompleteRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.CompleteRequest>, SpecTypes.CompleteRequest>>;
|
||||
type _K_ListToolsRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListToolsRequest>, SpecTypes.ListToolsRequest>>;
|
||||
type _K_CallToolRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.CallToolRequest>, SpecTypes.CallToolRequest>>;
|
||||
type _K_SetLevelRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.SetLevelRequest>, SpecTypes.SetLevelRequest>>;
|
||||
type _K_PingRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.PingRequest>, SpecTypes.PingRequest>>;
|
||||
type _K_ListResourcesRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListResourcesRequest>, SpecTypes.ListResourcesRequest>>;
|
||||
type _K_ListResourceTemplatesRequest = Assert<
|
||||
AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListResourceTemplatesRequest>, SpecTypes.ListResourceTemplatesRequest>
|
||||
>;
|
||||
type _K_ReadResourceRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ReadResourceRequest>, SpecTypes.ReadResourceRequest>>;
|
||||
type _K_ListPromptsRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListPromptsRequest>, SpecTypes.ListPromptsRequest>>;
|
||||
type _K_GetPromptRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.GetPromptRequest>, SpecTypes.GetPromptRequest>>;
|
||||
type _K_CreateMessageRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.CreateMessageRequest>, SpecTypes.CreateMessageRequest>>;
|
||||
type _K_InitializeRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.InitializeRequest>, SpecTypes.InitializeRequest>>;
|
||||
type _K_GetTaskRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.GetTaskRequest>, SpecTypes.GetTaskRequest>>;
|
||||
type _K_GetTaskPayloadRequest = Assert<
|
||||
AssertExactKeys<WithJSONRPCRequest<SDKTypes.GetTaskPayloadRequest>, SpecTypes.GetTaskPayloadRequest>
|
||||
>;
|
||||
type _K_ListTasksRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.ListTasksRequest>, SpecTypes.ListTasksRequest>>;
|
||||
type _K_CancelTaskRequest = Assert<AssertExactKeys<WithJSONRPCRequest<SDKTypes.CancelTaskRequest>, SpecTypes.CancelTaskRequest>>;
|
||||
|
||||
// -- Name mismatches (2) --
|
||||
// SDK exports these under different names than the spec.
|
||||
|
||||
type _K_CreateMessageResult = Assert<AssertExactKeysWithResultType<SDKTypes.CreateMessageResultWithTools, SpecTypes.CreateMessageResult>>;
|
||||
type _K_ResourceTemplate = Assert<AssertExactKeys<SDKTypes.ResourceTemplateType, SpecTypes.ResourceTemplate>>;
|
||||
|
||||
// Types excluded from the key-parity completeness guard: union types and primitive aliases
|
||||
// that cannot have meaningful AssertExactKeys assertions.
|
||||
const KEY_PARITY_EXCLUDED = [
|
||||
// Union types (15)
|
||||
'ClientRequest',
|
||||
'ServerRequest',
|
||||
'ClientNotification',
|
||||
'ServerNotification',
|
||||
'ClientResult',
|
||||
'ServerResult',
|
||||
'JSONRPCMessage',
|
||||
'JSONRPCResponse',
|
||||
'ContentBlock',
|
||||
'SamplingMessageContentBlock',
|
||||
'ElicitRequestParams',
|
||||
'PrimitiveSchemaDefinition',
|
||||
'SingleSelectEnumSchema',
|
||||
'MultiSelectEnumSchema',
|
||||
'EnumSchema',
|
||||
// Primitive aliases (6)
|
||||
'Role',
|
||||
'LoggingLevel',
|
||||
'ProgressToken',
|
||||
'RequestId',
|
||||
'Cursor',
|
||||
'TaskStatus'
|
||||
];
|
||||
|
||||
// Generated from the frozen 2025-11-25 release schema by `pnpm run fetch:spec-types 2025-11-25`.
|
||||
const SPEC_TYPES_FILE = path.resolve(__dirname, '../src/types/spec.types.2025-11-25.ts');
|
||||
const SDK_TYPES_FILE = path.resolve(__dirname, '../src/types/types.ts');
|
||||
|
||||
const MISSING_SDK_TYPES = [
|
||||
// These are inlined in the SDK:
|
||||
'Error', // The inner error object of a JSONRPCError
|
||||
'URLElicitationRequiredError' // In the SDK, but with a custom definition
|
||||
];
|
||||
|
||||
function extractExportedTypes(source: string): string[] {
|
||||
const matches = [...source.matchAll(/export\s+(?:interface|class|type)\s+(\w+)\b/g)];
|
||||
return matches.map(m => m[1]!);
|
||||
}
|
||||
|
||||
function extractKeyParityTypes(source: string): string[] {
|
||||
return [...source.matchAll(/^type _K_(\w+)\s*=/gm)].map(m => m[1]!);
|
||||
}
|
||||
|
||||
describe('Spec Types (2025-11-25)', () => {
|
||||
const specTypes = extractExportedTypes(fs.readFileSync(SPEC_TYPES_FILE, 'utf8'));
|
||||
const sdkTypes = extractExportedTypes(fs.readFileSync(SDK_TYPES_FILE, 'utf8'));
|
||||
const typesToCheck = specTypes.filter(type => !MISSING_SDK_TYPES.includes(type));
|
||||
|
||||
it('should define some expected types', () => {
|
||||
expect(specTypes).toContain('JSONRPCNotification');
|
||||
expect(specTypes).toContain('ElicitResult');
|
||||
expect(specTypes).toHaveLength(145);
|
||||
});
|
||||
|
||||
it('should have up to date list of missing sdk types', () => {
|
||||
for (const typeName of MISSING_SDK_TYPES) {
|
||||
expect(sdkTypes).not.toContain(typeName);
|
||||
}
|
||||
});
|
||||
|
||||
it('should have comprehensive compatibility tests', () => {
|
||||
const missingTests = [];
|
||||
|
||||
for (const typeName of typesToCheck) {
|
||||
if (!sdkTypeChecks[typeName as keyof typeof sdkTypeChecks]) {
|
||||
missingTests.push(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
expect(missingTests).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should have key-parity assertions for all non-excluded compatibility tests', () => {
|
||||
const thisSource = fs.readFileSync(__filename, 'utf8');
|
||||
const checked = new Set(extractKeyParityTypes(thisSource));
|
||||
const excluded = new Set<string>(KEY_PARITY_EXCLUDED);
|
||||
const missing = Object.keys(sdkTypeChecks).filter(name => !checked.has(name) && !excluded.has(name));
|
||||
expect(missing).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe('Missing SDK Types', () => {
|
||||
it.each(MISSING_SDK_TYPES)('%s should not be present in MISSING_SDK_TYPES if it has a compatibility test', type => {
|
||||
expect(sdkTypeChecks[type as keyof typeof sdkTypeChecks]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
550
packages/core/test/spec.types.2026-07-28.test.ts
Normal file
550
packages/core/test/spec.types.2026-07-28.test.ts
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/**
|
||||
* Compares the SDK's types against the upcoming 2026-07-28 schema (spec.types.2026-07-28.ts).
|
||||
* The frozen-release comparison lives in spec.types.2025-11-25.test.ts.
|
||||
*
|
||||
* The SDK does not implement the 2026-07-28 surface yet: every 2026-07-28 type whose shape the SDK
|
||||
* does not (yet) match is listed in MISSING_SDK_TYPES_2026_07_28 below. Removing a name from
|
||||
* that list forces a real mutual-assignability check to be added to sdkTypeChecks (the
|
||||
* completeness tests below fail otherwise) — implementation work burns the list down.
|
||||
*
|
||||
* Unlike MISSING_SDK_TYPES in the 2025-11-25 comparison, names in this list may well
|
||||
* exist in the SDK (e.g. RequestParams) — they are listed because the 2026-07-28 revision changed
|
||||
* their shape, not necessarily because the SDK lacks them.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import {
|
||||
LATEST_PROTOCOL_VERSION,
|
||||
MISSING_REQUIRED_CLIENT_CAPABILITY,
|
||||
UNSUPPORTED_PROTOCOL_VERSION
|
||||
} from '../src/types/spec.types.2026-07-28.js';
|
||||
import type * as SpecTypes from '../src/types/spec.types.2026-07-28.js';
|
||||
import type * as SDKTypes from '../src/types/index.js';
|
||||
import {
|
||||
CLIENT_CAPABILITIES_META_KEY,
|
||||
CLIENT_INFO_META_KEY,
|
||||
LOG_LEVEL_META_KEY,
|
||||
PROTOCOL_VERSION_META_KEY,
|
||||
ProtocolErrorCode
|
||||
} from '../src/types/index.js';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
||||
// Adds the `jsonrpc` property to a type, to match the on-wire format of notifications.
|
||||
type WithJSONRPC<T> = T & { jsonrpc: '2.0' };
|
||||
|
||||
// Adds the `jsonrpc` and `id` properties to a type, to match the on-wire format of requests.
|
||||
type WithJSONRPCRequest<T> = T & { jsonrpc: '2.0'; id: SDKTypes.RequestId };
|
||||
|
||||
const sdkTypeChecks = {
|
||||
JSONValue: (sdk: SDKTypes.JSONValue, spec: SpecTypes.JSONValue) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONObject: (sdk: SDKTypes.JSONObject, spec: SpecTypes.JSONObject) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONArray: (sdk: SDKTypes.JSONArray, spec: SpecTypes.JSONArray) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
MetaObject: (sdk: SDKTypes.MetaObject, spec: SpecTypes.MetaObject) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
// The SDK models the 2026-07-28 revision's required per-request `_meta` envelope as
|
||||
// RequestMetaEnvelope (the base request schemas stay lenient; envelope
|
||||
// requiredness is enforced at dispatch). This check also pins the
|
||||
// *_META_KEY constants: a drifted key name breaks mutual assignability.
|
||||
RequestMetaObject: (sdk: SDKTypes.RequestMetaEnvelope, spec: SpecTypes.RequestMetaObject) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressToken: (sdk: SDKTypes.ProgressToken, spec: SpecTypes.ProgressToken) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Cursor: (sdk: SDKTypes.Cursor, spec: SpecTypes.Cursor) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Request: (sdk: SDKTypes.Request, spec: SpecTypes.Request) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
NotificationParams: (sdk: SDKTypes.NotificationParams, spec: SpecTypes.NotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
RequestId: (sdk: SDKTypes.RequestId, spec: SpecTypes.RequestId) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCRequest: (sdk: SDKTypes.JSONRPCRequest, spec: SpecTypes.JSONRPCRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCNotification: (sdk: WithJSONRPC<SDKTypes.JSONRPCNotification>, spec: SpecTypes.JSONRPCNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
JSONRPCErrorResponse: (sdk: SDKTypes.JSONRPCErrorResponse, spec: SpecTypes.JSONRPCErrorResponse) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ParseError: (sdk: SDKTypes.ParseError, spec: SpecTypes.ParseError) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InvalidRequestError: (sdk: SDKTypes.InvalidRequestError, spec: SpecTypes.InvalidRequestError) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
MethodNotFoundError: (sdk: SDKTypes.MethodNotFoundError, spec: SpecTypes.MethodNotFoundError) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InvalidParamsError: (sdk: SDKTypes.InvalidParamsError, spec: SpecTypes.InvalidParamsError) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
InternalError: (sdk: SDKTypes.InternalError, spec: SpecTypes.InternalError) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelledNotificationParams: (sdk: SDKTypes.CancelledNotificationParams, spec: SpecTypes.CancelledNotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
CancelledNotification: (sdk: WithJSONRPC<SDKTypes.CancelledNotification>, spec: SpecTypes.CancelledNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientCapabilities: (sdk: SDKTypes.ClientCapabilities, spec: SpecTypes.ClientCapabilities) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ServerCapabilities: (sdk: SDKTypes.ServerCapabilities, spec: SpecTypes.ServerCapabilities) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Icon: (sdk: SDKTypes.Icon, spec: SpecTypes.Icon) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Icons: (sdk: SDKTypes.Icons, spec: SpecTypes.Icons) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BaseMetadata: (sdk: SDKTypes.BaseMetadata, spec: SpecTypes.BaseMetadata) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Implementation: (sdk: SDKTypes.Implementation, spec: SpecTypes.Implementation) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressNotificationParams: (sdk: SDKTypes.ProgressNotificationParams, spec: SpecTypes.ProgressNotificationParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ProgressNotification: (sdk: WithJSONRPC<SDKTypes.ProgressNotification>, spec: SpecTypes.ProgressNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceListChangedNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.ResourceListChangedNotification>,
|
||||
spec: SpecTypes.ResourceListChangedNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceUpdatedNotificationParams: (
|
||||
sdk: SDKTypes.ResourceUpdatedNotificationParams,
|
||||
spec: SpecTypes.ResourceUpdatedNotificationParams
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceUpdatedNotification: (sdk: WithJSONRPC<SDKTypes.ResourceUpdatedNotification>, spec: SpecTypes.ResourceUpdatedNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Resource: (sdk: SDKTypes.Resource, spec: SpecTypes.Resource) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceTemplate: (sdk: SDKTypes.ResourceTemplateType, spec: SpecTypes.ResourceTemplate) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceContents: (sdk: SDKTypes.ResourceContents, spec: SpecTypes.ResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TextResourceContents: (sdk: SDKTypes.TextResourceContents, spec: SpecTypes.TextResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BlobResourceContents: (sdk: SDKTypes.BlobResourceContents, spec: SpecTypes.BlobResourceContents) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Prompt: (sdk: SDKTypes.Prompt, spec: SpecTypes.Prompt) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptArgument: (sdk: SDKTypes.PromptArgument, spec: SpecTypes.PromptArgument) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Role: (sdk: SDKTypes.Role, spec: SpecTypes.Role) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptMessage: (sdk: SDKTypes.PromptMessage, spec: SpecTypes.PromptMessage) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceLink: (sdk: SDKTypes.ResourceLink, spec: SpecTypes.ResourceLink) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
EmbeddedResource: (sdk: SDKTypes.EmbeddedResource, spec: SpecTypes.EmbeddedResource) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptListChangedNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.PromptListChangedNotification>,
|
||||
spec: SpecTypes.PromptListChangedNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolListChangedNotification: (sdk: WithJSONRPC<SDKTypes.ToolListChangedNotification>, spec: SpecTypes.ToolListChangedNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolAnnotations: (sdk: SDKTypes.ToolAnnotations, spec: SpecTypes.ToolAnnotations) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingMessageNotificationParams: (
|
||||
sdk: SDKTypes.LoggingMessageNotificationParams,
|
||||
spec: SpecTypes.LoggingMessageNotificationParams
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingMessageNotification: (sdk: WithJSONRPC<SDKTypes.LoggingMessageNotification>, spec: SpecTypes.LoggingMessageNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LoggingLevel: (sdk: SDKTypes.LoggingLevel, spec: SpecTypes.LoggingLevel) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolChoice: (sdk: SDKTypes.ToolChoice, spec: SpecTypes.ToolChoice) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Annotations: (sdk: SDKTypes.Annotations, spec: SpecTypes.Annotations) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ContentBlock: (sdk: SDKTypes.ContentBlock, spec: SpecTypes.ContentBlock) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TextContent: (sdk: SDKTypes.TextContent, spec: SpecTypes.TextContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ImageContent: (sdk: SDKTypes.ImageContent, spec: SpecTypes.ImageContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
AudioContent: (sdk: SDKTypes.AudioContent, spec: SpecTypes.AudioContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ToolUseContent: (sdk: SDKTypes.ToolUseContent, spec: SpecTypes.ToolUseContent) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ModelPreferences: (sdk: SDKTypes.ModelPreferences, spec: SpecTypes.ModelPreferences) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ModelHint: (sdk: SDKTypes.ModelHint, spec: SpecTypes.ModelHint) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ResourceTemplateReference: (sdk: SDKTypes.ResourceTemplateReference, spec: SpecTypes.ResourceTemplateReference) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PromptReference: (sdk: SDKTypes.PromptReference, spec: SpecTypes.PromptReference) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
Root: (sdk: SDKTypes.Root, spec: SpecTypes.Root) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestFormParams: (sdk: SDKTypes.ElicitRequestFormParams, spec: SpecTypes.ElicitRequestFormParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestURLParams: (sdk: SDKTypes.ElicitRequestURLParams, spec: SpecTypes.ElicitRequestURLParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequestParams: (sdk: SDKTypes.ElicitRequestParams, spec: SpecTypes.ElicitRequestParams) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitRequest: (sdk: SDKTypes.ElicitRequest, spec: SpecTypes.ElicitRequest) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
PrimitiveSchemaDefinition: (sdk: SDKTypes.PrimitiveSchemaDefinition, spec: SpecTypes.PrimitiveSchemaDefinition) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
StringSchema: (sdk: SDKTypes.StringSchema, spec: SpecTypes.StringSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
NumberSchema: (sdk: SDKTypes.NumberSchema, spec: SpecTypes.NumberSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
BooleanSchema: (sdk: SDKTypes.BooleanSchema, spec: SpecTypes.BooleanSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UntitledSingleSelectEnumSchema: (sdk: SDKTypes.UntitledSingleSelectEnumSchema, spec: SpecTypes.UntitledSingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TitledSingleSelectEnumSchema: (sdk: SDKTypes.TitledSingleSelectEnumSchema, spec: SpecTypes.TitledSingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
SingleSelectEnumSchema: (sdk: SDKTypes.SingleSelectEnumSchema, spec: SpecTypes.SingleSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
UntitledMultiSelectEnumSchema: (sdk: SDKTypes.UntitledMultiSelectEnumSchema, spec: SpecTypes.UntitledMultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
TitledMultiSelectEnumSchema: (sdk: SDKTypes.TitledMultiSelectEnumSchema, spec: SpecTypes.TitledMultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
MultiSelectEnumSchema: (sdk: SDKTypes.MultiSelectEnumSchema, spec: SpecTypes.MultiSelectEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
LegacyTitledEnumSchema: (sdk: SDKTypes.LegacyTitledEnumSchema, spec: SpecTypes.LegacyTitledEnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
EnumSchema: (sdk: SDKTypes.EnumSchema, spec: SpecTypes.EnumSchema) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ElicitationCompleteNotification: (
|
||||
sdk: WithJSONRPC<SDKTypes.ElicitationCompleteNotification>,
|
||||
spec: SpecTypes.ElicitationCompleteNotification
|
||||
) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
},
|
||||
ClientNotification: (sdk: WithJSONRPC<SDKTypes.ClientNotification>, spec: SpecTypes.ClientNotification) => {
|
||||
sdk = spec;
|
||||
spec = sdk;
|
||||
}
|
||||
};
|
||||
|
||||
// Generated from the 2026-07-28 schema by `pnpm run fetch:spec-types 2026-07-28 <sha>`.
|
||||
const SPEC_TYPES_FILE = path.resolve(__dirname, '../src/types/spec.types.2026-07-28.ts');
|
||||
|
||||
/**
|
||||
* 2026-07-28 spec types the SDK does not match yet. Spec-implementation work for the
|
||||
* 2026-07-28 release removes entries from this list as the SDK adopts each shape.
|
||||
*/
|
||||
const MISSING_SDK_TYPES_2026_07_28 = [
|
||||
// Inlined in the SDK (same as the 2025-11-25 comparison):
|
||||
'Error', // The inner error object of a JSONRPCError
|
||||
|
||||
// SEP-2575 per-request envelope: 2026-07-28 requests REQUIRE a `_meta` envelope
|
||||
// (`io.modelcontextprotocol/protocolVersion`, clientInfo, clientCapabilities). The
|
||||
// envelope itself is modeled by RequestMetaEnvelope (see sdkTypeChecks above); the
|
||||
// request shapes below stay here because the SDK wire schemas deliberately keep
|
||||
// `_meta` lenient — the same schemas parse pre-2026 requests (no envelope) and 2026
|
||||
// requests, with envelope requiredness enforced per request at dispatch. They burn
|
||||
// only if the SDK ever models era-specific request types.
|
||||
'RequestParams',
|
||||
'PaginatedRequestParams',
|
||||
'ResourceRequestParams',
|
||||
'CallToolRequestParams',
|
||||
'CompleteRequestParams',
|
||||
'GetPromptRequestParams',
|
||||
'ReadResourceRequestParams',
|
||||
'CreateMessageRequestParams',
|
||||
'PaginatedRequest',
|
||||
'CallToolRequest',
|
||||
'CompleteRequest',
|
||||
'GetPromptRequest',
|
||||
'ListPromptsRequest',
|
||||
'ListResourceTemplatesRequest',
|
||||
'ListResourcesRequest',
|
||||
'ListRootsRequest',
|
||||
'ListToolsRequest',
|
||||
'ReadResourceRequest',
|
||||
'CreateMessageRequest',
|
||||
'ClientRequest',
|
||||
|
||||
// SEP-2322 (MRTR) → PR for MRTR: 2026-07-28 results carry a required `resultType`
|
||||
// discriminator. The SDK base result schema carries `resultType` as an optional
|
||||
// passthrough only (absent means "complete"); per-result modeling lands with MRTR.
|
||||
'Result',
|
||||
'EmptyResult',
|
||||
'PaginatedResult',
|
||||
'CallToolResult',
|
||||
'CompleteResult',
|
||||
'ElicitResult',
|
||||
'GetPromptResult',
|
||||
'ListPromptsResult',
|
||||
'ListResourceTemplatesResult',
|
||||
'ListResourcesResult',
|
||||
'ListRootsResult',
|
||||
'ListToolsResult',
|
||||
'ReadResourceResult',
|
||||
'CreateMessageResult',
|
||||
'ClientResult',
|
||||
'ServerResult',
|
||||
'ResultType',
|
||||
|
||||
// SEP-2549 cacheable results: `ttlMs`/`cacheScope` caching hints on the list/read
|
||||
// result shapes → PR for SEP-2549:
|
||||
'CacheableResult',
|
||||
|
||||
// Response envelopes embedding the changed Result shape → PR for MRTR:
|
||||
'JSONRPCResultResponse',
|
||||
'JSONRPCResponse',
|
||||
'JSONRPCMessage',
|
||||
'CallToolResultResponse',
|
||||
'CompleteResultResponse',
|
||||
'GetPromptResultResponse',
|
||||
'ListPromptsResultResponse',
|
||||
'ListResourceTemplatesResultResponse',
|
||||
'ListResourcesResultResponse',
|
||||
'ListToolsResultResponse',
|
||||
'ReadResourceResultResponse',
|
||||
|
||||
// SEP-2575 sessionless discovery: the SDK ships the wire shapes
|
||||
// (DiscoverRequestSchema / DiscoverResultSchema), but the 2026-07-28 shapes embed the
|
||||
// required `_meta` envelope (request) and required `resultType` (result → MRTR PR),
|
||||
// so they do not match yet; DiscoverResultResponse is a response wrapper (→ MRTR PR):
|
||||
'DiscoverRequest',
|
||||
'DiscoverResult',
|
||||
'DiscoverResultResponse',
|
||||
|
||||
// SEP-2567 input requests/responses (new surface) → PR for MRTR:
|
||||
'InputRequest',
|
||||
'InputRequests',
|
||||
'InputRequiredResult',
|
||||
'InputResponse',
|
||||
'InputResponseRequestParams',
|
||||
'InputResponses',
|
||||
|
||||
// 2026-07-28 subscriptions surface (new) → PR for subscriptions/listen:
|
||||
'SubscriptionFilter',
|
||||
'SubscriptionsAcknowledgedNotification',
|
||||
'SubscriptionsAcknowledgedNotificationParams',
|
||||
'SubscriptionsListenRequest',
|
||||
'SubscriptionsListenRequestParams',
|
||||
|
||||
// New typed protocol errors: the SDK ships -32003/-32004 as ProtocolErrorCode
|
||||
// entries plus the UnsupportedProtocolVersionError class (errors.ts); the spec's
|
||||
// per-code error *response envelope* interfaces are not modeled as wire types:
|
||||
'MissingRequiredClientCapabilityError',
|
||||
'UnsupportedProtocolVersionError',
|
||||
|
||||
// Other shapes changed in the 2026-07-28 schema: sampling content changes (SamplingMessage,
|
||||
// SamplingMessageContentBlock, ToolResultContent) → backchannel PR; open tool
|
||||
// input/output schema typing (Tool); loosened Notification.params (Notification);
|
||||
// server notification union, which gains the subscriptions ack (ServerNotification →
|
||||
// PR for subscriptions/listen):
|
||||
'SamplingMessage',
|
||||
'SamplingMessageContentBlock',
|
||||
'ToolResultContent',
|
||||
'Tool',
|
||||
'Notification',
|
||||
'ServerNotification'
|
||||
];
|
||||
|
||||
function extractExportedTypes(source: string): string[] {
|
||||
const matches = [...source.matchAll(/export\s+(?:interface|class|type)\s+(\w+)\b/g)];
|
||||
return matches.map(m => m[1]!);
|
||||
}
|
||||
|
||||
describe('Spec Types (2026-07-28)', () => {
|
||||
const specTypes = extractExportedTypes(fs.readFileSync(SPEC_TYPES_FILE, 'utf8'));
|
||||
const typesToCheck = specTypes.filter(type => !MISSING_SDK_TYPES_2026_07_28.includes(type));
|
||||
|
||||
it('pins the 2026-07-28 protocol version and the new error codes', () => {
|
||||
expect(LATEST_PROTOCOL_VERSION).toBe('2026-07-28');
|
||||
expect(MISSING_REQUIRED_CLIENT_CAPABILITY).toBe(-32003);
|
||||
expect(UNSUPPORTED_PROTOCOL_VERSION).toBe(-32004);
|
||||
expect(ProtocolErrorCode.MissingRequiredClientCapability).toBe(MISSING_REQUIRED_CLIENT_CAPABILITY);
|
||||
expect(ProtocolErrorCode.UnsupportedProtocolVersion).toBe(UNSUPPORTED_PROTOCOL_VERSION);
|
||||
});
|
||||
|
||||
it('pins the per-request _meta envelope keys to the 2026-07-28 schema', () => {
|
||||
expect(PROTOCOL_VERSION_META_KEY).toBe('io.modelcontextprotocol/protocolVersion');
|
||||
expect(CLIENT_INFO_META_KEY).toBe('io.modelcontextprotocol/clientInfo');
|
||||
expect(CLIENT_CAPABILITIES_META_KEY).toBe('io.modelcontextprotocol/clientCapabilities');
|
||||
expect(LOG_LEVEL_META_KEY).toBe('io.modelcontextprotocol/logLevel');
|
||||
});
|
||||
|
||||
it('should define some expected types', () => {
|
||||
expect(specTypes).toContain('DiscoverRequest');
|
||||
expect(specTypes).toContain('InputRequiredResult');
|
||||
expect(specTypes).toContain('SubscriptionsListenRequest');
|
||||
expect(specTypes).toHaveLength(150);
|
||||
});
|
||||
|
||||
it('should only allowlist types that exist in the 2026-07-28 schema', () => {
|
||||
for (const typeName of MISSING_SDK_TYPES_2026_07_28) {
|
||||
expect(specTypes).toContain(typeName);
|
||||
}
|
||||
});
|
||||
|
||||
it('should have comprehensive compatibility tests', () => {
|
||||
const missingTests = [];
|
||||
|
||||
for (const typeName of typesToCheck) {
|
||||
if (!sdkTypeChecks[typeName as keyof typeof sdkTypeChecks]) {
|
||||
missingTests.push(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
expect(missingTests).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe('Missing SDK Types', () => {
|
||||
it.each(MISSING_SDK_TYPES_2026_07_28)(
|
||||
'%s should not be present in MISSING_SDK_TYPES_2026_07_28 if it has a compatibility test',
|
||||
type => {
|
||||
expect(sdkTypeChecks[type as keyof typeof sdkTypeChecks]).toBeUndefined();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import {
|
||||
CallToolRequestSchema,
|
||||
CallToolResultSchema,
|
||||
CLIENT_CAPABILITIES_META_KEY,
|
||||
CLIENT_INFO_META_KEY,
|
||||
ClientCapabilitiesSchema,
|
||||
ClientRequestSchema,
|
||||
CompleteRequestSchema,
|
||||
|
|
@ -8,10 +10,17 @@ import {
|
|||
CreateMessageRequestSchema,
|
||||
CreateMessageResultSchema,
|
||||
CreateMessageResultWithToolsSchema,
|
||||
DiscoverRequestSchema,
|
||||
DiscoverResultSchema,
|
||||
ElicitRequestFormParamsSchema,
|
||||
EmptyResultSchema,
|
||||
LATEST_PROTOCOL_VERSION,
|
||||
LOG_LEVEL_META_KEY,
|
||||
PromptMessageSchema,
|
||||
PROTOCOL_VERSION_META_KEY,
|
||||
RequestMetaEnvelopeSchema,
|
||||
ResourceLinkSchema,
|
||||
ResultSchema,
|
||||
SamplingMessageSchema,
|
||||
SUPPORTED_PROTOCOL_VERSIONS,
|
||||
ToolChoiceSchema,
|
||||
|
|
@ -1049,3 +1058,117 @@ describe('2025-11-25 task wire interop (task feature removed; wire types remain)
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('2026-07-28 wire shapes', () => {
|
||||
describe('RequestMetaEnvelope', () => {
|
||||
const envelope = {
|
||||
[PROTOCOL_VERSION_META_KEY]: '2026-07-28',
|
||||
[CLIENT_INFO_META_KEY]: { name: 'test-client', version: '1.0.0' },
|
||||
[CLIENT_CAPABILITIES_META_KEY]: {}
|
||||
};
|
||||
|
||||
test('accepts a complete envelope', () => {
|
||||
const result = RequestMetaEnvelopeSchema.safeParse(envelope);
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data[PROTOCOL_VERSION_META_KEY]).toBe('2026-07-28');
|
||||
expect(result.data[CLIENT_INFO_META_KEY]).toEqual({ name: 'test-client', version: '1.0.0' });
|
||||
expect(result.data[CLIENT_CAPABILITIES_META_KEY]).toEqual({});
|
||||
}
|
||||
});
|
||||
|
||||
test('accepts the optional log level, progress token, and unknown keys', () => {
|
||||
const result = RequestMetaEnvelopeSchema.safeParse({
|
||||
...envelope,
|
||||
[LOG_LEVEL_META_KEY]: 'warning',
|
||||
progressToken: 'token-1',
|
||||
'com.example/custom': { anything: true }
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data[LOG_LEVEL_META_KEY]).toBe('warning');
|
||||
expect(result.data.progressToken).toBe('token-1');
|
||||
expect(result.data['com.example/custom']).toEqual({ anything: true });
|
||||
}
|
||||
});
|
||||
|
||||
test.each([PROTOCOL_VERSION_META_KEY, CLIENT_INFO_META_KEY, CLIENT_CAPABILITIES_META_KEY])(
|
||||
'rejects an envelope missing %s',
|
||||
key => {
|
||||
const incomplete: Record<string, unknown> = { ...envelope };
|
||||
delete incomplete[key];
|
||||
expect(RequestMetaEnvelopeSchema.safeParse(incomplete).success).toBe(false);
|
||||
}
|
||||
);
|
||||
|
||||
test('rejects an invalid log level', () => {
|
||||
const result = RequestMetaEnvelopeSchema.safeParse({ ...envelope, [LOG_LEVEL_META_KEY]: 'loud' });
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DiscoverRequest', () => {
|
||||
test('parses a discover request with and without params', () => {
|
||||
expect(DiscoverRequestSchema.safeParse({ method: 'server/discover' }).success).toBe(true);
|
||||
expect(
|
||||
DiscoverRequestSchema.safeParse({
|
||||
method: 'server/discover',
|
||||
params: { _meta: { [PROTOCOL_VERSION_META_KEY]: '2026-07-28' } }
|
||||
}).success
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects other methods', () => {
|
||||
expect(DiscoverRequestSchema.safeParse({ method: 'initialize' }).success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DiscoverResult', () => {
|
||||
const result = {
|
||||
supportedVersions: ['2026-07-28'],
|
||||
capabilities: { tools: { listChanged: true } },
|
||||
serverInfo: { name: 'test-server', version: '1.0.0' }
|
||||
};
|
||||
|
||||
test('parses a discover result', () => {
|
||||
const parsed = DiscoverResultSchema.safeParse({ ...result, resultType: 'complete', instructions: 'Use the echo tool.' });
|
||||
expect(parsed.success).toBe(true);
|
||||
if (parsed.success) {
|
||||
expect(parsed.data.supportedVersions).toEqual(['2026-07-28']);
|
||||
expect(parsed.data.capabilities).toEqual({ tools: { listChanged: true } });
|
||||
expect(parsed.data.serverInfo).toEqual({ name: 'test-server', version: '1.0.0' });
|
||||
expect(parsed.data.instructions).toBe('Use the echo tool.');
|
||||
}
|
||||
});
|
||||
|
||||
test.each(['supportedVersions', 'capabilities', 'serverInfo'])('rejects a discover result missing %s', key => {
|
||||
const incomplete: Record<string, unknown> = { ...result };
|
||||
delete incomplete[key];
|
||||
expect(DiscoverResultSchema.safeParse(incomplete).success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Result resultType passthrough', () => {
|
||||
test('accepts results with and without resultType (absent means "complete")', () => {
|
||||
const withIt = ResultSchema.safeParse({ resultType: 'complete' });
|
||||
expect(withIt.success).toBe(true);
|
||||
if (withIt.success) {
|
||||
expect(withIt.data.resultType).toBe('complete');
|
||||
}
|
||||
const withoutIt = ResultSchema.safeParse({});
|
||||
expect(withoutIt.success).toBe(true);
|
||||
if (withoutIt.success) {
|
||||
expect(withoutIt.data.resultType).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects a non-string resultType', () => {
|
||||
expect(ResultSchema.safeParse({ resultType: 42 }).success).toBe(false);
|
||||
});
|
||||
|
||||
test('EmptyResult accepts resultType but still rejects unknown keys', () => {
|
||||
expect(EmptyResultSchema.safeParse({ resultType: 'complete' }).success).toBe(true);
|
||||
expect(EmptyResultSchema.safeParse({ unexpected: true }).success).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
44
packages/core/test/types/errors.test.ts
Normal file
44
packages/core/test/types/errors.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { ProtocolErrorCode } from '../../src/types/enums.js';
|
||||
import { ProtocolError, UnsupportedProtocolVersionError } from '../../src/types/errors.js';
|
||||
|
||||
describe('UnsupportedProtocolVersionError', () => {
|
||||
const data = { supported: ['2025-11-25', '2025-06-18'], requested: '2026-07-28' };
|
||||
|
||||
it('carries code -32004 and the supported/requested data', () => {
|
||||
const error = new UnsupportedProtocolVersionError(data);
|
||||
expect(error.code).toBe(ProtocolErrorCode.UnsupportedProtocolVersion);
|
||||
expect(error.code).toBe(-32004);
|
||||
expect(error.supported).toEqual(['2025-11-25', '2025-06-18']);
|
||||
expect(error.requested).toBe('2026-07-28');
|
||||
expect(error.data).toEqual(data);
|
||||
});
|
||||
|
||||
it('defaults the message from the requested version', () => {
|
||||
const error = new UnsupportedProtocolVersionError(data);
|
||||
expect(error.message).toBe('Unsupported protocol version: 2026-07-28');
|
||||
const custom = new UnsupportedProtocolVersionError(data, 'try another version');
|
||||
expect(custom.message).toBe('try another version');
|
||||
});
|
||||
|
||||
it('is materialized by ProtocolError.fromError', () => {
|
||||
const error = ProtocolError.fromError(-32004, 'Unsupported protocol version: 2026-07-28', data);
|
||||
expect(error).toBeInstanceOf(UnsupportedProtocolVersionError);
|
||||
if (error instanceof UnsupportedProtocolVersionError) {
|
||||
expect(error.supported).toEqual(['2025-11-25', '2025-06-18']);
|
||||
expect(error.requested).toBe('2026-07-28');
|
||||
}
|
||||
expect(error.message).toBe('Unsupported protocol version: 2026-07-28');
|
||||
});
|
||||
|
||||
it('falls back to a generic ProtocolError when the data is missing or malformed', () => {
|
||||
for (const malformed of [undefined, {}, { supported: 'not-an-array', requested: '2026-07-28' }, { supported: ['2025-11-25'] }]) {
|
||||
const error = ProtocolError.fromError(-32004, 'unsupported', malformed);
|
||||
expect(error).toBeInstanceOf(ProtocolError);
|
||||
expect(error).not.toBeInstanceOf(UnsupportedProtocolVersionError);
|
||||
expect(error.code).toBe(-32004);
|
||||
expect(error.data).toEqual(malformed);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -7,12 +7,32 @@ const __filename = fileURLToPath(import.meta.url);
|
|||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '..');
|
||||
|
||||
/**
|
||||
* The protocol revisions the SDK keeps reference types for:
|
||||
* - `2025-11-25`: the frozen, released schema.
|
||||
* - `2026-07-28`: the upcoming protocol revision.
|
||||
*
|
||||
* Each is written to `packages/core/src/types/spec.types.<version>.ts`.
|
||||
*/
|
||||
const SUPPORTED_VERSIONS = ['2025-11-25', '2026-07-28'] as const;
|
||||
type SpecVersion = (typeof SUPPORTED_VERSIONS)[number];
|
||||
|
||||
/**
|
||||
* Upstream schema directory per revision. Until the 2026-07-28 revision is
|
||||
* published, its schema lives in the spec repository's draft directory; this
|
||||
* mapping drops once `schema/2026-07-28/` exists upstream.
|
||||
*/
|
||||
const UPSTREAM_SCHEMA_DIRS: Record<SpecVersion, string> = {
|
||||
'2025-11-25': '2025-11-25',
|
||||
'2026-07-28': 'draft'
|
||||
};
|
||||
|
||||
interface GitHubCommit {
|
||||
sha: string;
|
||||
}
|
||||
|
||||
async function fetchLatestSHA(): Promise<string> {
|
||||
const url = 'https://api.github.com/repos/modelcontextprotocol/modelcontextprotocol/commits?path=schema/draft/schema.ts&per_page=1';
|
||||
async function fetchLatestSHA(version: SpecVersion): Promise<string> {
|
||||
const url = `https://api.github.com/repos/modelcontextprotocol/modelcontextprotocol/commits?path=schema/${UPSTREAM_SCHEMA_DIRS[version]}/schema.ts&per_page=1`;
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
|
|
@ -27,8 +47,8 @@ async function fetchLatestSHA(): Promise<string> {
|
|||
return commits[0].sha;
|
||||
}
|
||||
|
||||
async function fetchSpecTypes(sha: string): Promise<string> {
|
||||
const url = `https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/${sha}/schema/draft/schema.ts`;
|
||||
async function fetchSpecTypes(version: SpecVersion, sha: string): Promise<string> {
|
||||
const url = `https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/${sha}/schema/${UPSTREAM_SCHEMA_DIRS[version]}/schema.ts`;
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
|
|
@ -38,49 +58,70 @@ async function fetchSpecTypes(sha: string): Promise<string> {
|
|||
return await response.text();
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Check if SHA is provided as command line argument
|
||||
const providedSHA = process.argv[2];
|
||||
async function updateSpecTypes(version: SpecVersion, providedSHA?: string): Promise<void> {
|
||||
let sha: string;
|
||||
if (providedSHA) {
|
||||
console.log(`[${version}] Using provided SHA: ${providedSHA}`);
|
||||
sha = providedSHA;
|
||||
} else {
|
||||
console.log(`[${version}] Fetching latest commit SHA...`);
|
||||
sha = await fetchLatestSHA(version);
|
||||
}
|
||||
|
||||
let latestSHA: string;
|
||||
if (providedSHA) {
|
||||
console.log(`Using provided SHA: ${providedSHA}`);
|
||||
latestSHA = providedSHA;
|
||||
} else {
|
||||
console.log('Fetching latest commit SHA...');
|
||||
latestSHA = await fetchLatestSHA();
|
||||
}
|
||||
console.log(`[${version}] Fetching schema.ts from commit: ${sha}`);
|
||||
|
||||
console.log(`Fetching spec.types.ts from commit: ${latestSHA}`);
|
||||
const specContent = await fetchSpecTypes(version, sha);
|
||||
|
||||
const specContent = await fetchSpecTypes(latestSHA);
|
||||
|
||||
// Read header template
|
||||
const headerTemplate = `/**
|
||||
// Read header template
|
||||
const headerTemplate = `/**
|
||||
* This file is automatically generated from the Model Context Protocol specification.
|
||||
*
|
||||
* Source: https://github.com/modelcontextprotocol/modelcontextprotocol
|
||||
* Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/draft/schema.ts
|
||||
* Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/{SCHEMA_DIR}/schema.ts
|
||||
* Last updated from commit: {SHA}
|
||||
*
|
||||
* DO NOT EDIT THIS FILE MANUALLY. Changes will be overwritten by automated updates.
|
||||
* To update this file, run: pnpm run fetch:spec-types
|
||||
* To update this file, run: pnpm run fetch:spec-types {VERSION}
|
||||
*/`;
|
||||
|
||||
const header = headerTemplate.replace('{SHA}', latestSHA);
|
||||
const header = headerTemplate.replaceAll('{VERSION}', version).replaceAll('{SCHEMA_DIR}', UPSTREAM_SCHEMA_DIRS[version]).replace('{SHA}', sha);
|
||||
|
||||
// Combine header and content
|
||||
const fullContent = header + specContent;
|
||||
// Combine header and content
|
||||
const fullContent = header + specContent;
|
||||
|
||||
// Format with prettier using the project's config so the output passes lint
|
||||
const outputPath = join(PROJECT_ROOT, 'packages', 'core', 'src', 'types', 'spec.types.ts');
|
||||
const prettierConfig = await prettier.resolveConfig(outputPath);
|
||||
const formatted = await prettier.format(fullContent, { ...prettierConfig, filepath: outputPath });
|
||||
// Format with prettier using the project's config so the output passes lint
|
||||
const outputPath = join(PROJECT_ROOT, 'packages', 'core', 'src', 'types', `spec.types.${version}.ts`);
|
||||
const prettierConfig = await prettier.resolveConfig(outputPath);
|
||||
const formatted = await prettier.format(fullContent, { ...prettierConfig, filepath: outputPath });
|
||||
|
||||
writeFileSync(outputPath, formatted, 'utf-8');
|
||||
writeFileSync(outputPath, formatted, 'utf-8');
|
||||
|
||||
console.log('Successfully updated packages/core/src/types/spec.types.ts');
|
||||
console.log(`[${version}] Successfully updated packages/core/src/types/spec.types.${version}.ts`);
|
||||
}
|
||||
|
||||
function isSupportedVersion(value: string): value is SpecVersion {
|
||||
return (SUPPORTED_VERSIONS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Usage: fetch-spec-types.ts [version] [sha]
|
||||
// With no version, all supported versions are fetched at their latest upstream SHA.
|
||||
const providedVersion = process.argv[2];
|
||||
const providedSHA = process.argv[3];
|
||||
|
||||
if (providedVersion === undefined) {
|
||||
for (const version of SUPPORTED_VERSIONS) {
|
||||
await updateSpecTypes(version);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSupportedVersion(providedVersion)) {
|
||||
throw new Error(`Unsupported version "${providedVersion}". Supported versions: ${SUPPORTED_VERSIONS.join(', ')}`);
|
||||
}
|
||||
|
||||
await updateSpecTypes(providedVersion, providedSHA);
|
||||
} catch (error) {
|
||||
console.error('Error:', error instanceof Error ? error.message : String(error));
|
||||
process.exit(1);
|
||||
|
|
|
|||
Loading…
Reference in a new issue