v2: Errors refactor (ProtocolError, SdkError, OAuthError) (#1454)
This commit is contained in:
parent
160902eb2e
commit
0f0a4eb7c8
2 changed files with 1086 additions and 705 deletions
|
|
@ -20,13 +20,13 @@ Remove the old package and install only what you need:
|
|||
npm uninstall @modelcontextprotocol/sdk
|
||||
```
|
||||
|
||||
| You need | Install |
|
||||
|----------|---------|
|
||||
| Client only | `npm install @modelcontextprotocol/client` |
|
||||
| Server only | `npm install @modelcontextprotocol/server` |
|
||||
| Server + Node.js HTTP | `npm install @modelcontextprotocol/server @modelcontextprotocol/node` |
|
||||
| Server + Express | `npm install @modelcontextprotocol/server @modelcontextprotocol/express` |
|
||||
| Server + Hono | `npm install @modelcontextprotocol/server @modelcontextprotocol/hono` |
|
||||
| You need | Install |
|
||||
| --------------------- | ------------------------------------------------------------------------ |
|
||||
| Client only | `npm install @modelcontextprotocol/client` |
|
||||
| Server only | `npm install @modelcontextprotocol/server` |
|
||||
| Server + Node.js HTTP | `npm install @modelcontextprotocol/server @modelcontextprotocol/node` |
|
||||
| Server + Express | `npm install @modelcontextprotocol/server @modelcontextprotocol/express` |
|
||||
| Server + Hono | `npm install @modelcontextprotocol/server @modelcontextprotocol/hono` |
|
||||
|
||||
`@modelcontextprotocol/core` is installed automatically as a dependency.
|
||||
|
||||
|
|
@ -36,65 +36,175 @@ Replace all `@modelcontextprotocol/sdk/...` imports using this table.
|
|||
|
||||
### Client imports
|
||||
|
||||
| v1 import path | v2 package |
|
||||
|----------------|------------|
|
||||
| `@modelcontextprotocol/sdk/client/index.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/auth.js` | `@modelcontextprotocol/client` |
|
||||
| v1 import path | v2 package |
|
||||
| ---------------------------------------------------- | ------------------------------ |
|
||||
| `@modelcontextprotocol/sdk/client/index.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/auth.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/streamableHttp.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/sse.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/stdio.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/websocket.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/sse.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/stdio.js` | `@modelcontextprotocol/client` |
|
||||
| `@modelcontextprotocol/sdk/client/websocket.js` | `@modelcontextprotocol/client` |
|
||||
|
||||
### Server imports
|
||||
|
||||
| v1 import path | v2 package |
|
||||
|----------------|------------|
|
||||
| `@modelcontextprotocol/sdk/server/mcp.js` | `@modelcontextprotocol/server` |
|
||||
| `@modelcontextprotocol/sdk/server/index.js` | `@modelcontextprotocol/server` |
|
||||
| `@modelcontextprotocol/sdk/server/stdio.js` | `@modelcontextprotocol/server` |
|
||||
| v1 import path | v2 package |
|
||||
| ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `@modelcontextprotocol/sdk/server/mcp.js` | `@modelcontextprotocol/server` |
|
||||
| `@modelcontextprotocol/sdk/server/index.js` | `@modelcontextprotocol/server` |
|
||||
| `@modelcontextprotocol/sdk/server/stdio.js` | `@modelcontextprotocol/server` |
|
||||
| `@modelcontextprotocol/sdk/server/streamableHttp.js` | `@modelcontextprotocol/node` (class renamed to `NodeStreamableHTTPServerTransport`) |
|
||||
| `@modelcontextprotocol/sdk/server/sse.js` | REMOVED (migrate to Streamable HTTP) |
|
||||
| `@modelcontextprotocol/sdk/server/auth/*` | REMOVED (use external auth library) |
|
||||
| `@modelcontextprotocol/sdk/server/middleware.js` | `@modelcontextprotocol/express` (signature changed, see section 8) |
|
||||
| `@modelcontextprotocol/sdk/server/sse.js` | REMOVED (migrate to Streamable HTTP) |
|
||||
| `@modelcontextprotocol/sdk/server/auth/*` | REMOVED (use external auth library) |
|
||||
| `@modelcontextprotocol/sdk/server/middleware.js` | `@modelcontextprotocol/express` (signature changed, see section 8) |
|
||||
|
||||
### Types / shared imports
|
||||
|
||||
| v1 import path | v2 package |
|
||||
|----------------|------------|
|
||||
| `@modelcontextprotocol/sdk/types.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/protocol.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/transport.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/stdio.js` | `@modelcontextprotocol/core` |
|
||||
| v1 import path | v2 package |
|
||||
| ------------------------------------------------- | ---------------------------- |
|
||||
| `@modelcontextprotocol/sdk/types.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/protocol.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/transport.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/stdio.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/uriTemplate.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/auth.js` | `@modelcontextprotocol/core` |
|
||||
| `@modelcontextprotocol/sdk/shared/auth.js` | `@modelcontextprotocol/core` |
|
||||
|
||||
Notes:
|
||||
|
||||
- `@modelcontextprotocol/client` and `@modelcontextprotocol/server` both re-export everything from `@modelcontextprotocol/core`, so you can import types from whichever package you already depend on.
|
||||
- When multiple v1 imports map to the same v2 package, consolidate them into a single import statement.
|
||||
- If code imports from `sdk/client/...`, install `@modelcontextprotocol/client`. If from `sdk/server/...`, install `@modelcontextprotocol/server`. If from `sdk/types.js` or `sdk/shared/...` only, install `@modelcontextprotocol/core`.
|
||||
|
||||
## 4. Renamed Symbols
|
||||
|
||||
| v1 symbol | v2 symbol | v2 package |
|
||||
|-----------|-----------|------------|
|
||||
| v1 symbol | v2 symbol | v2 package |
|
||||
| ------------------------------- | ----------------------------------- | ---------------------------- |
|
||||
| `StreamableHTTPServerTransport` | `NodeStreamableHTTPServerTransport` | `@modelcontextprotocol/node` |
|
||||
|
||||
## 5. Removed / Renamed Type Aliases and Symbols
|
||||
|
||||
| v1 (removed) | v2 (replacement) |
|
||||
|--------------|------------------|
|
||||
| `JSONRPCError` | `JSONRPCErrorResponse` |
|
||||
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
|
||||
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
|
||||
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
|
||||
| `ResourceReference` | `ResourceTemplateReference` |
|
||||
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
|
||||
| `IsomorphicHeaders` | REMOVED (use Web Standard `Headers`) |
|
||||
| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now in `@modelcontextprotocol/core`) |
|
||||
| v1 (removed) | v2 (replacement) |
|
||||
| ---------------------------------------- | -------------------------------------------------------- |
|
||||
| `JSONRPCError` | `JSONRPCErrorResponse` |
|
||||
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
|
||||
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
|
||||
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
|
||||
| `ResourceReference` | `ResourceTemplateReference` |
|
||||
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
|
||||
| `IsomorphicHeaders` | REMOVED (use Web Standard `Headers`) |
|
||||
| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now in `@modelcontextprotocol/core`) |
|
||||
| `McpError` | `ProtocolError` |
|
||||
| `ErrorCode` | `ProtocolErrorCode` |
|
||||
| `ErrorCode.RequestTimeout` | `SdkErrorCode.RequestTimeout` |
|
||||
| `ErrorCode.ConnectionClosed` | `SdkErrorCode.ConnectionClosed` |
|
||||
| `StreamableHTTPError` | REMOVED (use `SdkError` with `SdkErrorCode.ClientHttp*`) |
|
||||
|
||||
All other symbols from `@modelcontextprotocol/sdk/types.js` retain their original names (e.g., `CallToolResultSchema`, `ListToolsResultSchema`, etc.).
|
||||
|
||||
**Unchanged APIs** (only import paths changed): `Client` constructor and methods, `McpServer` constructor, `server.connect()`, `server.close()`, all client transports (`StreamableHTTPClientTransport`, `SSEClientTransport`, `StdioClientTransport`), `StdioServerTransport`, all Zod schemas, all callback return types.
|
||||
### Error class changes
|
||||
|
||||
Two error classes now exist:
|
||||
|
||||
- **`ProtocolError`** (renamed from `McpError`): Protocol errors that cross the wire as JSON-RPC responses
|
||||
- **`SdkError`** (new): Local SDK errors that never cross the wire
|
||||
|
||||
| Error scenario | v1 type | v2 type |
|
||||
| -------------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| Request timeout | `McpError` with `ErrorCode.RequestTimeout` | `SdkError` with `SdkErrorCode.RequestTimeout` |
|
||||
| Connection closed | `McpError` with `ErrorCode.ConnectionClosed` | `SdkError` with `SdkErrorCode.ConnectionClosed` |
|
||||
| Capability not supported | `new Error(...)` | `SdkError` with `SdkErrorCode.CapabilityNotSupported` |
|
||||
| Not connected | `new Error('Not connected')` | `SdkError` with `SdkErrorCode.NotConnected` |
|
||||
| Invalid params (server response) | `McpError` with `ErrorCode.InvalidParams` | `ProtocolError` with `ProtocolErrorCode.InvalidParams` |
|
||||
| HTTP transport error | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttp*` |
|
||||
| Failed to open SSE stream | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttpFailedToOpenStream` |
|
||||
| 401 after auth flow | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttpAuthentication` |
|
||||
| 403 after upscoping | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttpForbidden` |
|
||||
| Unexpected content type | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttpUnexpectedContent` |
|
||||
| Session termination failed | `StreamableHTTPError` | `SdkError` with `SdkErrorCode.ClientHttpFailedToTerminateSession` |
|
||||
|
||||
New `SdkErrorCode` enum values:
|
||||
|
||||
- `SdkErrorCode.NotConnected` = `'NOT_CONNECTED'`
|
||||
- `SdkErrorCode.AlreadyConnected` = `'ALREADY_CONNECTED'`
|
||||
- `SdkErrorCode.NotInitialized` = `'NOT_INITIALIZED'`
|
||||
- `SdkErrorCode.CapabilityNotSupported` = `'CAPABILITY_NOT_SUPPORTED'`
|
||||
- `SdkErrorCode.RequestTimeout` = `'REQUEST_TIMEOUT'`
|
||||
- `SdkErrorCode.ConnectionClosed` = `'CONNECTION_CLOSED'`
|
||||
- `SdkErrorCode.SendFailed` = `'SEND_FAILED'`
|
||||
- `SdkErrorCode.ClientHttpNotImplemented` = `'CLIENT_HTTP_NOT_IMPLEMENTED'`
|
||||
- `SdkErrorCode.ClientHttpAuthentication` = `'CLIENT_HTTP_AUTHENTICATION'`
|
||||
- `SdkErrorCode.ClientHttpForbidden` = `'CLIENT_HTTP_FORBIDDEN'`
|
||||
- `SdkErrorCode.ClientHttpUnexpectedContent` = `'CLIENT_HTTP_UNEXPECTED_CONTENT'`
|
||||
- `SdkErrorCode.ClientHttpFailedToOpenStream` = `'CLIENT_HTTP_FAILED_TO_OPEN_STREAM'`
|
||||
- `SdkErrorCode.ClientHttpFailedToTerminateSession` = `'CLIENT_HTTP_FAILED_TO_TERMINATE_SESSION'`
|
||||
|
||||
Update error handling:
|
||||
|
||||
```typescript
|
||||
// v1
|
||||
if (error instanceof McpError && error.code === ErrorCode.RequestTimeout) { ... }
|
||||
|
||||
// v2
|
||||
import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core';
|
||||
if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) { ... }
|
||||
```
|
||||
|
||||
Update HTTP transport error handling:
|
||||
|
||||
```typescript
|
||||
// v1
|
||||
import { StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
||||
if (error instanceof StreamableHTTPError) {
|
||||
console.log('HTTP status:', error.code);
|
||||
}
|
||||
|
||||
// v2
|
||||
import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core';
|
||||
if (error instanceof SdkError && error.code === SdkErrorCode.ClientHttpFailedToOpenStream) {
|
||||
const status = (error.data as { status?: number })?.status;
|
||||
}
|
||||
```
|
||||
|
||||
### OAuth error consolidation
|
||||
|
||||
Individual OAuth error classes replaced with single `OAuthError` class and `OAuthErrorCode` enum:
|
||||
|
||||
| v1 Class | v2 Equivalent |
|
||||
| ------------------------------ | ---------------------------------------------------------- |
|
||||
| `InvalidRequestError` | `OAuthError` with `OAuthErrorCode.InvalidRequest` |
|
||||
| `InvalidClientError` | `OAuthError` with `OAuthErrorCode.InvalidClient` |
|
||||
| `InvalidGrantError` | `OAuthError` with `OAuthErrorCode.InvalidGrant` |
|
||||
| `UnauthorizedClientError` | `OAuthError` with `OAuthErrorCode.UnauthorizedClient` |
|
||||
| `UnsupportedGrantTypeError` | `OAuthError` with `OAuthErrorCode.UnsupportedGrantType` |
|
||||
| `InvalidScopeError` | `OAuthError` with `OAuthErrorCode.InvalidScope` |
|
||||
| `AccessDeniedError` | `OAuthError` with `OAuthErrorCode.AccessDenied` |
|
||||
| `ServerError` | `OAuthError` with `OAuthErrorCode.ServerError` |
|
||||
| `TemporarilyUnavailableError` | `OAuthError` with `OAuthErrorCode.TemporarilyUnavailable` |
|
||||
| `UnsupportedResponseTypeError` | `OAuthError` with `OAuthErrorCode.UnsupportedResponseType` |
|
||||
| `UnsupportedTokenTypeError` | `OAuthError` with `OAuthErrorCode.UnsupportedTokenType` |
|
||||
| `InvalidTokenError` | `OAuthError` with `OAuthErrorCode.InvalidToken` |
|
||||
| `MethodNotAllowedError` | `OAuthError` with `OAuthErrorCode.MethodNotAllowed` |
|
||||
| `TooManyRequestsError` | `OAuthError` with `OAuthErrorCode.TooManyRequests` |
|
||||
| `InvalidClientMetadataError` | `OAuthError` with `OAuthErrorCode.InvalidClientMetadata` |
|
||||
| `InsufficientScopeError` | `OAuthError` with `OAuthErrorCode.InsufficientScope` |
|
||||
| `InvalidTargetError` | `OAuthError` with `OAuthErrorCode.InvalidTarget` |
|
||||
| `CustomOAuthError` | `new OAuthError(customCode, message)` |
|
||||
|
||||
Removed: `OAUTH_ERRORS` constant.
|
||||
|
||||
Update OAuth error handling:
|
||||
|
||||
```typescript
|
||||
// v1
|
||||
import { InvalidClientError, InvalidGrantError } from '@modelcontextprotocol/core';
|
||||
if (error instanceof InvalidClientError) { ... }
|
||||
|
||||
// v2
|
||||
import { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/core';
|
||||
if (error instanceof OAuthError && error.code === OAuthErrorCode.InvalidClient) { ... }
|
||||
```
|
||||
|
||||
**Unchanged APIs** (only import paths changed): `Client` constructor and methods, `McpServer` constructor, `server.connect()`, `server.close()`, all client transports (`StreamableHTTPClientTransport`, `SSEClientTransport`, `StdioClientTransport`), `StdioServerTransport`, all Zod
|
||||
schemas, all callback return types.
|
||||
|
||||
## 6. McpServer API Changes
|
||||
|
||||
|
|
@ -105,21 +215,25 @@ The variadic `.tool()`, `.prompt()`, `.resource()` methods are removed. Use the
|
|||
```typescript
|
||||
// v1: server.tool(name, schema, callback)
|
||||
server.tool('greet', { name: z.string() }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// v1: server.tool(name, description, schema, callback)
|
||||
server.tool('greet', 'Greet a user', { name: z.string() }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// v2: server.registerTool(name, config, callback)
|
||||
server.registerTool('greet', {
|
||||
description: 'Greet a user',
|
||||
inputSchema: { name: z.string() },
|
||||
}, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
server.registerTool(
|
||||
'greet',
|
||||
{
|
||||
description: 'Greet a user',
|
||||
inputSchema: { name: z.string() }
|
||||
},
|
||||
async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`, `annotations?`, `_meta?`
|
||||
|
|
@ -129,15 +243,19 @@ Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`,
|
|||
```typescript
|
||||
// v1: server.prompt(name, schema, callback)
|
||||
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
});
|
||||
|
||||
// v2: server.registerPrompt(name, config, callback)
|
||||
server.registerPrompt('summarize', {
|
||||
argsSchema: { text: z.string() },
|
||||
}, async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
});
|
||||
server.registerPrompt(
|
||||
'summarize',
|
||||
{
|
||||
argsSchema: { text: z.string() }
|
||||
},
|
||||
async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Config object fields: `title?`, `description?`, `argsSchema?`
|
||||
|
|
@ -146,13 +264,13 @@ Config object fields: `title?`, `description?`, `argsSchema?`
|
|||
|
||||
```typescript
|
||||
// v1: server.resource(name, uri, callback)
|
||||
server.resource('config', 'config://app', async (uri) => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
server.resource('config', 'config://app', async uri => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
});
|
||||
|
||||
// v2: server.registerResource(name, uri, metadata, callback)
|
||||
server.registerResource('config', 'config://app', {}, async (uri) => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
server.registerResource('config', 'config://app', {}, async uri => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -180,7 +298,8 @@ extra.requestInfo?.headers.get('mcp-session-id')
|
|||
|
||||
### Server-side auth
|
||||
|
||||
All server OAuth exports removed: `mcpAuthRouter`, `OAuthServerProvider`, `OAuthTokenVerifier`, `requireBearerAuth`, `authenticateClient`, `ProxyOAuthServerProvider`, `allowedMethods`, and associated types. Use an external auth library (e.g., `better-auth`). See `examples/server/src/` for demos.
|
||||
All server OAuth exports removed: `mcpAuthRouter`, `OAuthServerProvider`, `OAuthTokenVerifier`, `requireBearerAuth`, `authenticateClient`, `ProxyOAuthServerProvider`, `allowedMethods`, and associated types. Use an external auth library (e.g., `better-auth`). See
|
||||
`examples/server/src/` for demos.
|
||||
|
||||
### Host header validation (Express)
|
||||
|
||||
|
|
@ -214,26 +333,26 @@ server.setNotificationHandler('notifications/message', (notification) => { ... }
|
|||
|
||||
Schema to method string mapping:
|
||||
|
||||
| v1 Schema | v2 Method String |
|
||||
|-----------|-----------------|
|
||||
| `InitializeRequestSchema` | `'initialize'` |
|
||||
| `CallToolRequestSchema` | `'tools/call'` |
|
||||
| `ListToolsRequestSchema` | `'tools/list'` |
|
||||
| `ListPromptsRequestSchema` | `'prompts/list'` |
|
||||
| `GetPromptRequestSchema` | `'prompts/get'` |
|
||||
| `ListResourcesRequestSchema` | `'resources/list'` |
|
||||
| `ReadResourceRequestSchema` | `'resources/read'` |
|
||||
| `CreateMessageRequestSchema` | `'sampling/createMessage'` |
|
||||
| `ElicitRequestSchema` | `'elicitation/create'` |
|
||||
| `SetLevelRequestSchema` | `'logging/setLevel'` |
|
||||
| `PingRequestSchema` | `'ping'` |
|
||||
| `LoggingMessageNotificationSchema` | `'notifications/message'` |
|
||||
| `ToolListChangedNotificationSchema` | `'notifications/tools/list_changed'` |
|
||||
| v1 Schema | v2 Method String |
|
||||
| --------------------------------------- | ---------------------------------------- |
|
||||
| `InitializeRequestSchema` | `'initialize'` |
|
||||
| `CallToolRequestSchema` | `'tools/call'` |
|
||||
| `ListToolsRequestSchema` | `'tools/list'` |
|
||||
| `ListPromptsRequestSchema` | `'prompts/list'` |
|
||||
| `GetPromptRequestSchema` | `'prompts/get'` |
|
||||
| `ListResourcesRequestSchema` | `'resources/list'` |
|
||||
| `ReadResourceRequestSchema` | `'resources/read'` |
|
||||
| `CreateMessageRequestSchema` | `'sampling/createMessage'` |
|
||||
| `ElicitRequestSchema` | `'elicitation/create'` |
|
||||
| `SetLevelRequestSchema` | `'logging/setLevel'` |
|
||||
| `PingRequestSchema` | `'ping'` |
|
||||
| `LoggingMessageNotificationSchema` | `'notifications/message'` |
|
||||
| `ToolListChangedNotificationSchema` | `'notifications/tools/list_changed'` |
|
||||
| `ResourceListChangedNotificationSchema` | `'notifications/resources/list_changed'` |
|
||||
| `PromptListChangedNotificationSchema` | `'notifications/prompts/list_changed'` |
|
||||
| `ProgressNotificationSchema` | `'notifications/progress'` |
|
||||
| `CancelledNotificationSchema` | `'notifications/cancelled'` |
|
||||
| `InitializedNotificationSchema` | `'notifications/initialized'` |
|
||||
| `PromptListChangedNotificationSchema` | `'notifications/prompts/list_changed'` |
|
||||
| `ProgressNotificationSchema` | `'notifications/progress'` |
|
||||
| `CancelledNotificationSchema` | `'notifications/cancelled'` |
|
||||
| `InitializedNotificationSchema` | `'notifications/initialized'` |
|
||||
|
||||
Request/notification params remain fully typed. Remove unused schema imports after migration.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ This guide covers the breaking changes introduced in v2 of the MCP TypeScript SD
|
|||
|
||||
## Overview
|
||||
|
||||
Version 2 of the MCP TypeScript SDK introduces several breaking changes to improve modularity, reduce dependency bloat, and provide a cleaner API surface. The biggest change is the split from a single `@modelcontextprotocol/sdk` package into separate `@modelcontextprotocol/core`, `@modelcontextprotocol/client`, and `@modelcontextprotocol/server` packages.
|
||||
Version 2 of the MCP TypeScript SDK introduces several breaking changes to improve modularity, reduce dependency bloat, and provide a cleaner API surface. The biggest change is the split from a single `@modelcontextprotocol/sdk` package into separate `@modelcontextprotocol/core`,
|
||||
`@modelcontextprotocol/client`, and `@modelcontextprotocol/server` packages.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
|
|
@ -12,11 +13,11 @@ Version 2 of the MCP TypeScript SDK introduces several breaking changes to impro
|
|||
|
||||
The single `@modelcontextprotocol/sdk` package has been split into three packages:
|
||||
|
||||
| v1 | v2 |
|
||||
|----|-----|
|
||||
| v1 | v2 |
|
||||
| --------------------------- | ---------------------------------------------------------- |
|
||||
| `@modelcontextprotocol/sdk` | `@modelcontextprotocol/core` (types, protocol, transports) |
|
||||
| | `@modelcontextprotocol/client` (client implementation) |
|
||||
| | `@modelcontextprotocol/server` (server implementation) |
|
||||
| | `@modelcontextprotocol/client` (client implementation) |
|
||||
| | `@modelcontextprotocol/server` (server implementation) |
|
||||
|
||||
Remove the old package and install only the packages you need:
|
||||
|
||||
|
|
@ -64,6 +65,7 @@ Note: `@modelcontextprotocol/client` and `@modelcontextprotocol/server` both re-
|
|||
v2 requires **Node.js 20+** and ships **ESM only** (no more CommonJS builds).
|
||||
|
||||
If your project uses CommonJS (`require()`), you will need to either:
|
||||
|
||||
- Migrate to ESM (`import`/`export`)
|
||||
- Use dynamic `import()` to load the SDK
|
||||
|
||||
|
|
@ -71,11 +73,11 @@ If your project uses CommonJS (`require()`), you will need to either:
|
|||
|
||||
The server package no longer depends on Express or Hono. HTTP framework integrations are now separate middleware packages:
|
||||
|
||||
| v1 | v2 |
|
||||
|----|-----|
|
||||
| v1 | v2 |
|
||||
| -------------------------------------- | ------------------------------------------- |
|
||||
| Built into `@modelcontextprotocol/sdk` | `@modelcontextprotocol/node` (Node.js HTTP) |
|
||||
| | `@modelcontextprotocol/express` (Express) |
|
||||
| | `@modelcontextprotocol/hono` (Hono) |
|
||||
| | `@modelcontextprotocol/express` (Express) |
|
||||
| | `@modelcontextprotocol/hono` (Hono) |
|
||||
|
||||
Install the middleware package for your framework:
|
||||
|
||||
|
|
@ -128,12 +130,12 @@ This affects both transport constructors and request handler code that reads hea
|
|||
```typescript
|
||||
// Transport headers
|
||||
const transport = new StreamableHTTPClientTransport(url, {
|
||||
requestInit: {
|
||||
headers: {
|
||||
'Authorization': 'Bearer token',
|
||||
'X-Custom': 'value',
|
||||
},
|
||||
},
|
||||
requestInit: {
|
||||
headers: {
|
||||
Authorization: 'Bearer token',
|
||||
'X-Custom': 'value'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Reading headers in a request handler
|
||||
|
|
@ -145,12 +147,12 @@ const sessionId = extra.requestInfo?.headers['mcp-session-id'];
|
|||
```typescript
|
||||
// Transport headers
|
||||
const transport = new StreamableHTTPClientTransport(url, {
|
||||
requestInit: {
|
||||
headers: new Headers({
|
||||
'Authorization': 'Bearer token',
|
||||
'X-Custom': 'value',
|
||||
}),
|
||||
},
|
||||
requestInit: {
|
||||
headers: new Headers({
|
||||
Authorization: 'Bearer token',
|
||||
'X-Custom': 'value'
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Reading headers in a request handler
|
||||
|
|
@ -170,22 +172,22 @@ const server = new McpServer({ name: 'demo', version: '1.0.0' });
|
|||
|
||||
// Tool with schema
|
||||
server.tool('greet', { name: z.string() }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// Tool with description
|
||||
server.tool('greet', 'Greet a user', { name: z.string() }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// Prompt
|
||||
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
|
||||
});
|
||||
|
||||
// Resource
|
||||
server.resource('config', 'config://app', async (uri) => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
server.resource('config', 'config://app', async uri => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -198,28 +200,29 @@ const server = new McpServer({ name: 'demo', version: '1.0.0' });
|
|||
|
||||
// Tool with schema
|
||||
server.registerTool('greet', { inputSchema: { name: z.string() } }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// Tool with description
|
||||
server.registerTool('greet', { description: 'Greet a user', inputSchema: { name: z.string() } }, async ({ name }) => {
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
|
||||
});
|
||||
|
||||
// Prompt
|
||||
server.registerPrompt('summarize', { argsSchema: { text: z.string() } }, async ({ text }) => {
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
|
||||
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
|
||||
});
|
||||
|
||||
// Resource
|
||||
server.registerResource('config', 'config://app', {}, async (uri) => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
server.registerResource('config', 'config://app', {}, async uri => {
|
||||
return { contents: [{ uri: uri.href, text: '{}' }] };
|
||||
});
|
||||
```
|
||||
|
||||
### Host header validation moved
|
||||
|
||||
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`, `hostHeaderValidationResponse()`.
|
||||
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`,
|
||||
`hostHeaderValidationResponse()`.
|
||||
|
||||
**Before (v1):**
|
||||
|
||||
|
|
@ -249,13 +252,13 @@ import { Server, InitializeRequestSchema, LoggingMessageNotificationSchema } fro
|
|||
const server = new Server({ name: 'my-server', version: '1.0.0' });
|
||||
|
||||
// Request handler with schema
|
||||
server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
||||
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
|
||||
server.setRequestHandler(InitializeRequestSchema, async request => {
|
||||
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
|
||||
});
|
||||
|
||||
// Notification handler with schema
|
||||
server.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
|
||||
console.log(notification.params.data);
|
||||
server.setNotificationHandler(LoggingMessageNotificationSchema, notification => {
|
||||
console.log(notification.params.data);
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -267,13 +270,13 @@ import { Server } from '@modelcontextprotocol/server';
|
|||
const server = new Server({ name: 'my-server', version: '1.0.0' });
|
||||
|
||||
// Request handler with method string
|
||||
server.setRequestHandler('initialize', async (request) => {
|
||||
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
|
||||
server.setRequestHandler('initialize', async request => {
|
||||
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
|
||||
});
|
||||
|
||||
// Notification handler with method string
|
||||
server.setNotificationHandler('notifications/message', (notification) => {
|
||||
console.log(notification.params.data);
|
||||
server.setNotificationHandler('notifications/message', notification => {
|
||||
console.log(notification.params.data);
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -281,21 +284,21 @@ The request and notification parameters remain fully typed via `RequestTypeMap`
|
|||
|
||||
Common method string replacements:
|
||||
|
||||
| Schema (v1) | Method string (v2) |
|
||||
|-------------|-------------------|
|
||||
| `InitializeRequestSchema` | `'initialize'` |
|
||||
| `CallToolRequestSchema` | `'tools/call'` |
|
||||
| `ListToolsRequestSchema` | `'tools/list'` |
|
||||
| `ListPromptsRequestSchema` | `'prompts/list'` |
|
||||
| `GetPromptRequestSchema` | `'prompts/get'` |
|
||||
| `ListResourcesRequestSchema` | `'resources/list'` |
|
||||
| `ReadResourceRequestSchema` | `'resources/read'` |
|
||||
| `CreateMessageRequestSchema` | `'sampling/createMessage'` |
|
||||
| `ElicitRequestSchema` | `'elicitation/create'` |
|
||||
| `LoggingMessageNotificationSchema` | `'notifications/message'` |
|
||||
| `ToolListChangedNotificationSchema` | `'notifications/tools/list_changed'` |
|
||||
| Schema (v1) | Method string (v2) |
|
||||
| --------------------------------------- | ---------------------------------------- |
|
||||
| `InitializeRequestSchema` | `'initialize'` |
|
||||
| `CallToolRequestSchema` | `'tools/call'` |
|
||||
| `ListToolsRequestSchema` | `'tools/list'` |
|
||||
| `ListPromptsRequestSchema` | `'prompts/list'` |
|
||||
| `GetPromptRequestSchema` | `'prompts/get'` |
|
||||
| `ListResourcesRequestSchema` | `'resources/list'` |
|
||||
| `ReadResourceRequestSchema` | `'resources/read'` |
|
||||
| `CreateMessageRequestSchema` | `'sampling/createMessage'` |
|
||||
| `ElicitRequestSchema` | `'elicitation/create'` |
|
||||
| `LoggingMessageNotificationSchema` | `'notifications/message'` |
|
||||
| `ToolListChangedNotificationSchema` | `'notifications/tools/list_changed'` |
|
||||
| `ResourceListChangedNotificationSchema` | `'notifications/resources/list_changed'` |
|
||||
| `PromptListChangedNotificationSchema` | `'notifications/prompts/list_changed'` |
|
||||
| `PromptListChangedNotificationSchema` | `'notifications/prompts/list_changed'` |
|
||||
|
||||
### Client list methods return empty results for missing capabilities
|
||||
|
||||
|
|
@ -304,24 +307,27 @@ Common method string replacements:
|
|||
To restore v1 behavior (throw an error when capabilities are missing), set `enforceStrictCapabilities: true`:
|
||||
|
||||
```typescript
|
||||
const client = new Client({ name: 'my-client', version: '1.0.0' }, {
|
||||
enforceStrictCapabilities: true,
|
||||
});
|
||||
const client = new Client(
|
||||
{ name: 'my-client', version: '1.0.0' },
|
||||
{
|
||||
enforceStrictCapabilities: true
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Removed type aliases and deprecated exports
|
||||
|
||||
The following deprecated type aliases have been removed from `@modelcontextprotocol/core`:
|
||||
|
||||
| Removed | Replacement |
|
||||
|---------|-------------|
|
||||
| `JSONRPCError` | `JSONRPCErrorResponse` |
|
||||
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
|
||||
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
|
||||
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
|
||||
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
|
||||
| `ResourceReference` | `ResourceTemplateReference` |
|
||||
| `IsomorphicHeaders` | Use Web Standard `Headers` |
|
||||
| Removed | Replacement |
|
||||
| ---------------------------------------- | ------------------------------------------------ |
|
||||
| `JSONRPCError` | `JSONRPCErrorResponse` |
|
||||
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
|
||||
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
|
||||
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
|
||||
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
|
||||
| `ResourceReference` | `ResourceTemplateReference` |
|
||||
| `IsomorphicHeaders` | Use Web Standard `Headers` |
|
||||
| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now in `@modelcontextprotocol/core`) |
|
||||
|
||||
All other types and schemas exported from `@modelcontextprotocol/sdk/types.js` retain their original names in `@modelcontextprotocol/core`.
|
||||
|
|
@ -338,6 +344,208 @@ import { JSONRPCError, ResourceReference, isJSONRPCError } from '@modelcontextpr
|
|||
import { JSONRPCErrorResponse, ResourceTemplateReference, isJSONRPCErrorResponse } from '@modelcontextprotocol/core';
|
||||
```
|
||||
|
||||
### Error hierarchy refactoring
|
||||
|
||||
The SDK now distinguishes between two types of errors:
|
||||
|
||||
1. **`ProtocolError`** (renamed from `McpError`): Protocol errors that cross the wire as JSON-RPC error responses
|
||||
2. **`SdkError`**: Local SDK errors that never cross the wire (timeouts, connection issues, capability checks)
|
||||
|
||||
#### Renamed exports
|
||||
|
||||
| v1 | v2 |
|
||||
| ---------------------------- | ------------------------------- |
|
||||
| `McpError` | `ProtocolError` |
|
||||
| `ErrorCode` | `ProtocolErrorCode` |
|
||||
| `ErrorCode.RequestTimeout` | `SdkErrorCode.RequestTimeout` |
|
||||
| `ErrorCode.ConnectionClosed` | `SdkErrorCode.ConnectionClosed` |
|
||||
|
||||
**Before (v1):**
|
||||
|
||||
```typescript
|
||||
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
try {
|
||||
await client.callTool({ name: 'test', arguments: {} });
|
||||
} catch (error) {
|
||||
if (error instanceof McpError && error.code === ErrorCode.RequestTimeout) {
|
||||
console.log('Request timed out');
|
||||
}
|
||||
if (error instanceof McpError && error.code === ErrorCode.InvalidParams) {
|
||||
console.log('Invalid parameters');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After (v2):**
|
||||
|
||||
```typescript
|
||||
import { ProtocolError, ProtocolErrorCode, SdkError, SdkErrorCode } from '@modelcontextprotocol/core';
|
||||
|
||||
try {
|
||||
await client.callTool({ name: 'test', arguments: {} });
|
||||
} catch (error) {
|
||||
// Local timeout/connection errors are now SdkError
|
||||
if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) {
|
||||
console.log('Request timed out');
|
||||
}
|
||||
// Protocol errors from the server are still ProtocolError
|
||||
if (error instanceof ProtocolError && error.code === ProtocolErrorCode.InvalidParams) {
|
||||
console.log('Invalid parameters');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### New `SdkErrorCode` enum
|
||||
|
||||
The new `SdkErrorCode` enum contains string-valued codes for local SDK errors:
|
||||
|
||||
| Code | Description |
|
||||
| ------------------------------------------------- | ------------------------------------------ |
|
||||
| `SdkErrorCode.NotConnected` | Transport is not connected |
|
||||
| `SdkErrorCode.AlreadyConnected` | Transport is already connected |
|
||||
| `SdkErrorCode.NotInitialized` | Protocol is not initialized |
|
||||
| `SdkErrorCode.CapabilityNotSupported` | Required capability is not supported |
|
||||
| `SdkErrorCode.RequestTimeout` | Request timed out waiting for response |
|
||||
| `SdkErrorCode.ConnectionClosed` | Connection was closed |
|
||||
| `SdkErrorCode.SendFailed` | Failed to send message |
|
||||
| `SdkErrorCode.ClientHttpNotImplemented` | HTTP POST request failed |
|
||||
| `SdkErrorCode.ClientHttpAuthentication` | Server returned 401 after successful auth |
|
||||
| `SdkErrorCode.ClientHttpForbidden` | Server returned 403 after trying upscoping |
|
||||
| `SdkErrorCode.ClientHttpUnexpectedContent` | Unexpected content type in HTTP response |
|
||||
| `SdkErrorCode.ClientHttpFailedToOpenStream` | Failed to open SSE stream |
|
||||
| `SdkErrorCode.ClientHttpFailedToTerminateSession` | Failed to terminate session |
|
||||
|
||||
#### `StreamableHTTPError` removed
|
||||
|
||||
The `StreamableHTTPError` class has been removed. HTTP transport errors are now thrown as `SdkError` with specific `SdkErrorCode` values that provide more granular error information:
|
||||
|
||||
**Before (v1):**
|
||||
|
||||
```typescript
|
||||
import { StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
||||
|
||||
try {
|
||||
await transport.send(message);
|
||||
} catch (error) {
|
||||
if (error instanceof StreamableHTTPError) {
|
||||
console.log('HTTP error:', error.code); // HTTP status code
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After (v2):**
|
||||
|
||||
```typescript
|
||||
import { SdkError, SdkErrorCode } from '@modelcontextprotocol/core';
|
||||
|
||||
try {
|
||||
await transport.send(message);
|
||||
} catch (error) {
|
||||
if (error instanceof SdkError) {
|
||||
switch (error.code) {
|
||||
case SdkErrorCode.ClientHttpAuthentication:
|
||||
console.log('Auth failed after completing auth flow');
|
||||
break;
|
||||
case SdkErrorCode.ClientHttpForbidden:
|
||||
console.log('Forbidden after upscoping attempt');
|
||||
break;
|
||||
case SdkErrorCode.ClientHttpFailedToOpenStream:
|
||||
console.log('Failed to open SSE stream');
|
||||
break;
|
||||
case SdkErrorCode.ClientHttpNotImplemented:
|
||||
console.log('HTTP request failed');
|
||||
break;
|
||||
}
|
||||
// Access HTTP status code from error.data if needed
|
||||
const httpStatus = (error.data as { status?: number })?.status;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Why this change?
|
||||
|
||||
Previously, `ErrorCode.RequestTimeout` (-32001) and `ErrorCode.ConnectionClosed` (-32000) were used for local timeout/connection errors. However, these errors never cross the wire as JSON-RPC responses - they are rejected locally. Using protocol error codes for local errors was
|
||||
semantically inconsistent.
|
||||
|
||||
The new design:
|
||||
|
||||
- `ProtocolError` with `ProtocolErrorCode`: For errors that are serialized and sent as JSON-RPC error responses
|
||||
- `SdkError` with `SdkErrorCode`: For local errors that are thrown/rejected locally and never leave the SDK
|
||||
|
||||
### OAuth error refactoring
|
||||
|
||||
The OAuth error classes have been consolidated into a single `OAuthError` class with an `OAuthErrorCode` enum.
|
||||
|
||||
#### Removed classes
|
||||
|
||||
The following individual error classes have been removed in favor of `OAuthError` with the appropriate code:
|
||||
|
||||
| v1 Class | v2 Equivalent |
|
||||
| ------------------------------ | ----------------------------------------------------------------- |
|
||||
| `InvalidRequestError` | `new OAuthError(OAuthErrorCode.InvalidRequest, message)` |
|
||||
| `InvalidClientError` | `new OAuthError(OAuthErrorCode.InvalidClient, message)` |
|
||||
| `InvalidGrantError` | `new OAuthError(OAuthErrorCode.InvalidGrant, message)` |
|
||||
| `UnauthorizedClientError` | `new OAuthError(OAuthErrorCode.UnauthorizedClient, message)` |
|
||||
| `UnsupportedGrantTypeError` | `new OAuthError(OAuthErrorCode.UnsupportedGrantType, message)` |
|
||||
| `InvalidScopeError` | `new OAuthError(OAuthErrorCode.InvalidScope, message)` |
|
||||
| `AccessDeniedError` | `new OAuthError(OAuthErrorCode.AccessDenied, message)` |
|
||||
| `ServerError` | `new OAuthError(OAuthErrorCode.ServerError, message)` |
|
||||
| `TemporarilyUnavailableError` | `new OAuthError(OAuthErrorCode.TemporarilyUnavailable, message)` |
|
||||
| `UnsupportedResponseTypeError` | `new OAuthError(OAuthErrorCode.UnsupportedResponseType, message)` |
|
||||
| `UnsupportedTokenTypeError` | `new OAuthError(OAuthErrorCode.UnsupportedTokenType, message)` |
|
||||
| `InvalidTokenError` | `new OAuthError(OAuthErrorCode.InvalidToken, message)` |
|
||||
| `MethodNotAllowedError` | `new OAuthError(OAuthErrorCode.MethodNotAllowed, message)` |
|
||||
| `TooManyRequestsError` | `new OAuthError(OAuthErrorCode.TooManyRequests, message)` |
|
||||
| `InvalidClientMetadataError` | `new OAuthError(OAuthErrorCode.InvalidClientMetadata, message)` |
|
||||
| `InsufficientScopeError` | `new OAuthError(OAuthErrorCode.InsufficientScope, message)` |
|
||||
| `InvalidTargetError` | `new OAuthError(OAuthErrorCode.InvalidTarget, message)` |
|
||||
| `CustomOAuthError` | `new OAuthError(customCode, message)` |
|
||||
|
||||
The `OAUTH_ERRORS` constant has also been removed.
|
||||
|
||||
**Before (v1):**
|
||||
|
||||
```typescript
|
||||
import { InvalidClientError, InvalidGrantError, ServerError } from '@modelcontextprotocol/core';
|
||||
|
||||
try {
|
||||
await refreshToken();
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidClientError) {
|
||||
// Handle invalid client
|
||||
} else if (error instanceof InvalidGrantError) {
|
||||
// Handle invalid grant
|
||||
} else if (error instanceof ServerError) {
|
||||
// Handle server error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After (v2):**
|
||||
|
||||
```typescript
|
||||
import { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/core';
|
||||
|
||||
try {
|
||||
await refreshToken();
|
||||
} catch (error) {
|
||||
if (error instanceof OAuthError) {
|
||||
switch (error.code) {
|
||||
case OAuthErrorCode.InvalidClient:
|
||||
// Handle invalid client
|
||||
break;
|
||||
case OAuthErrorCode.InvalidGrant:
|
||||
// Handle invalid grant
|
||||
break;
|
||||
case OAuthErrorCode.ServerError:
|
||||
// Handle server error
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Unchanged APIs
|
||||
|
||||
The following APIs are unchanged between v1 and v2 (only the import paths changed):
|
||||
|
|
@ -352,7 +560,8 @@ The following APIs are unchanged between v1 and v2 (only the import paths change
|
|||
|
||||
## Using an LLM to migrate your code
|
||||
|
||||
An LLM-optimized version of this guide is available at [`docs/migration-SKILL.md`](migration-SKILL.md). It contains dense mapping tables designed for tools like Claude Code to mechanically apply all the changes described above. You can paste it into your LLM context or load it as a skill.
|
||||
An LLM-optimized version of this guide is available at [`docs/migration-SKILL.md`](migration-SKILL.md). It contains dense mapping tables designed for tools like Claude Code to mechanically apply all the changes described above. You can paste it into your LLM context or load it as
|
||||
a skill.
|
||||
|
||||
## Need Help?
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue