Skip to content

Commit eafaf13

Browse files
committed
address review: changeset, move ToolError, migration docs, test nit
1. Add minor changeset for @modelcontextprotocol/server 2. Move ToolError class above McpServer JSDoc so generated docs aren't orphaned 3. Add migration.md entry explaining the breaking change for v1 authors who throw raw Error expecting clients to see the message 4. Add expect(result.isError).toBe(true) to cancellation test
1 parent a866147 commit eafaf13

File tree

4 files changed

+39
-14
lines changed

4 files changed

+39
-14
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/server': minor
3+
---
4+
5+
Add ToolError class for secure-by-default tool error handling. Unhandled errors from tool handlers are now sanitized to "Internal error" instead of exposing raw messages. Use `throw new ToolError('message')` when you want clients to see a specific error message.

docs/migration.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,26 @@ import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';
870870
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';
871871
```
872872

873+
## Tool error sanitization
874+
875+
Tool handlers that `throw new Error('message')` will now return `"Internal error"` to clients instead of the raw error message. This prevents accidental leakage of server internals (hostnames, connection strings, stack traces).
876+
877+
To send a user-visible error message, use the new `ToolError` class:
878+
879+
```typescript
880+
import { ToolError } from '@modelcontextprotocol/server';
881+
882+
server.registerTool('my-tool', {}, async () => {
883+
// Client sees: "Internal error"
884+
throw new Error('DB connection failed at 10.0.0.5:5432');
885+
886+
// Client sees: "Invalid country"
887+
throw new ToolError('Invalid country');
888+
});
889+
```
890+
891+
`ProtocolError` messages (SDK validation errors) are still passed through unchanged.
892+
873893
## Unchanged APIs
874894

875895
The following APIs are unchanged between v1 and v2 (only the import paths changed):

packages/server/src/server/mcp.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,6 @@ import { getCompleter, isCompletable } from './completable.js';
4545
import type { ServerOptions } from './server.js';
4646
import { Server } from './server.js';
4747

48-
/**
49-
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
50-
* For advanced usage (like sending notifications or setting custom request handlers), use the underlying
51-
* {@linkcode Server} instance available via the {@linkcode McpServer.server | server} property.
52-
*
53-
* @example
54-
* ```ts source="./mcp.examples.ts#McpServer_basicUsage"
55-
* const server = new McpServer({
56-
* name: 'my-server',
57-
* version: '1.0.0'
58-
* });
59-
* ```
60-
*/
61-
6248
/**
6349
* Error class for tool handlers to throw when they want to send a
6450
* user-visible error message to the client. Unlike regular errors,
@@ -74,6 +60,19 @@ export class ToolError extends Error {
7460
}
7561
}
7662

63+
/**
64+
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
65+
* For advanced usage (like sending notifications or setting custom request handlers), use the underlying
66+
* {@linkcode Server} instance available via the {@linkcode McpServer.server | server} property.
67+
*
68+
* @example
69+
* ```ts source="./mcp.examples.ts#McpServer_basicUsage"
70+
* const server = new McpServer({
71+
* name: 'my-server',
72+
* version: '1.0.0'
73+
* });
74+
* ```
75+
*/
7776
export class McpServer {
7877
/**
7978
* The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.

test/integration/test/server/mcp.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7076,6 +7076,7 @@ describe('Zod v4', () => {
70767076
});
70777077

70787078
// Should receive an error since cancelled tasks don't have results
7079+
expect(result.isError).toBe(true);
70797080
expect(result).toHaveProperty('content');
70807081
expect(result.content).toEqual([{ type: 'text' as const, text: 'Internal error' }]);
70817082

0 commit comments

Comments
 (0)