Add tool annotations (readOnlyHint, destructiveHint, etc.) #14
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add tool annotations — declare each tool's destructiveness/idempotence/read-only nature so the client can gate the dangerous ones behind extra confirmation.
Goal
shell,shell_bg,write_file,edit_file,remote_*are obviously destructive;read_file,list_dir,search_files,fetch,web_searchare obviously not. The client cannot tell. Clients that respect annotations (Claude Desktop, Claude Code) display a banner / require explicit per-call confirmation for destructive tools — but only if the tool declares itself as such. Today none of lmcp's tools do.This is the smallest possible spec-conformance win — one keyword-table per tool registration.
Annotation keys (per spec)
titlename(which is the call-id)readOnlyHintdestructiveHintidempotentHintopenWorldHintHints are advisory — clients decide whether to enforce. The spec says they SHOULD be set "based on the best understanding of the tool's behaviour."
API for lmcp
Extend the
server:toolsignature:5th positional arg (optional
optstable) keeps backwards compat.Suggested annotations for current lmcp tools
shellshell_bgread_filewrite_fileedit_filelist_dirsearch_filessysteminfofetchweb_searchAll
hubremote_*tools mirror the corresponding non-remote tool, exceptopenWorldHintis always true (network).Scope (v1)
server:toolto accept a 5thoptsarg withannotations.tools/listresponses (spec field name:annotations).server.luaandhub.lua.Out of scope
shellunless an env flag is set). Annotations are advisory.Priority
High for value-per-effort. Half a day total. Immediate safety win across every client that respects annotations. Should ship before further tool additions so new tools default to declaring their stance.
Implemented across lmcp.lua, server.lua, hub.lua, example_server.lua.
server:tool()accepts an optional 5thoptsarg withannotations = { title?, readOnlyHint?, destructiveHint?, idempotentHint?, openWorldHint? }.tools/listemitsannotationsonly when registered (backwards compat: legacy 4-arg calls keep working).Backfilled annotations across all 21 tool registrations: 10 in server.lua, 8 in hub.lua, 4 in example_server.lua. Phase 5 reviewer caught a spec-interpretation error in my first table:
fetch/web_searchwere originally markedidempotent=falsebecause remote responses vary, but spec defines idempotent as effect on the tool's own environment (server-side) — flipped toidempotent=true(the world-side variability is conveyed byopenWorldHint=true).Memory: project_mcp_idempotent_semantics.md captures the trap.
Left
windows/pkg/tree unsynced (April-2026 stale snapshot, pre-existing scope debt). Filed as follow-up #18.