Skip to content

fix(types): forbid csp/permissions on McpUiToolMeta via never#624

Merged
ochafik merged 2 commits intomainfrom
ochafik/tool-meta-csp-never
Apr 21, 2026
Merged

fix(types): forbid csp/permissions on McpUiToolMeta via never#624
ochafik merged 2 commits intomainfrom
ochafik/tool-meta-csp-never

Conversation

@ochafik
Copy link
Copy Markdown
Contributor

@ochafik ochafik commented Apr 21, 2026

Summary

Hosts read _meta.ui.csp and _meta.ui.permissions from the resource (resources/read content item, with resources/list entry as fallback) — never from the tool. Because _meta.ui.resourceUri does live on the tool, it's an easy mistake to put csp there too; doing so silently yields the default sandbox CSP.

This types csp and permissions as ?: never on McpUiToolMeta, with JSDoc pointing at McpUiResourceMeta. Preventive — not tied to a specific bug report.

Why never and not just rely on excess property checking?

For direct object literals — the common registerAppTool(s, { _meta: { ui: { resourceUri, csp } } }) case — TypeScript's excess property check already errors without this change. The never adds value in two places:

  • Indirect assignment (config built in a variable, spread from a shared object, returned from a helper): structural typing allows extra keys, so const ui = { resourceUri, csp }; registerAppTool(s, { _meta: { ui } }) typechecks clean on main today. With never, it fails with Type '{...csp...}' is not assignable to 'McpUiToolMeta'.
  • JSDoc on the forbidden field: the excess-property error only says "csp does not exist in type McpUiToolMeta"; the never field's hover/docs say where it actually belongs.

Generated Zod emits z.never().optional(); McpUiToolMetaSchema is exported but not .parse()'d anywhere in the SDK or host today, so this is dormant at runtime.

A companion host-side change adds a console.warn for non-TypeScript servers.

Test plan

  • npm run generate:schemasnever"not": {} in schema.json.
  • bun test — 106/106 pass.
  • Verified empirically: indirect assignment typechecks clean on main, errors with TS2322 on this branch.
  • CI typedoc validation.

Hosts read _meta.ui.csp and _meta.ui.permissions from the resource
(resources/read content item, with resources/list entry as fallback),
never from the tool. Typing them as `never` on McpUiToolMeta gives
TypeScript users a compile-time error pointing at McpUiResourceMeta
instead of silently accepting and ignoring them.

Companion to anthropics/apps#38705 (host-side console.warn).
Refs anthropics/claude-ai-mcp#40.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Preview

Preview deployments for this PR have been cleaned up.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 21, 2026

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@624

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@624

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@624

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@624

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@624

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@624

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@624

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@624

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@624

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@624

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@624

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@624

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@624

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@624

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@624

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@624

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@624

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@624

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@624

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@624

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@624

commit: b185b1c

@ochafik ochafik requested a review from antonpk1 April 21, 2026 12:28
@ochafik ochafik merged commit 4995746 into main Apr 21, 2026
22 checks passed
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.

1 participant