Skip to content

mcp: add tool annotations to render, lint and read_docs - #27

Merged
danhstevens merged 1 commit into
anypost:mainfrom
theluckystrike:mcp-tool-annotations
Nov 13, 2026
Merged

danhstevens merged 1 commit into
anypost:mainfrom
theluckystrike:mcp-tool-annotations

Conversation

@theluckystrike

@theluckystrike theluckystrike commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What was missing

The three MCP tools (render, lint, read_docs) are registered without annotations, so tools/list returns no readOnlyHint, destructiveHint or openWorldHint. Under the MCP spec's ToolAnnotations defaults, a tool without hints is treated as possibly destructive (destructiveHint defaults to true) and open-world (openWorldHint defaults to true).

Why it matters

  • MCP spec, ToolAnnotations: https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-annotations
  • The Anthropic connectors directory asks for readOnlyHint or destructiveHint on every tool, and OpenAI's app review checks readOnlyHint, destructiveHint and openWorldHint on every tool.
  • Clients that gate calls on the hints (for example, skipping the confirmation prompt for read-only tools) can now treat these tools as safe.

The change

I read each handler before choosing the values:

Tool readOnly destructive idempotent openWorld Why
render true false true false Pure function of the markdown; the preview link is built locally in the URL fragment
lint true false true false Pure function of the markdown
read_docs true false true false GET of a page under emailmd.dev only (fixed host, no user-supplied URL)

The values live in one READ_ONLY_ANNOTATIONS constant in src/mcp.ts, and each tool also gets annotations.title (same as its existing title). A test in tests/mcp.test.ts asserts the annotations on every listed tool.

How I verified

  • npx vitest run in packages/emailmd: 991 passed (990 before, plus the new test)
  • npx tsc --noEmit -p packages/emailmd: clean
  • npm run build and npm run lint at the root: clean

Found with the free McpStamp check (mcpstamp.com/check).

All three tools only read: render and lint are pure functions of their
input and read_docs fetches pages from emailmd.dev. Declare that with
explicit readOnlyHint/destructiveHint/idempotentHint/openWorldHint so
clients do not fall back to the spec defaults (destructiveHint and
openWorldHint default to true), and repeat the tool title in
annotations.title for clients that read it from there.
@vercel

vercel Bot commented Nov 7, 2026

Copy link
Copy Markdown

@theluckystrike is attempting to deploy a commit to the unmta Team on Vercel.

A member of the Team first needs to authorize it.

@danhstevens
danhstevens merged commit c643851 into anypost:main Nov 13, 2026
1 check failed
@danhstevens

Copy link
Copy Markdown
Contributor

@theluckystrike thanks for the contribution!

@anypost anypost deleted a comment from theluckystrike Nov 14, 2026
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.

2 participants