Skip to content

fix(mcp): advertise MCP tool annotations so clients stop treating every tool as destructive - #683

Merged
dash0-dev[bot] merged 2 commits into
mainfrom
fix/mcp-tool-annotations
Oct 6, 2026
Merged

dash0-dev[bot] merged 2 commits into
mainfrom
fix/mcp-tool-annotations

Conversation

@dash0-dev

@dash0-dev dash0-dev Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

tools/list sent no annotations, so MCP clients applied the spec defaults (readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true) and showed all 22 LoreKit tools, memory.read and memory.search included, as write + destructive. Every catalog entry now declares all four hints explicitly, and the wire projection passes them through to both the edge server and the local lorekit mcp stdio server.

Changes

  • tool-catalog.ts: new required annotations: McpToolAnnotations field on McpToolDoc (all four hints required, so no tool can fall back to a default), a READ_ONLY constant and a writeHints({ destructive, idempotent }) helper. toWireTool now emits annotations.
  • Classification:
    • Read-only (8): memory.read, memory.list, memory.search, memory.scopes, memory.list_archived, org.list, policy.list, groom.preview
    • Write, non-destructive (6): memory.archive, memory.restore, memory.protect, groom.run, org.create, policy.create
    • Write, destructive (8): memory.write (upsert overwrites the value in place), memory.delete (force: true hard-deletes), memory.purge, memory.purge_expired, org.rename, org.delete, policy.update, policy.delete
    • openWorldHint: false on all of them, since every tool acts only on the LoreKit store. idempotentHint: false only for memory.write (bumps seen_count), org.create and policy.create.
  • tool-catalog-parity.spec.ts: asserts readOnlyHint === (toolRequires(name) === 'read'), that all four hints are present booleans on every tool, that read-only tools are never destructive, and pins the destructive set by name so moving a tool in or out of it has to be done on purpose.
  • Regenerated the edge mirror, surfaces.generated.mjs and llms.txt (each tool block now gets a "MCP annotations: …" line). Added a check to the smoke suite and to the stdio server test. Documented the classification in docs/mcp-tools.md, and added the now-required annotations field to step 1 and the worked example of docs/adding-an-operation.md.

Context

  • The issue showed up in Dash0's MCP connector settings, which listed every LoreKit tool under "Write/destructive tools".
  • The servers still negotiate protocol 2024-11-05. annotations was added to the spec in 2025-03-26, and this PR sends the field without bumping the negotiated version. Clients that read annotations regardless of version will pick it up. A client that only reads them on a newer negotiated version would still need that bump, which is left out of this PR because it changes transport semantics.
  • Judgment calls for review: soft-archive (memory.archive, groom.run) is marked non-destructive because memory.restore reverses it. org.rename and policy.update are marked destructive because they overwrite in place.
  • Verified locally: mcp-core src/mcp-guards/*, src/edge/*, permissions.spec.ts; all schemas specs; tsc --noEmit for schemas and mcp-core; cli test/mcp-server.test.mjs. CI covers deno check and lint.

…ry tool as destructive

tools/list sent no annotations, so MCP clients applied the spec defaults
(readOnlyHint: false, destructiveHint: true) and showed all 22 tools,
memory.read included, as write + destructive. Each catalog entry now
declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint
explicitly, and toWireTool passes them through to the edge server and the
local stdio server.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

The dashboard preview for this PR — redeployed on each push that changes the web app.

Project Deployment Actions Updated
lorekit Ready Ready Preview Oct 6, 2026 9:45am UTC

Preview always points at this PR's latest commit; Deployment is the immutable build of be26c3e. · Comment /web-preview to force a redeploy. · Workflow logs

@dash0-dev

dash0-dev Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ No issues found

The follow-up commit adds annotations, READ_ONLY/writeHints and the pinned destructive list to the add-operation guide, and each claim matches the catalog and the parity spec. The earlier finding is resolved. No new findings.

Checked: 1 of 1 changed file read · 0 of 4 dependent files traced · 2 possible issues → 0 confirmed → 0 posted

Progress: open review threads 1 → 0 across the last 2 reviews

What this change reaches — 4 changed exports · 4 dependent files · 0 checked · 4 not checked · 1 changed file imported by 3 files
flowchart LR
  subgraph pr["Changed in this PR"]
    s1["MCP_TOOL_DEFS<br/>body changed"]:::changed
    s2["MCP_TOOLS<br/>body changed"]:::changed
    s3["renderTool<br/>body changed"]:::changed
    s4["McpToolAnnotations<br/>added"]:::changed
    m1["supabase/functions/_shared/schemas/tool-catalog.ts<br/>file changed"]:::changed
  end
  s1c1["packages/cli/src/commands/mcp-server.mjs<br/>? not checked"]:::unknown
  s1c2["scripts/smoke/smoke-mcp-tools.mjs<br/>? not checked"]:::unknown
  s2c1["packages/schemas/src/llms/ · 2 files<br/>? not checked"]:::unknown
  s3c1["packages/schemas/src/llms/render.spec.ts<br/>? not checked"]:::unknown
  s4c1["packages/schemas/src/llms/render.ts<br/>? not checked"]:::unknown
  m1i1["supabase/functions/mcp/ · 2 files<br/>import this file"]:::imports
  m1i2["supabase/functions/_shared/schemas/memory.ts<br/>imports this file"]:::imports
  s1 -.-> s1c1
  s1 -.-> s1c2
  s2 -.-> s2c1
  s3 -.-> s3c1
  s4 -.-> s4c1
  m1 -.-> m1i1
  m1 -.-> m1i2
  classDef changed fill:#eef2ff,stroke:#6366f1,color:#1e1b4b
  classDef ok fill:#e7f6ec,stroke:#16a34a,color:#14532d
  classDef partial fill:#fef9c3,stroke:#ca8a04,color:#713f12
  classDef unknown fill:#f3f4f6,stroke:#9ca3af,stroke-dasharray:4 3,color:#374151
  classDef bad fill:#fde8e8,stroke:#dc2626,color:#7f1d1d
  classDef warn fill:#fff4e5,stroke:#d97706,color:#78350f
  classDef imports fill:#f8fafc,stroke:#64748b,stroke-dasharray:4 3,color:#1e293b
Loading
  • MCP_TOOL_DEFS (packages/cli/src/surfaces.generated.mjs) — body change · 2 consumer files · 2 not traced
  • MCP_TOOLS (packages/schemas/src/shared/tool-catalog.ts) — body change · 2 consumer files · 2 not traced
  • renderTool (packages/schemas/src/llms/render.ts) — body change · 1 consumer file · 1 not traced
  • McpToolAnnotations (packages/schemas/src/shared/tool-catalog.ts) — added change · 1 consumer file · 1 not traced
  • supabase/functions/_shared/schemas/tool-catalog.ts — changed file · imported by 3 files, not traced
Review details
Gate Status Details
Description vs. code ✅ Description matches the diff; the follow-up commit's add-operation guide edit is unlisted but within scope
Prior review feedback ✅ Earlier review comments are resolved.
Documentation ✅ PR body, the McpToolAnnotations doc comment, docs/mcp-tools.md and now the add-operation guide explain the change
Self-review signals ✅ No debug logs, leftover TODOs, or unreviewed stubs.
Code review ✅ The multi-lens review found no blocking issues.

Found

Quality — produced 2 → posted inline 0 · cleared 0 · carried forward 0 · deferred 0 · below-bar 0
Dropped — 1 below-bar, 2 materiality (docs-only delta, cosmetic)
Standards — ran — delta scope: 1 file against 4 governing docs, 68 bullets; 0 findings
Measurability — ran — quiet: gate 1 not met (delta touches docs/ only; no web, api or worker path)

Run

incremental · 9 lines in delta · tier standard · depth checkout · finders and verifier in-context · consumer trace limited to delta exports (none changed; dependents last traced at be26c3e)
CI — still pending: Typecheck, Test & Lint (affected) · 8 passed
Memories — 41 indexed · 0 used

Nothing to report — optimality (skipped), integrations (not activated), severity, 0 files skipped.

pr-reviewer · commit 4fc651a · incremental review, delta since be26c3e · how these findings are produced · updated Oct 6, 2026 10:17am UTC

Comment thread packages/schemas/src/shared/tool-catalog.ts
…-operation guide

Addresses the pr-reviewer bot's comment: #683 (comment)

Refs: #683
Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
@dash0-dev
dash0-dev Bot marked this pull request as ready for review October 6, 2026 10:19
@dash0-dev
dash0-dev Bot requested a review from mthines as a code owner October 6, 2026 10:19
@dash0-dev
dash0-dev Bot merged commit 12e933a into main Oct 6, 2026
18 checks passed
@lorekitbot lorekitbot Bot mentioned this pull request Oct 6, 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.

1 participant