Skip to content

feat: add MCP tool annotations (readOnly/destructive hints)#123

Open
yunanwg wants to merge 6 commits into
baruchiro:mainfrom
yunanwg:feat/tool-annotations
Open

feat: add MCP tool annotations (readOnly/destructive hints)#123
yunanwg wants to merge 6 commits into
baruchiro:mainfrom
yunanwg:feat/tool-annotations

Conversation

@yunanwg

@yunanwg yunanwg commented Jun 16, 2026

Copy link
Copy Markdown

What

Stamps MCP tool annotations (readOnlyHint / destructiveHint / openWorldHint) onto every registered tool, derived from the tool-name verb prefix:

  • list_ / get_ / search_ / download_readOnlyHint: true
  • delete_ / bulk_edit_destructiveHint: true
  • everything else → non-destructive write
  • openWorldHint: false (Paperless-ngx is a closed system)

It is implemented as a one-time wrap of server.tool in createMcpServer (using the public RegisteredTool.update()), so no change is needed at any server.tool(...) call site and new tools are covered automatically. It only fills in annotations a tool has not already set, so explicit per-tool annotations would still win.

Why

MCP tool annotations are the hints clients use to present and guard tools — flagging or confirming destructive operations. The server already encodes this intent in prose (⚠️ DESTRUCTIVE: ...); this exposes it as the structured field clients actually read. Without it a client cannot tell get_document from delete_document.

Notes

No change to tool behavior — only tools/list gains annotations. The verb prefixes follow the existing tool naming convention. If you would prefer explicit per-tool annotations instead of the wrapper, happy to expand it.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added MCP tool annotations across the server to label each operation as read-only, write, or destructive, helping MCP clients better understand tool intent and safety.
  • Tests
    • Added an automated check to ensure every registered tool includes the required annotation hints and expected boolean values.
  • Chores
    • Updated release metadata for a minor version bump.

Copilot AI review requested due to automatic review settings June 16, 2026 20:20
@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 81391a4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@baruchiro/paperless-mcp Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68d27009-8a66-462b-a787-2d66caddc2fa

📥 Commits

Reviewing files that changed from the base of the PR and between 1c379a9 and 81391a4.

📒 Files selected for processing (1)
  • src/tools/annotations.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tools/annotations.test.ts

📝 Walkthrough

Walkthrough

A new annotation constants module (src/tools/utils/annotations.ts) exports three ToolAnnotations objects—READ_ONLY, WRITE, and DESTRUCTIVE—each pre-configured with the appropriate boolean values for readOnlyHint, destructiveHint, and openWorldHint. Every tool file (correspondents.ts, customFields.ts, documentTypes.ts, documents.ts, mail.ts, tags.ts) imports these constants and passes the appropriate constant as an argument to each server.tool(...) registration. A new validation test (src/tools/annotations.test.ts) verifies that all registered tools include the required annotation fields. The changeset documents the minor version bump and the new annotation behavior.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • baruchiro/paperless-mcp#31: Modifies the same server.tool(...) registrations in tool files to add description/help strings, directly overlapping with the tool annotation wiring locations.
  • baruchiro/paperless-mcp#109: Modifies src/tools/documents.ts tool registration code paths for download_document and get_document_thumbnail resource URI output.
  • baruchiro/paperless-mcp#111: Introduces the mail tools in src/tools/mail.ts that this PR annotates.

Suggested reviewers

  • baruchiro
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add MCP tool annotations (readOnly/destructive hints)' accurately and clearly summarizes the main change—adding MCP tool annotations with read-only and destructive hints to the Paperless-ngx server.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds automatic MCP tool annotations based on tool-name verb prefixes so MCP clients can better distinguish read vs write vs destructive operations without changing every tool registration call site.

Changes:

  • Import MCP SDK types needed to annotate tools (RegisteredTool, ToolAnnotations).
  • Add toolAnnotations(name) helper that derives readOnlyHint/destructiveHint/openWorldHint from tool-name prefixes.
  • Wrap server.tool to automatically stamp annotations onto every registered tool.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/server.ts Outdated
Comment thread src/server.ts Outdated
Comment thread src/server.ts Outdated
Comment thread src/server.ts Outdated
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@baruchiro baruchiro left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm from mobile and it is hard to review it well, so expect another review, hopefully this weekend.

Comment thread src/server.ts Outdated
Comment thread src/server.ts Outdated
Replace the verb-prefix wrapper that derived annotations from tool names
with explicit annotations at each server.tool(...) call site, via three
shared constants (READ_ONLY / WRITE / DESTRUCTIVE). This keeps every
tool's hint visible at its registration and lets exceptions be set per
tool, addressing review feedback to annotate tools manually.

bulk_edit_* stay destructive because each exposes a permanent 'delete'
method in its description; update_* are non-destructive edits.

Add src/tools/annotations.test.ts, which builds the server and asserts
every registered tool declares annotations, so a new tool can't ship
without one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tools/annotations.test.ts`:
- Around line 30-34: The assertion for openWorldHint in the test only validates
the type is boolean but does not enforce the required value. Modify the
assert.equal call to check that annotations.openWorldHint is explicitly equal to
false instead of just checking typeof, ensuring the closed-system contract is
properly validated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6f31aece-d0de-4294-b067-cb256bb41cb6

📥 Commits

Reviewing files that changed from the base of the PR and between 903ba92 and a2f4ebb.

📒 Files selected for processing (10)
  • .changeset/mcp-tool-annotations.md
  • src/server.ts
  • src/tools/annotations.test.ts
  • src/tools/correspondents.ts
  • src/tools/customFields.ts
  • src/tools/documentTypes.ts
  • src/tools/documents.ts
  • src/tools/mail.ts
  • src/tools/tags.ts
  • src/tools/utils/annotations.ts
✅ Files skipped from review due to trivial changes (2)
  • src/tools/utils/annotations.ts
  • src/server.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/mcp-tool-annotations.md

Comment thread src/tools/annotations.test.ts
yunanwg and others added 2 commits June 17, 2026 22:19
Per the repo's comment policy (CLAUDE.md): remove the per-constant JSDoc
in annotations.ts and the header comment in annotations.test.ts — the
constant names + field values and the test name + assertion messages
already say what they said. Keep only the openWorldHint "why" note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@baruchiro baruchiro left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

3 participants