Skip to content

mcp: annotate every tool so a host can tell an observation from an input action - #512

Merged
xxx merged 1 commit into
masterfrom
mcp-tool-annotations-509
Aug 22, 2026
Merged

mcp: annotate every tool so a host can tell an observation from an input action#512
xxx merged 1 commit into
masterfrom
mcp-tool-annotations-509

Conversation

@xxx

@xxx xxx commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #509.

destructiveHint and openWorldHint both default to true in the MCP spec, so glass's 30 unannotated tools read to a host as destructive and open-world — glass_a11y_snapshot paid the same confirmation prompt as glass_click. Every tool now declares readOnlyHint and openWorldHint; every input tool also declares destructiveHint.

The four judgement calls the issue left open:

  • glass_doctor is not read-only. deep = true spawns and tears down a headless display, and a hint is per-tool, not per-argument, so the worst case wins.
  • glass_start is the only open-world tool. It builds, and a build fetches dependencies over the network. Everything else is bounded by the one local app.
  • glass_stop is destructive, and idempotent — a second stop adds no further effect.
  • idempotentHint is otherwise claimed only for glass_select_window. glass_move, glass_window, glass_set_value and glass_clipboard_set all look idempotent but fire app-visible events whose handlers run again on a repeat; claiming otherwise invites a host to auto-retry them.

glass_baseline_save and glass_select_window are read_only = false, destructive = false: they change glass's state, not the app's.

annotations_classify_every_tool holds an exhaustive name -> read_only table and checks that every tool carries annotations, that its classification matches the table, that openWorldHint is always set, that input tools set destructiveHint, and that read-only tools set neither destructiveHint nor idempotentHint (the spec says both are meaningless there). A tool added later fails until it is classified; a reclassification cannot be silent.

Verification

  • All six guard branches ablated individually and confirmed red before the annotations went in.
  • tools/list over stdio against the built binary returns 30 tools, none without annotations, in camelCase.
  • cargo test --workspace (0 failures), cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --all --check.

Draft until CI is green.

… an input action (fixes #509)

destructiveHint and openWorldHint both default to true in the MCP spec, so glass's
30 unannotated tools read to a host as destructive and open-world — glass_a11y_snapshot
paid the same confirmation prompt as glass_click.

Each tool now declares readOnlyHint and openWorldHint, and each input tool declares
destructiveHint. The judgement calls: glass_doctor is not read-only because deep=true
spawns a display and a hint is per-tool, not per-argument; glass_start is the only
open-world tool because it builds, and a build fetches over the network; idempotentHint
is claimed only for glass_stop and glass_select_window, since the rest fire app-visible
events whose handlers run again on a repeat.

annotations_classify_every_tool holds an exhaustive name -> read_only table, so a tool
added later fails until classified and a reclassification cannot be silent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@xxx
xxx marked this pull request as ready for review August 22, 2026 00:48
@xxx
xxx merged commit cc07559 into master Aug 22, 2026
17 checks passed
@xxx
xxx deleted the mcp-tool-annotations-509 branch August 22, 2026 00:48
@xxx xxx mentioned this pull request Aug 22, 2026
xxx added a commit that referenced this pull request Aug 22, 2026
Rename [Unreleased] to [1.5.0] with today's UTC date and open a fresh
[Unreleased], updating the two compare links.

Also backfills three entries whose PRs merged without one: the MCP tool
annotations (#512), the X11 clipboard owner that kept reporting itself
alive (#449), and the launched app's log readers that waited for an EOF
that never came (#478).

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

mcp: tools carry no annotations, so a client cannot tell an observation from an input action

1 participant