Skip to content

pdf-server: display_pdf/interact rejected client-side by strict 2020-12 output-schema validators #765

Description

@bonallure

Bug

Calling display_pdf or interact in examples/pdf-server fails client-side, before the tool call ever reaches the server, on clients with a strict JSON Schema 2020-12-only output-schema validator (observed on Claude Desktop / Claude Code):

Tool 'display_pdf' has an invalid outputSchema: JSON Schema declares an unsupported dialect
("$schema": "http://json-schema.org/draft-07/schema#"). The default validator supports
JSON Schema 2020-12 only, pass a pre-configured Ajv instance to AjvJs

interact has no outputSchema of its own, but it fails too — the client rejects the entire tools/list response over the one bad tool (display_pdf), so every tool in the list breaks together.

Root cause

@modelcontextprotocol/sdk (pinned ^1.29.0 here, confirmed still present in latest 1.30.0) always emits "$schema": "http://json-schema.org/draft-07/schema#" on Zod-derived inputSchema/outputSchema, with no way to configure it via registerTool/registerAppTool:

  • node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js:9-17mapMiniTarget() falls back to 'draft-7' whenever no target is passed.
  • node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js:88-96 — the tools/list handler never passes a target.

This is a known, already-filed, still-open upstream bug: modelcontextprotocol/typescript-sdk#2721. There is no released SDK version that fixes it.

display_pdf, read_pdf_bytes, and save_pdf in examples/pdf-server/server.ts all declare outputSchema: z.object({...}) via registerAppTool and trigger this.

Fix

Opening a PR that adds fixOutputSchemaDialect(server) to src/server/index.ts — a workaround that wraps Server.setRequestHandler to intercept the tools/list handler and rewrite the draft-07 $schema to https://json-schema.org/draft/2020-12/schema before the response goes out. Wired into examples/pdf-server/server.ts, called immediately after new McpServer(...).

Follow-up (not in the linked PR, scoped out to keep it focused)

The same unpatched bug affects other examples that declare outputSchema without calling the new helper:

  • examples/budget-allocator-server/server.ts
  • examples/cohort-heatmap-server/server.ts
  • examples/basic-server-vanillajs/server.ts
  • examples/integration-server/server.ts
  • examples/customer-segmentation-server/server.ts
  • examples/system-monitor-server/server.ts
  • examples/debug-server/server.ts
  • examples/wiki-explorer-server/server.ts
  • examples/scenario-modeler-server/server.ts
  • examples/video-resource-server/server.ts
  • examples/threejs-server/server.ts

Happy to send a follow-up PR applying fixOutputSchemaDialect to these too, or maintainers may prefer to fold it into registerAppTool itself once there's agreement on the right call-site contract (it must run before any tool registration, since McpServer only installs its real tools/list handler once, lazily, on first registration).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions