Skip to content

fix: do not expose internal error details to clients#1851

Open
lexwhiting wants to merge 1 commit intomodelcontextprotocol:mainfrom
lexwhiting:fix/sanitize-tool-errors
Open

fix: do not expose internal error details to clients#1851
lexwhiting wants to merge 1 commit intomodelcontextprotocol:mainfrom
lexwhiting:fix/sanitize-tool-errors

Conversation

@lexwhiting
Copy link
Copy Markdown

Summary

Fixes #1429. Tool handlers that throw unhandled errors now return a generic "Internal error" message instead of leaking the raw error.message to the client.

Before: Any thrown error (including stack traces, connection strings, internal hostnames) was serialized and sent to the client as a CallToolResult with isError: true.

After:

  • ToolError — a new error class for intentional client-visible messages. Throw new ToolError('Invalid input: ...') and the message is returned to the client.
  • ProtocolError — SDK-internal errors (validation, invalid params) remain visible, as they contain no sensitive information.
  • All other errors — sanitized to "Internal error". The real error is passed to an optional onToolError callback for server-side logging.

Changes

  • Add ToolError class exported from @modelcontextprotocol/server
  • Add McpServerOptions interface with optional onToolError callback
  • Update catch block in tools/call handler to sanitize unhandled errors
  • Add 2 new tests (ToolError passthrough, onToolError callback with sensitive data)
  • Update 2 existing tests to expect "Internal error" instead of raw messages

Usage

import { McpServer, ToolError } from '@modelcontextprotocol/server';

const server = new McpServer(
  { name: 'my-server', version: '1.0.0' },
  {
    onToolError: (error) => {
      console.error('Tool error:', error); // Log internally
    }
  }
);

server.registerTool('my-tool', {}, async () => {
  // This message IS shown to the client:
  throw new ToolError('Invalid input: location is required');

  // This message is NOT shown — client sees "Internal error":
  // throw new Error('postgres://admin:secret@internal-host:5432');
});

Test plan

  • All 424 existing tests pass
  • New test: ToolError messages are returned to the client
  • New test: non-ToolError exceptions return "Internal error" and trigger onToolError callback
  • Validation errors (ProtocolError) still return descriptive messages
  • UrlElicitationRequiredError still re-throws correctly
  • Pre-push hooks pass (typecheck, build, lint)

…tocol#1429)

Tool handlers that throw unhandled errors now return a generic
"Internal error" message instead of leaking the raw error.message
to the client. This prevents exposing stack traces, connection
strings, internal hostnames, or other sensitive information.

- Add ToolError class for intentional client-visible errors
- Add McpServerOptions.onToolError callback for server-side logging
- ProtocolError messages (validation, invalid params) remain visible
- Generic Error/unknown exceptions are sanitized to "Internal error"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 4, 2026

⚠️ No Changeset found

Latest commit: 1584a73

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 4, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1851

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1851

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1851

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1851

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1851

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1851

commit: 1584a73

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Do not return and expose internal errors to the client as this is a security risk

1 participant