Skip to content

fix: allow named interfaces for structuredContent in tool callbacks#1714

Open
travisbreaks wants to merge 1 commit intomodelcontextprotocol:mainfrom
travisbreaks:fix/structured-content-type-error
Open

fix: allow named interfaces for structuredContent in tool callbacks#1714
travisbreaks wants to merge 1 commit intomodelcontextprotocol:mainfrom
travisbreaks:fix/structured-content-type-error

Conversation

@travisbreaks
Copy link

Summary

  • Fixes typing structuredContent indirectly causes type error #837: Named interfaces (e.g., interface MyResult { data: string }) caused a type error when returned as structuredContent in tool callbacks, while inline object types worked fine.
  • Root cause: TypeScript does not allow named interfaces to be assigned to Record<string, unknown> index signatures, even when all properties are compatible. CallToolResult.structuredContent is typed as Record<string, unknown> | undefined.
  • Introduces ToolCallbackResult, a more permissive version of CallToolResult that uses object instead of Record<string, unknown> for the structuredContent field. This type is used only in the callback return position; the Zod schema remains unchanged for runtime validation.

What changed

  • packages/server/src/server/mcp.ts: Added ToolCallbackResult type and updated ToolCallback to use it instead of CallToolResult
  • packages/server/src/server/mcp.examples.ts: Added a compile-time type test that verifies named interfaces work as structuredContent without casts
  • .changeset/fix-structured-content-type.md: Changeset for patch release

Test plan

  • pnpm --filter @modelcontextprotocol/server test passes (37 tests)
  • pnpm --filter @modelcontextprotocol/test-integration test passes (386 tests)
  • npx tsc --noEmit passes with zero type errors (including the new named-interface example)
  • pnpm --filter @modelcontextprotocol/server lint passes
  • Existing examples with inline object types and explicit CallToolResult annotations continue to compile

🤖 Generated with Claude Code

TypeScript does not allow named interfaces to be assigned to index
signatures (Record<string, unknown>), even when all properties are
compatible. This meant that returning a named interface as
structuredContent in a tool callback caused a type error, while
inline object types worked fine.

Introduces ToolCallbackResult, which uses `object` instead of
Record<string, unknown> for the structuredContent field in the
callback return position. The Zod schema remains unchanged for
runtime validation.

Adds a compile-time type test in mcp.examples.ts verifying that
named interfaces work as structuredContent without type casts.

Fixes modelcontextprotocol#837

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@travisbreaks travisbreaks requested a review from a team as a code owner March 19, 2026 16:15
@changeset-bot
Copy link

changeset-bot bot commented Mar 19, 2026

🦋 Changeset detected

Latest commit: ff438df

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@modelcontextprotocol/server Patch
@modelcontextprotocol/express Patch
@modelcontextprotocol/hono Patch
@modelcontextprotocol/node Patch

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1714

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1714

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1714

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1714

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1714

commit: ff438df

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.

typing structuredContent indirectly causes type error

1 participant