diff --git a/.changeset/sdk-meta-package.md b/.changeset/sdk-meta-package.md new file mode 100644 index 000000000..20d085fbe --- /dev/null +++ b/.changeset/sdk-meta-package.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/sdk': patch +--- + +Add `@modelcontextprotocol/sdk` meta-package: re-exports `@modelcontextprotocol/server` + `client` + `node` and preserves v1 deep-import subpaths (`/types.js`, `/server/mcp.js`, `/client/index.js`, `/shared/transport.js`, `/server/auth/errors.js`, etc.). The package is the recommended primary entry point; the split packages remain available for bundle-conscious consumers. diff --git a/packages/sdk/README.md b/packages/sdk/README.md new file mode 100644 index 000000000..a64d003cb --- /dev/null +++ b/packages/sdk/README.md @@ -0,0 +1,25 @@ +# @modelcontextprotocol/sdk + +The **primary entry point** for the Model Context Protocol TypeScript SDK. + +This meta-package re-exports the full public surface of [`@modelcontextprotocol/server`](../server), [`@modelcontextprotocol/client`](../client), and [`@modelcontextprotocol/node`](../middleware/node), so most applications can depend on this package alone: + +```ts +import { McpServer, Client, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk'; +``` + +## Upgrading from v1 + +`@modelcontextprotocol/sdk` v2 is a drop-in upgrade for most v1 servers — just bump the version. v1 deep-import paths (`@modelcontextprotocol/sdk/types.js`, `/server/mcp.js`, `/client/index.js`, `/shared/transport.js`, etc.) are preserved as compatibility subpaths that re-export +the matching v2 symbols and emit one-time deprecation warnings where the API shape changed. + +See [`docs/migration.md`](../../docs/migration.md) for the full mapping. + +## When to use the sub-packages directly + +Bundle-sensitive targets (browsers, Cloudflare Workers) should import from `@modelcontextprotocol/client` or `@modelcontextprotocol/server` directly to avoid pulling in Node-only transports. + +## Optional subpaths + +The `./server/auth/*` subpaths re-export the legacy Authorization Server helpers from `@modelcontextprotocol/server-auth-legacy`, which require `express` to be installed by the consumer. Similarly, `./server/sse.js` (the deprecated `SSEServerTransport`) is provided by +`@modelcontextprotocol/node`. Both `express` and `hono` are optional peer dependencies — install them only if you use those subpaths. diff --git a/packages/sdk/eslint.config.mjs b/packages/sdk/eslint.config.mjs new file mode 100644 index 000000000..e34a2a51a --- /dev/null +++ b/packages/sdk/eslint.config.mjs @@ -0,0 +1,27 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default [ + ...baseConfig, + { + settings: { + 'import/internal-regex': '^@modelcontextprotocol/' + } + }, + { + // This package is the v1-compat surface; deprecated re-exports are intentional. + // import/no-unresolved: subpaths re-export from sibling packages (server-auth-legacy, + // node/sse, server/zod-schemas) that don't exist on this branch standalone — they + // land via separate PRs in this BC series. Resolves once those merge. + // import/export: types.ts deliberately shadows `export *` names with v1-compat aliases + // (TS spec: named export wins over re-export). + // unicorn/filename-case: validation/ajv-provider.ts etc. match v1 subpath names. + rules: { + '@typescript-eslint/no-deprecated': 'off', + 'import/no-unresolved': 'off', + 'import/export': 'off', + 'unicorn/filename-case': 'off' + } + } +]; diff --git a/packages/sdk/package.json b/packages/sdk/package.json new file mode 100644 index 000000000..fc1aec119 --- /dev/null +++ b/packages/sdk/package.json @@ -0,0 +1,332 @@ +{ + "name": "@modelcontextprotocol/sdk", + "version": "2.0.0-alpha.2", + "description": "Model Context Protocol implementation for TypeScript - Full SDK (re-exports client, server, and node middleware)", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "types": "./dist/index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=20" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs" + }, + "./stdio": { + "types": "./dist/stdio.d.ts", + "import": "./dist/stdio.mjs" + }, + "./types.js": { + "types": "./dist/types.d.ts", + "import": "./dist/types.mjs" + }, + "./types": { + "types": "./dist/types.d.ts", + "import": "./dist/types.mjs" + }, + "./server/index.js": { + "types": "./dist/server/index.d.ts", + "import": "./dist/server/index.mjs" + }, + "./server/index": { + "types": "./dist/server/index.d.ts", + "import": "./dist/server/index.mjs" + }, + "./server/mcp.js": { + "types": "./dist/server/mcp.d.ts", + "import": "./dist/server/mcp.mjs" + }, + "./server/mcp": { + "types": "./dist/server/mcp.d.ts", + "import": "./dist/server/mcp.mjs" + }, + "./server/zod-compat.js": { + "types": "./dist/server/zod-compat.d.ts", + "import": "./dist/server/zod-compat.mjs" + }, + "./server/zod-compat": { + "types": "./dist/server/zod-compat.d.ts", + "import": "./dist/server/zod-compat.mjs" + }, + "./server/stdio.js": { + "types": "./dist/server/stdio.d.ts", + "import": "./dist/server/stdio.mjs" + }, + "./server/stdio": { + "types": "./dist/server/stdio.d.ts", + "import": "./dist/server/stdio.mjs" + }, + "./server/streamableHttp.js": { + "types": "./dist/server/streamableHttp.d.ts", + "import": "./dist/server/streamableHttp.mjs" + }, + "./server/streamableHttp": { + "types": "./dist/server/streamableHttp.d.ts", + "import": "./dist/server/streamableHttp.mjs" + }, + "./server/auth/types.js": { + "types": "./dist/server/auth/types.d.ts", + "import": "./dist/server/auth/types.mjs" + }, + "./server/auth/types": { + "types": "./dist/server/auth/types.d.ts", + "import": "./dist/server/auth/types.mjs" + }, + "./server/auth/errors.js": { + "types": "./dist/server/auth/errors.d.ts", + "import": "./dist/server/auth/errors.mjs" + }, + "./server/auth/errors": { + "types": "./dist/server/auth/errors.d.ts", + "import": "./dist/server/auth/errors.mjs" + }, + "./client": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.mjs" + }, + "./client/index.js": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.mjs" + }, + "./client/index": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.mjs" + }, + "./client/stdio.js": { + "types": "./dist/client/stdio.d.ts", + "import": "./dist/client/stdio.mjs" + }, + "./client/stdio": { + "types": "./dist/client/stdio.d.ts", + "import": "./dist/client/stdio.mjs" + }, + "./client/streamableHttp.js": { + "types": "./dist/client/streamableHttp.d.ts", + "import": "./dist/client/streamableHttp.mjs" + }, + "./client/streamableHttp": { + "types": "./dist/client/streamableHttp.d.ts", + "import": "./dist/client/streamableHttp.mjs" + }, + "./client/sse.js": { + "types": "./dist/client/sse.d.ts", + "import": "./dist/client/sse.mjs" + }, + "./client/sse": { + "types": "./dist/client/sse.d.ts", + "import": "./dist/client/sse.mjs" + }, + "./client/auth.js": { + "types": "./dist/client/auth.d.ts", + "import": "./dist/client/auth.mjs" + }, + "./client/auth": { + "types": "./dist/client/auth.d.ts", + "import": "./dist/client/auth.mjs" + }, + "./shared/protocol.js": { + "types": "./dist/shared/protocol.d.ts", + "import": "./dist/shared/protocol.mjs" + }, + "./shared/protocol": { + "types": "./dist/shared/protocol.d.ts", + "import": "./dist/shared/protocol.mjs" + }, + "./shared/transport.js": { + "types": "./dist/shared/transport.d.ts", + "import": "./dist/shared/transport.mjs" + }, + "./shared/transport": { + "types": "./dist/shared/transport.d.ts", + "import": "./dist/shared/transport.mjs" + }, + "./shared/auth.js": { + "types": "./dist/shared/auth.d.ts", + "import": "./dist/shared/auth.mjs" + }, + "./shared/auth": { + "types": "./dist/shared/auth.d.ts", + "import": "./dist/shared/auth.mjs" + }, + "./server/auth/middleware/bearerAuth.js": { + "types": "./dist/server/auth/middleware/bearerAuth.d.ts", + "import": "./dist/server/auth/middleware/bearerAuth.mjs" + }, + "./server/auth/middleware/bearerAuth": { + "types": "./dist/server/auth/middleware/bearerAuth.d.ts", + "import": "./dist/server/auth/middleware/bearerAuth.mjs" + }, + "./server/auth/router.js": { + "types": "./dist/server/auth/router.d.ts", + "import": "./dist/server/auth/router.mjs" + }, + "./server/auth/router": { + "types": "./dist/server/auth/router.d.ts", + "import": "./dist/server/auth/router.mjs" + }, + "./server/auth/provider.js": { + "types": "./dist/server/auth/provider.d.ts", + "import": "./dist/server/auth/provider.mjs" + }, + "./server/auth/provider": { + "types": "./dist/server/auth/provider.d.ts", + "import": "./dist/server/auth/provider.mjs" + }, + "./server/auth/clients.js": { + "types": "./dist/server/auth/clients.d.ts", + "import": "./dist/server/auth/clients.mjs" + }, + "./server/auth/clients": { + "types": "./dist/server/auth/clients.d.ts", + "import": "./dist/server/auth/clients.mjs" + }, + "./inMemory.js": { + "types": "./dist/inMemory.d.ts", + "import": "./dist/inMemory.mjs" + }, + "./inMemory": { + "types": "./dist/inMemory.d.ts", + "import": "./dist/inMemory.mjs" + }, + "./server/completable.js": { + "types": "./dist/server/completable.d.ts", + "import": "./dist/server/completable.mjs" + }, + "./server/completable": { + "types": "./dist/server/completable.d.ts", + "import": "./dist/server/completable.mjs" + }, + "./server/sse.js": { + "types": "./dist/server/sse.d.ts", + "import": "./dist/server/sse.mjs" + }, + "./server/sse": { + "types": "./dist/server/sse.d.ts", + "import": "./dist/server/sse.mjs" + }, + "./experimental/tasks": { + "types": "./dist/experimental/tasks.d.ts", + "import": "./dist/experimental/tasks.mjs" + }, + "./server": { + "types": "./dist/server/index.d.ts", + "import": "./dist/server/index.mjs" + }, + "./server.js": { + "types": "./dist/server/index.d.ts", + "import": "./dist/server/index.mjs" + }, + "./client.js": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.mjs" + }, + "./server/webStandardStreamableHttp.js": { + "types": "./dist/server/webStandardStreamableHttp.d.ts", + "import": "./dist/server/webStandardStreamableHttp.mjs" + }, + "./server/webStandardStreamableHttp": { + "types": "./dist/server/webStandardStreamableHttp.d.ts", + "import": "./dist/server/webStandardStreamableHttp.mjs" + }, + "./shared/stdio.js": { + "types": "./dist/shared/stdio.d.ts", + "import": "./dist/shared/stdio.mjs" + }, + "./shared/stdio": { + "types": "./dist/shared/stdio.d.ts", + "import": "./dist/shared/stdio.mjs" + }, + "./validation/types.js": { + "types": "./dist/validation/types.d.ts", + "import": "./dist/validation/types.mjs" + }, + "./validation/types": { + "types": "./dist/validation/types.d.ts", + "import": "./dist/validation/types.mjs" + }, + "./validation/cfworker-provider.js": { + "types": "./dist/validation/cfworker-provider.d.ts", + "import": "./dist/validation/cfworker-provider.mjs" + }, + "./validation/cfworker-provider": { + "types": "./dist/validation/cfworker-provider.d.ts", + "import": "./dist/validation/cfworker-provider.mjs" + }, + "./validation/ajv-provider.js": { + "types": "./dist/validation/ajv-provider.d.ts", + "import": "./dist/validation/ajv-provider.mjs" + }, + "./validation/ajv-provider": { + "types": "./dist/validation/ajv-provider.d.ts", + "import": "./dist/validation/ajv-provider.mjs" + } + }, + "files": [ + "dist" + ], + "scripts": { + "typecheck": "tsgo -p tsconfig.json --noEmit", + "build": "tsdown && tsc -p tsconfig.build.json", + "lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .", + "lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .", + "check": "pnpm run typecheck && pnpm run lint", + "test": "vitest run", + "test:watch": "vitest", + "prepack": "pnpm run build" + }, + "dependencies": { + "@modelcontextprotocol/client": "workspace:^", + "@modelcontextprotocol/node": "workspace:^", + "@modelcontextprotocol/server": "workspace:^", + "@modelcontextprotocol/server-auth-legacy": "workspace:^" + }, + "peerDependencies": { + "express": "^4.18.0 || ^5.0.0", + "hono": "*" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + }, + "hono": { + "optional": true + } + }, + "devDependencies": { + "@modelcontextprotocol/core": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@modelcontextprotocol/test-helpers": "workspace:^", + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@typescript/native-preview": "catalog:devTools", + "eslint": "catalog:devTools", + "prettier": "catalog:devTools", + "tsdown": "catalog:devTools", + "typescript": "catalog:devTools", + "vitest": "catalog:devTools", + "zod": "catalog:runtimeShared" + }, + "typesVersions": { + "*": { + "*.js": [ + "dist/*.d.ts" + ], + "*": [ + "dist/*.d.ts", + "dist/*/index.d.ts" + ] + } + } +} diff --git a/packages/sdk/src/client/auth.ts b/packages/sdk/src/client/auth.ts new file mode 100644 index 000000000..55eaaedf6 --- /dev/null +++ b/packages/sdk/src/client/auth.ts @@ -0,0 +1 @@ +export * from '@modelcontextprotocol/client'; diff --git a/packages/sdk/src/client/index.ts b/packages/sdk/src/client/index.ts new file mode 100644 index 000000000..55eaaedf6 --- /dev/null +++ b/packages/sdk/src/client/index.ts @@ -0,0 +1 @@ +export * from '@modelcontextprotocol/client'; diff --git a/packages/sdk/src/client/sse.ts b/packages/sdk/src/client/sse.ts new file mode 100644 index 000000000..de4e3b56e --- /dev/null +++ b/packages/sdk/src/client/sse.ts @@ -0,0 +1 @@ +export { SSEClientTransport, type SSEClientTransportOptions, SseError } from '@modelcontextprotocol/client'; diff --git a/packages/sdk/src/client/stdio.ts b/packages/sdk/src/client/stdio.ts new file mode 100644 index 000000000..456ea8cf1 --- /dev/null +++ b/packages/sdk/src/client/stdio.ts @@ -0,0 +1,2 @@ +export type { StdioServerParameters } from '@modelcontextprotocol/client/stdio'; +export { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment, StdioClientTransport } from '@modelcontextprotocol/client/stdio'; diff --git a/packages/sdk/src/client/streamableHttp.ts b/packages/sdk/src/client/streamableHttp.ts new file mode 100644 index 000000000..0d2d4d14b --- /dev/null +++ b/packages/sdk/src/client/streamableHttp.ts @@ -0,0 +1,7 @@ +export { + type StartSSEOptions, + StreamableHTTPClientTransport, + type StreamableHTTPClientTransportOptions, + StreamableHTTPError, + type StreamableHTTPReconnectionOptions +} from '@modelcontextprotocol/client'; diff --git a/packages/sdk/src/experimental/tasks.ts b/packages/sdk/src/experimental/tasks.ts new file mode 100644 index 000000000..cf883d266 --- /dev/null +++ b/packages/sdk/src/experimental/tasks.ts @@ -0,0 +1,5 @@ +// v1 compat: `@modelcontextprotocol/sdk/experimental/tasks` +// Re-exports the full server surface (task stores, handlers, and related types +// are scattered between core/public and server/experimental/tasks; the root +// barrel includes both). +export * from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/inMemory.ts b/packages/sdk/src/inMemory.ts new file mode 100644 index 000000000..7f2e9c6be --- /dev/null +++ b/packages/sdk/src/inMemory.ts @@ -0,0 +1 @@ +export { InMemoryTransport } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts new file mode 100644 index 000000000..71126956f --- /dev/null +++ b/packages/sdk/src/index.ts @@ -0,0 +1,90 @@ +// Root barrel for @modelcontextprotocol/sdk — the everything package. +// +// Re-exports the full public surface of the server, client, and node packages +// so consumers can `import { McpServer, Client, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk'` +// without choosing a sub-package. +// +// Bundle-sensitive consumers (browser, Workers) should import from +// @modelcontextprotocol/client or @modelcontextprotocol/server directly instead. + +// Server gives us all server-specific exports + the entire core/public surface +// (spec types, error classes, transport interface, constants, guards). +export * from '@modelcontextprotocol/server'; + +// Node middleware — explicit named exports only. Not `export *`, because the +// node package re-exports core types from server and `export *` from both +// packages would collide on overlapping symbols (TS2308). +export { NodeStreamableHTTPServerTransport, type StreamableHTTPServerTransportOptions } from '@modelcontextprotocol/node'; +/** @deprecated Renamed to {@linkcode NodeStreamableHTTPServerTransport}. */ +export { NodeStreamableHTTPServerTransport as StreamableHTTPServerTransport } from '@modelcontextprotocol/node'; + +// Client-specific exports only — NOT `export *`, because client also re-exports +// core/public and the duplicate runtime-value identities (each package bundles +// core separately) trigger TS2308. core/public is already covered by server above. +export type { + AddClientAuthentication, + AssertionCallback, + AuthProvider, + AuthResult, + ClientAuthMethod, + ClientCredentialsProviderOptions, + ClientOptions, + CrossAppAccessContext, + CrossAppAccessProviderOptions, + DiscoverAndRequestJwtAuthGrantOptions, + JwtAuthGrantResult, + LoggingOptions, + Middleware, + OAuthClientProvider, + OAuthDiscoveryState, + OAuthServerInfo, + PrivateKeyJwtProviderOptions, + ReconnectionScheduler, + RequestJwtAuthGrantOptions, + RequestLogger, + SSEClientTransportOptions, + StartSSEOptions, + StaticPrivateKeyJwtProviderOptions, + StreamableHTTPClientTransportOptions, + StreamableHTTPReconnectionOptions +} from '@modelcontextprotocol/client'; +export { + applyMiddlewares, + auth, + buildDiscoveryUrls, + Client, + ClientCredentialsProvider, + createMiddleware, + createPrivateKeyJwtAuth, + CrossAppAccessProvider, + discoverAndRequestJwtAuthGrant, + discoverAuthorizationServerMetadata, + discoverOAuthMetadata, + discoverOAuthProtectedResourceMetadata, + discoverOAuthServerInfo, + exchangeAuthorization, + exchangeJwtAuthGrant, + ExperimentalClientTasks, + extractResourceMetadataUrl, + extractWWWAuthenticateParams, + fetchToken, + getSupportedElicitationModes, + isHttpsUrl, + parseErrorResponse, + prepareAuthorizationCodeRequest, + PrivateKeyJwtProvider, + refreshAuthorization, + registerClient, + requestJwtAuthorizationGrant, + selectClientAuthMethod, + selectResourceURL, + SSEClientTransport, + SseError, + startAuthorization, + StaticPrivateKeyJwtProvider, + StreamableHTTPClientTransport, + UnauthorizedError, + validateClientMetadataUrl, + withLogging, + withOAuth +} from '@modelcontextprotocol/client'; diff --git a/packages/sdk/src/server/auth/clients.ts b/packages/sdk/src/server/auth/clients.ts new file mode 100644 index 000000000..7e5518907 --- /dev/null +++ b/packages/sdk/src/server/auth/clients.ts @@ -0,0 +1,2 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/auth/clients.js` +export * from '@modelcontextprotocol/server-auth-legacy'; diff --git a/packages/sdk/src/server/auth/errors.ts b/packages/sdk/src/server/auth/errors.ts new file mode 100644 index 000000000..5ca4eea12 --- /dev/null +++ b/packages/sdk/src/server/auth/errors.ts @@ -0,0 +1,6 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/auth/errors.js` +// Re-exports the frozen v1 OAuth error classes from the legacy package so that +// errors thrown from this subpath share the same `OAuthError` identity that +// `mcpAuthRouter`/`requireBearerAuth` (re-exported by sibling subpaths) check +// with `instanceof`. +export * from '@modelcontextprotocol/server-auth-legacy'; diff --git a/packages/sdk/src/server/auth/middleware/bearerAuth.ts b/packages/sdk/src/server/auth/middleware/bearerAuth.ts new file mode 100644 index 000000000..104581785 --- /dev/null +++ b/packages/sdk/src/server/auth/middleware/bearerAuth.ts @@ -0,0 +1,5 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js` +// Re-exports from server-auth-legacy (not @modelcontextprotocol/express) so that +// `requireBearerAuth`'s `instanceof OAuthError` check matches the error classes +// re-exported by the sibling `server/auth/*` subpaths. +export * from '@modelcontextprotocol/server-auth-legacy'; diff --git a/packages/sdk/src/server/auth/provider.ts b/packages/sdk/src/server/auth/provider.ts new file mode 100644 index 000000000..c166221f3 --- /dev/null +++ b/packages/sdk/src/server/auth/provider.ts @@ -0,0 +1,2 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/auth/provider.js` +export * from '@modelcontextprotocol/server-auth-legacy'; diff --git a/packages/sdk/src/server/auth/router.ts b/packages/sdk/src/server/auth/router.ts new file mode 100644 index 000000000..12fa9dc7b --- /dev/null +++ b/packages/sdk/src/server/auth/router.ts @@ -0,0 +1,2 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/auth/router.js` +export * from '@modelcontextprotocol/server-auth-legacy'; diff --git a/packages/sdk/src/server/auth/types.ts b/packages/sdk/src/server/auth/types.ts new file mode 100644 index 000000000..11ed919d2 --- /dev/null +++ b/packages/sdk/src/server/auth/types.ts @@ -0,0 +1 @@ +export type { AuthInfo } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/server/completable.ts b/packages/sdk/src/server/completable.ts new file mode 100644 index 000000000..84eee372f --- /dev/null +++ b/packages/sdk/src/server/completable.ts @@ -0,0 +1 @@ +export { completable, type CompletableSchema, type CompleteCallback, isCompletable } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/server/index.ts b/packages/sdk/src/server/index.ts new file mode 100644 index 000000000..6ecbcce01 --- /dev/null +++ b/packages/sdk/src/server/index.ts @@ -0,0 +1 @@ +export * from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/server/mcp.ts b/packages/sdk/src/server/mcp.ts new file mode 100644 index 000000000..5ce074972 --- /dev/null +++ b/packages/sdk/src/server/mcp.ts @@ -0,0 +1,23 @@ +export { + type AnyToolHandler, + type BaseToolCallback, + completable, + type CompletableSchema, + type CompleteCallback, + type CompleteResourceTemplateCallback, + isCompletable, + type LegacyPromptCallback, + type LegacyToolCallback, + type ListResourcesCallback, + McpServer, + type PromptCallback, + type ReadResourceCallback, + type ReadResourceTemplateCallback, + type RegisteredPrompt, + type RegisteredResource, + type RegisteredResourceTemplate, + type RegisteredTool, + type ResourceMetadata, + ResourceTemplate, + type ToolCallback +} from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/server/sse.ts b/packages/sdk/src/server/sse.ts new file mode 100644 index 000000000..1a817e66d --- /dev/null +++ b/packages/sdk/src/server/sse.ts @@ -0,0 +1 @@ +export { SSEServerTransport, type SSEServerTransportOptions } from '@modelcontextprotocol/node/sse'; diff --git a/packages/sdk/src/server/stdio.ts b/packages/sdk/src/server/stdio.ts new file mode 100644 index 000000000..b45cc492d --- /dev/null +++ b/packages/sdk/src/server/stdio.ts @@ -0,0 +1 @@ +export { StdioServerTransport } from '@modelcontextprotocol/server/stdio'; diff --git a/packages/sdk/src/server/streamableHttp.ts b/packages/sdk/src/server/streamableHttp.ts new file mode 100644 index 000000000..4cfda1b20 --- /dev/null +++ b/packages/sdk/src/server/streamableHttp.ts @@ -0,0 +1,4 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/streamableHttp.js` +export * from '@modelcontextprotocol/node'; +/** @deprecated Renamed to {@link NodeStreamableHTTPServerTransport} and moved to `@modelcontextprotocol/node` in v2. */ +export { NodeStreamableHTTPServerTransport as StreamableHTTPServerTransport } from '@modelcontextprotocol/node'; diff --git a/packages/sdk/src/server/webStandardStreamableHttp.ts b/packages/sdk/src/server/webStandardStreamableHttp.ts new file mode 100644 index 000000000..75870a36b --- /dev/null +++ b/packages/sdk/src/server/webStandardStreamableHttp.ts @@ -0,0 +1,4 @@ +export { + WebStandardStreamableHTTPServerTransport, + type WebStandardStreamableHTTPServerTransportOptions +} from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/server/zod-compat.ts b/packages/sdk/src/server/zod-compat.ts new file mode 100644 index 000000000..5486bac0e --- /dev/null +++ b/packages/sdk/src/server/zod-compat.ts @@ -0,0 +1,16 @@ +// v1 compat: `@modelcontextprotocol/sdk/server/zod-compat.js` +// v1 unified Zod v3 + v4 types. v2 is Zod v4-only, so these collapse to the +// v4 types. Prefer `StandardSchemaV1` / `StandardSchemaWithJSON` for new code. + +import type * as z from 'zod'; + +/** @deprecated Use `StandardSchemaV1` (any Standard Schema) or a Zod type directly in v2. */ +export type AnySchema = z.core.$ZodType; + +/** @deprecated Use `Record` directly in v2. */ +export type ZodRawShapeCompat = Record; + +/** @deprecated */ +export type AnyObjectSchema = z.core.$ZodObject | AnySchema; + +export type { StandardSchemaV1, StandardSchemaWithJSON } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/shared/auth.ts b/packages/sdk/src/shared/auth.ts new file mode 100644 index 000000000..3c8b49505 --- /dev/null +++ b/packages/sdk/src/shared/auth.ts @@ -0,0 +1,33 @@ +// v1 compat: `@modelcontextprotocol/sdk/shared/auth.js` +export type { + AuthorizationServerMetadata, + OAuthClientInformation, + OAuthClientInformationFull, + OAuthClientInformationMixed, + OAuthClientMetadata, + OAuthClientRegistrationError, + OAuthErrorResponse, + OAuthMetadata, + OAuthProtectedResourceMetadata, + OAuthTokenRevocationRequest, + OAuthTokens, + OpenIdProviderDiscoveryMetadata, + OpenIdProviderMetadata +} from '@modelcontextprotocol/server'; +export { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/server'; +export { + IdJagTokenExchangeResponseSchema, + OAuthClientInformationFullSchema, + OAuthClientInformationSchema, + OAuthClientMetadataSchema, + OAuthClientRegistrationErrorSchema, + OAuthErrorResponseSchema, + OAuthMetadataSchema, + OAuthProtectedResourceMetadataSchema, + OAuthTokenRevocationRequestSchema, + OAuthTokensSchema, + OpenIdProviderDiscoveryMetadataSchema, + OpenIdProviderMetadataSchema, + OptionalSafeUrlSchema, + SafeUrlSchema +} from '@modelcontextprotocol/server/zod-schemas'; diff --git a/packages/sdk/src/shared/protocol.ts b/packages/sdk/src/shared/protocol.ts new file mode 100644 index 000000000..2667a6389 --- /dev/null +++ b/packages/sdk/src/shared/protocol.ts @@ -0,0 +1,16 @@ +// v1 compat: `@modelcontextprotocol/sdk/shared/protocol.js` + +export type { + BaseContext, + ClientContext, + NotificationOptions, + ProtocolOptions, + ProtocolSpec, + RequestOptions, + ServerContext +} from '@modelcontextprotocol/server'; +export { DEFAULT_REQUEST_TIMEOUT_MSEC, Protocol } from '@modelcontextprotocol/server'; + +/** @deprecated Use {@link ServerContext} (server handlers) or {@link ClientContext} (client handlers) in v2. */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export type RequestHandlerExtra<_ReqT = unknown, _NotifT = unknown> = import('@modelcontextprotocol/server').ServerContext; diff --git a/packages/sdk/src/shared/stdio.ts b/packages/sdk/src/shared/stdio.ts new file mode 100644 index 000000000..87ff5ce32 --- /dev/null +++ b/packages/sdk/src/shared/stdio.ts @@ -0,0 +1 @@ +export { deserializeMessage, ReadBuffer, serializeMessage } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/shared/transport.ts b/packages/sdk/src/shared/transport.ts new file mode 100644 index 000000000..2cee788b9 --- /dev/null +++ b/packages/sdk/src/shared/transport.ts @@ -0,0 +1,2 @@ +export type { FetchLike, Transport, TransportSendOptions } from '@modelcontextprotocol/server'; +export { createFetchWithInit } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/stdio.ts b/packages/sdk/src/stdio.ts new file mode 100644 index 000000000..c5ba37441 --- /dev/null +++ b/packages/sdk/src/stdio.ts @@ -0,0 +1,3 @@ +export type { StdioServerParameters } from '@modelcontextprotocol/client/stdio'; +export { DEFAULT_INHERITED_ENV_VARS, getDefaultEnvironment, StdioClientTransport } from '@modelcontextprotocol/client/stdio'; +export { StdioServerTransport } from '@modelcontextprotocol/server/stdio'; diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts new file mode 100644 index 000000000..42a0f2c78 --- /dev/null +++ b/packages/sdk/src/types.ts @@ -0,0 +1,20 @@ +// v1 compat: `@modelcontextprotocol/sdk/types.js` +// In v1 this was the giant types.ts file with all spec types + Zod schemas. +// v2 dropped the Zod schema constants from the public surface; spec TypeScript +// types are re-exported here from the server package. + +export * from '@modelcontextprotocol/server'; +// v1's types.js also exported the Zod *Schema constants used with +// setRequestHandler/setNotificationHandler. v2 moved those to a separate +// subpath; re-export them here for v1-compat. +export * from '@modelcontextprotocol/server/zod-schemas'; +/** + * @deprecated Use {@link ResourceTemplateType}. + * + * v1's `types.js` exported the spec-derived ResourceTemplate data type under + * this name. v2 renamed it to `ResourceTemplateType` to avoid clashing with the + * `ResourceTemplate` helper class exported by `@modelcontextprotocol/server`. + * This alias lives only in the meta-package compat subpath; exporting it from + * core/public causes tsdown to mark server's class as type-only in bundled .d.mts. + */ +export type { ResourceTemplateType as ResourceTemplate } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/validation/ajv-provider.ts b/packages/sdk/src/validation/ajv-provider.ts new file mode 100644 index 000000000..8f6e0f51e --- /dev/null +++ b/packages/sdk/src/validation/ajv-provider.ts @@ -0,0 +1 @@ +export { AjvJsonSchemaValidator } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/src/validation/cfworker-provider.ts b/packages/sdk/src/validation/cfworker-provider.ts new file mode 100644 index 000000000..08b23bf34 --- /dev/null +++ b/packages/sdk/src/validation/cfworker-provider.ts @@ -0,0 +1 @@ +export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker'; diff --git a/packages/sdk/src/validation/types.ts b/packages/sdk/src/validation/types.ts new file mode 100644 index 000000000..a696f02bd --- /dev/null +++ b/packages/sdk/src/validation/types.ts @@ -0,0 +1,2 @@ +export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from '@modelcontextprotocol/server'; +export { AjvJsonSchemaValidator, fromJsonSchema } from '@modelcontextprotocol/server'; diff --git a/packages/sdk/test/compat.test.ts b/packages/sdk/test/compat.test.ts new file mode 100644 index 000000000..b15098468 --- /dev/null +++ b/packages/sdk/test/compat.test.ts @@ -0,0 +1,93 @@ +import { afterEach, beforeEach, describe, expect, it, vi, type MockInstance } from 'vitest'; +import { z } from 'zod'; + +// Exercise the v1 deep-import subpaths. +import { McpError, ErrorCode, type CallToolRequest } from '../src/types.js'; +import { Server } from '../src/server/index.js'; +import { Client } from '../src/client/index.js'; +import { McpServer } from '../src/server/mcp.js'; +import { InvalidTokenError, OAuthError as LegacyOAuthError } from '../src/server/auth/errors.js'; +import { StreamableHTTPServerTransport } from '../src/server/streamableHttp.js'; +import type { Transport } from '../src/shared/transport.js'; +import type { RequestHandlerExtra } from '../src/shared/protocol.js'; +import { ProtocolError } from '../src/index.js'; + +describe('@modelcontextprotocol/sdk meta-package', () => { + let warnSpy: MockInstance; + + beforeEach(() => { + warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + warnSpy.mockRestore(); + }); + + it('re-exports v1 deep-import subpaths', () => { + // ./types.js — McpError/ErrorCode aliases + const err = new McpError(ErrorCode.InvalidParams, 'x'); + expect(err).toBeInstanceOf(ProtocolError); + + // ./server/mcp.js + expect(typeof McpServer).toBe('function'); + + // ./server/auth/errors.js — v1 OAuth subclasses (legacy hierarchy, shared with sibling auth subpaths) + const tokenErr = new InvalidTokenError('bad'); + expect(tokenErr).toBeInstanceOf(LegacyOAuthError); + expect(tokenErr.errorCode).toBe('invalid_token'); + + // ./server/streamableHttp.js — alias to NodeStreamableHTTPServerTransport + expect(typeof StreamableHTTPServerTransport).toBe('function'); + + // ./shared/transport.js + ./shared/protocol.js — type-only re-exports compile + const _t: Transport | undefined = undefined; + const _ctx: RequestHandlerExtra | undefined = undefined; + const _req: CallToolRequest | undefined = undefined; + void _t; + void _ctx; + void _req; + }); + + describe('Server.setRequestHandler (Zod-schema form)', () => { + it('accepts a Zod request schema and registers by extracted method (first-class, no warning)', () => { + const server = new Server({ name: 't', version: '1' }, { capabilities: { tools: {} } }); + const ListToolsRequestSchema = z.object({ method: z.literal('tools/list') }); + + server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: [] })); + + expect(warnSpy).not.toHaveBeenCalled(); + expect(() => server.assertCanSetRequestHandler('tools/list')).toThrow(); + }); + + it('accepts the v2 string-method form without warning', () => { + const server = new Server({ name: 't', version: '1' }, { capabilities: { tools: {} } }); + server.setRequestHandler('tools/list', () => ({ tools: [] })); + expect(warnSpy).not.toHaveBeenCalled(); + }); + }); + + describe('McpServer.server reaches the schema-arg overload', () => { + it('accepts a Zod request schema on .server.setRequestHandler (no warning)', () => { + const mcp = new McpServer({ name: 't', version: '1' }, { capabilities: { resources: {} } }); + const ListResourcesRequestSchema = z.object({ method: z.literal('resources/list') }); + + mcp.server.setRequestHandler(ListResourcesRequestSchema, () => ({ resources: [] })); + + expect(warnSpy).not.toHaveBeenCalled(); + expect(() => mcp.server.assertCanSetRequestHandler('resources/list')).toThrow(); + expect(mcp.server).toBeInstanceOf(Server); + }); + }); + + describe('Client.request (result-schema form)', () => { + it('accepts (req, ResultSchema, opts) call shape (first-class, no warning)', async () => { + const client = new Client({ name: 't', version: '1' }); + const ResultSchema = z.object({}); + + // Not connected — rejects, but the call shape is accepted at the type/dispatch level. + await expect(client.request({ method: 'ping' }, ResultSchema, { timeout: 10 })).rejects.toThrow(); + + expect(warnSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/sdk/tsconfig.build.json b/packages/sdk/tsconfig.build.json new file mode 100644 index 000000000..ad0d8e637 --- /dev/null +++ b/packages/sdk/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist", + "rootDir": "src", + "incremental": false, + "paths": {} + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json new file mode 100644 index 000000000..5a30e6c18 --- /dev/null +++ b/packages/sdk/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "paths": { + "*": ["./*"], + "@modelcontextprotocol/core": ["./node_modules/@modelcontextprotocol/core/src/index.ts"], + "@modelcontextprotocol/core/public": ["./node_modules/@modelcontextprotocol/core/src/exports/public/index.ts"], + "@modelcontextprotocol/client": ["./node_modules/@modelcontextprotocol/client/src/index.ts"], + "@modelcontextprotocol/client/stdio": ["./node_modules/@modelcontextprotocol/client/src/client/stdio.ts"], + "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], + "@modelcontextprotocol/server/stdio": ["./node_modules/@modelcontextprotocol/server/src/server/stdio.ts"], + "@modelcontextprotocol/server/zod-schemas": ["./node_modules/@modelcontextprotocol/server/src/zodSchemas.ts"], + "@modelcontextprotocol/server/validators/cf-worker": ["./node_modules/@modelcontextprotocol/server/src/validators/cfWorker.ts"], + "@modelcontextprotocol/node": ["./node_modules/@modelcontextprotocol/node/src/index.ts"], + "@modelcontextprotocol/node/sse": ["./node_modules/@modelcontextprotocol/node/src/sse.ts"], + "@modelcontextprotocol/server-auth-legacy": ["./node_modules/@modelcontextprotocol/server-auth-legacy/src/index.ts"], + "@modelcontextprotocol/client/_shims": ["./node_modules/@modelcontextprotocol/client/src/shimsNode.ts"], + "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], + "@modelcontextprotocol/test-helpers": ["./node_modules/@modelcontextprotocol/test-helpers/src/index.ts"] + } + } +} diff --git a/packages/sdk/tsdown.config.ts b/packages/sdk/tsdown.config.ts new file mode 100644 index 000000000..8c6595654 --- /dev/null +++ b/packages/sdk/tsdown.config.ts @@ -0,0 +1,46 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + failOnWarn: false, + entry: [ + 'src/index.ts', + 'src/stdio.ts', + 'src/types.ts', + 'src/inMemory.ts', + 'src/experimental/tasks.ts', + 'src/server/index.ts', + 'src/server/mcp.ts', + 'src/server/zod-compat.ts', + 'src/server/completable.ts', + 'src/server/sse.ts', + 'src/server/stdio.ts', + 'src/server/streamableHttp.ts', + 'src/server/auth/types.ts', + 'src/server/auth/errors.ts', + 'src/server/auth/middleware/bearerAuth.ts', + 'src/server/auth/router.ts', + 'src/server/auth/provider.ts', + 'src/server/auth/clients.ts', + 'src/client/index.ts', + 'src/client/stdio.ts', + 'src/client/streamableHttp.ts', + 'src/client/sse.ts', + 'src/client/auth.ts', + 'src/shared/protocol.ts', + 'src/shared/transport.ts', + 'src/shared/auth.ts', + 'src/shared/stdio.ts', + 'src/server/webStandardStreamableHttp.ts', + 'src/validation/types.ts', + 'src/validation/cfworker-provider.ts', + 'src/validation/ajv-provider.ts' + ], + format: ['esm'], + outDir: 'dist', + clean: true, + sourcemap: true, + target: 'esnext', + platform: 'node', + dts: false, + external: [/^@modelcontextprotocol\//] +}); diff --git a/packages/sdk/vitest.config.js b/packages/sdk/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/sdk/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d63c27f7f..f89e9bef8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -257,7 +257,7 @@ importers: version: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.4) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) + version: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) eslint-plugin-n: specifier: catalog:devTools version: 17.24.0(eslint@9.39.4)(typescript@5.9.3) @@ -889,6 +889,64 @@ importers: specifier: catalog:devTools version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(vite@7.3.0(@types/node@25.5.0)(tsx@4.21.0)(yaml@2.8.3)) + packages/sdk: + dependencies: + '@modelcontextprotocol/client': + specifier: workspace:^ + version: link:../client + '@modelcontextprotocol/node': + specifier: workspace:^ + version: link:../middleware/node + '@modelcontextprotocol/server': + specifier: workspace:^ + version: link:../server + '@modelcontextprotocol/server-auth-legacy': + specifier: workspace:^ + version: link:../server-auth-legacy + express: + specifier: ^4.18.0 || ^5.0.0 + version: 5.2.1 + hono: + specifier: '*' + version: 4.12.9 + devDependencies: + '@modelcontextprotocol/core': + specifier: workspace:^ + version: link:../core + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/test-helpers': + specifier: workspace:^ + version: link:../../test/helpers + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + '@typescript/native-preview': + specifier: catalog:devTools + version: 7.0.0-dev.20260327.2 + eslint: + specifier: catalog:devTools + version: 9.39.4 + prettier: + specifier: catalog:devTools + version: 3.6.2 + tsdown: + specifier: catalog:devTools + version: 0.18.4(@typescript/native-preview@7.0.0-dev.20260327.2)(typescript@5.9.3) + typescript: + specifier: catalog:devTools + version: 5.9.3 + vitest: + specifier: catalog:devTools + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(vite@7.3.0(@types/node@25.5.0)(tsx@4.21.0)(yaml@2.8.3)) + zod: + specifier: catalog:runtimeShared + version: 4.3.6 + packages/server: dependencies: zod: @@ -1115,9 +1173,15 @@ importers: '@modelcontextprotocol/node': specifier: workspace:^ version: link:../../packages/middleware/node + '@modelcontextprotocol/sdk': + specifier: workspace:^ + version: link:../../packages/sdk '@modelcontextprotocol/server': specifier: workspace:^ version: link:../../packages/server + '@modelcontextprotocol/server-auth-legacy': + specifier: workspace:^ + version: link:../../packages/server-auth-legacy '@modelcontextprotocol/test-helpers': specifier: workspace:^ version: link:../helpers @@ -7177,14 +7241,15 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4): dependencies: debug: 3.2.7 optionalDependencies: + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.4) @@ -7198,7 +7263,7 @@ snapshots: eslint: 9.39.4 eslint-compat-utils: 0.5.1(eslint@9.39.4) - eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7209,7 +7274,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.4) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -7220,6 +7285,8 @@ snapshots: semver: 6.3.1 string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack diff --git a/test/integration/package.json b/test/integration/package.json index 8618d0580..62757d1e5 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -40,7 +40,9 @@ "@modelcontextprotocol/eslint-config": "workspace:^", "@modelcontextprotocol/express": "workspace:^", "@modelcontextprotocol/node": "workspace:^", + "@modelcontextprotocol/sdk": "workspace:^", "@modelcontextprotocol/server": "workspace:^", + "@modelcontextprotocol/server-auth-legacy": "workspace:^", "@modelcontextprotocol/test-helpers": "workspace:^", "@modelcontextprotocol/tsconfig": "workspace:^", "@modelcontextprotocol/vitest-config": "workspace:^", diff --git a/test/integration/test/compat/v1Surface.test.ts b/test/integration/test/compat/v1Surface.test.ts new file mode 100644 index 000000000..e002621f2 --- /dev/null +++ b/test/integration/test/compat/v1Surface.test.ts @@ -0,0 +1,120 @@ +/* eslint-disable import/no-unresolved -- + This test's purpose is to import from `@modelcontextprotocol/sdk/...` v1 subpaths. + eslint can't resolve them until the sdk package is built; tsconfig `paths` covers TS. */ +/** + * v1 API surface compat test. + * + * Every import in this file uses a v1 deep-import path under + * `@modelcontextprotocol/sdk/...`. The fact that it typechecks and runs IS the + * primary assertion: a v1 consumer can bump `@modelcontextprotocol/sdk` to + * 2.x and keep their existing imports and call shapes. + * + * Covers (by BC track): + * - D1 meta-package subpath re-exports (every import below) + * - C2 McpServer.tool() variadic + * - C4 registerTool raw-shape inputSchema + * - C5 flat ctx.* getters + RequestHandlerExtra type alias + * - C7 McpError/ErrorCode/JSONRPCError/StreamableHTTPError aliases + * - C8 StreamableHTTPServerTransport alias (from /node) + * - C10 *RequestSchema constants in sdk/types.js + OAuth schemas in shared/auth.js + * - A1 setRequestHandler(ZodSchema, h) + callTool(params, ResultSchema) + */ +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { OAuthTokensSchema } from '@modelcontextprotocol/sdk/shared/auth.js'; +import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js'; +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; +import type { CallToolResult, JSONRPCError } from '@modelcontextprotocol/sdk/types.js'; +import { + CallToolRequestSchema, + CallToolResultSchema, + ErrorCode, + LATEST_PROTOCOL_VERSION, + ListToolsRequestSchema, + McpError, + StreamableHTTPError +} from '@modelcontextprotocol/sdk/types.js'; +import { describe, expect, it, vi } from 'vitest'; +import { z } from 'zod'; + +void StdioServerTransport; // type-level: import resolves +const _t: Transport | undefined = undefined; +void _t; + +describe('v1 API surface (bump-only compat)', () => { + it('McpServer.tool() variadic + raw-shape + InMemory roundtrip + callTool(_, ResultSchema)', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const server = new McpServer({ name: 't', version: '1.0.0' }); + // C2 variadic + C4 raw-shape (object of ZodTypes, not z.object) + server.tool('echo', { msg: z.string() }, async ({ msg }) => ({ + content: [{ type: 'text', text: msg }] + })); + + const [clientT, serverT] = InMemoryTransport.createLinkedPair(); + const client = new Client({ name: 'c', version: '1.0.0' }); + await Promise.all([server.connect(serverT), client.connect(clientT)]); + + // A1: callTool(params, ResultSchema) overload (first-class, no warning) + const result = (await client.callTool({ name: 'echo', arguments: { msg: 'hi' } }, CallToolResultSchema)) as CallToolResult; + expect(result.content[0]).toEqual({ type: 'text', text: 'hi' }); + warn.mockRestore(); + await Promise.all([client.close(), server.close()]); + }); + + it('low-level Server.setRequestHandler(ZodSchema, h) + flat ctx.* getters', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const server = new Server({ name: 't', version: '1.0.0' }, { capabilities: { tools: {} } }); + let sawExtra: RequestHandlerExtra | undefined; + // A1: deprecated schema-arg form + server.setRequestHandler(ListToolsRequestSchema, async (_req, extra) => { + sawExtra = extra; + // C5: flat getters + expect(extra.signal).toBeInstanceOf(AbortSignal); + expect(typeof extra.requestId === 'number' || typeof extra.requestId === 'string').toBe(true); + expect(typeof extra.sendNotification).toBe('function'); + expect(typeof extra.sendRequest).toBe('function'); + return { tools: [] }; + }); + server.setRequestHandler(CallToolRequestSchema, async () => ({ content: [] })); + + const [clientT, serverT] = InMemoryTransport.createLinkedPair(); + const client = new Client({ name: 'c', version: '1.0.0' }); + await Promise.all([server.connect(serverT), client.connect(clientT)]); + const tools = await client.listTools(); + expect(tools.tools).toEqual([]); + expect(sawExtra).toBeDefined(); + warn.mockRestore(); + await Promise.all([client.close(), server.close()]); + }); + + it('McpError/ErrorCode/JSONRPCError/StreamableHTTPError aliases', () => { + const e = new McpError(ErrorCode.InvalidParams, 'x'); + expect(e.code).toBe(ErrorCode.InvalidParams); + // C7: ConnectionClosed/RequestTimeout shimmed onto ErrorCode + expect(ErrorCode.ConnectionClosed).toBeDefined(); + expect(ErrorCode.RequestTimeout).toBeDefined(); + const httpErr = new StreamableHTTPError(404, 'nf'); + expect(httpErr).toBeInstanceOf(Error); + // JSONRPCError is a type alias — assignable to the v2 shape + const _je: JSONRPCError = { jsonrpc: '2.0', id: 1, error: { code: -32_600, message: 'x' } }; + void _je; + }); + + it('OAuth Zod schemas available for runtime parse (shared/auth.js)', () => { + const parsed = OAuthTokensSchema.safeParse({ access_token: 'x', token_type: 'Bearer' }); + expect(parsed.success).toBe(true); + }); + + it('extensionless subpath imports resolve (claude-ai pattern)', async () => { + const types = await import('@modelcontextprotocol/sdk/types'); + expect(types.LATEST_PROTOCOL_VERSION).toBe(LATEST_PROTOCOL_VERSION); + }); + + it('StreamableHTTPServerTransport alias available from /node-style import', async () => { + const node = await import('@modelcontextprotocol/sdk/server/streamableHttp.js'); + expect(node.StreamableHTTPServerTransport).toBeDefined(); + }); +}); diff --git a/test/integration/tsconfig.json b/test/integration/tsconfig.json index 210bb0111..347032187 100644 --- a/test/integration/tsconfig.json +++ b/test/integration/tsconfig.json @@ -13,6 +13,13 @@ "@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"], "@modelcontextprotocol/server/stdio": ["./node_modules/@modelcontextprotocol/server/src/stdio.ts"], "@modelcontextprotocol/server/_shims": ["./node_modules/@modelcontextprotocol/server/src/shimsNode.ts"], + "@modelcontextprotocol/server/zod-schemas": ["./node_modules/@modelcontextprotocol/server/src/zodSchemas.ts"], + "@modelcontextprotocol/server/validators/cf-worker": ["./node_modules/@modelcontextprotocol/server/src/validators/cfWorker.ts"], + "@modelcontextprotocol/server-auth-legacy": ["./node_modules/@modelcontextprotocol/server-auth-legacy/src/index.ts"], + "@modelcontextprotocol/node/sse": ["./node_modules/@modelcontextprotocol/node/src/sse.ts"], + "@modelcontextprotocol/sdk": ["./node_modules/@modelcontextprotocol/sdk/src/index.ts"], + "@modelcontextprotocol/sdk/*.js": ["./node_modules/@modelcontextprotocol/sdk/src/*.ts"], + "@modelcontextprotocol/sdk/*": ["./node_modules/@modelcontextprotocol/sdk/src/*.ts"], "@modelcontextprotocol/express": ["./node_modules/@modelcontextprotocol/express/src/index.ts"], "@modelcontextprotocol/node": ["./node_modules/@modelcontextprotocol/node/src/index.ts"], "@modelcontextprotocol/vitest-config": ["./node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"], diff --git a/typedoc.config.mjs b/typedoc.config.mjs index f2a4e50f5..a3709f24b 100644 --- a/typedoc.config.mjs +++ b/typedoc.config.mjs @@ -14,7 +14,12 @@ const packages = packageJsonPaths.map(p => { return { rootDir, manifest }; }); -const publicPackages = packages.filter(p => p.manifest.private !== true); +// `sdk` is a pure re-export meta-package; its docs are the underlying packages'. +// Re-exported symbols' inherited `{@link}` JSDoc resolves in the source package's +// module structure, not the re-exporting package's, so including it here yields +// spurious link warnings without adding any documentation value. +const TYPEDOC_EXCLUDED = new Set(['@modelcontextprotocol/sdk']); +const publicPackages = packages.filter(p => p.manifest.private !== true && !TYPEDOC_EXCLUDED.has(p.manifest.name)); const entryPoints = publicPackages.map(p => p.rootDir); console.log(