Return tool annotations from describe.tool - #1980
Open
daviesayo wants to merge 1 commit into
Open
Conversation
`ToolSchemaView` carried everything about a tool except the annotations a plugin declares on it, so code written inside `execute` could not tell an approval-gated tool from a plain one except by reading its prose description. The data was already persisted on the tool row and already used by the executor's own approval copy. `tools.schema` now projects the three fields declared in `ToolAnnotations` (`requiresApproval`, `approvalDescription`, `mayElicit`), and `describe.tool` passes them through. The fields are picked explicitly rather than spread, because plugins keep private bookkeeping alongside the contract: the mcp plugin stores its upstream tool name and `_meta` map in the same column, and none of that should reach a caller. The key is omitted when a tool declares no annotations, so the describe payload does not grow for the tools that have nothing to say. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ToolSchemaViewcarries everything about a tool except the annotations a plugin declares on it, so code written insideexecutecannot tell an approval-gated tool from a plain one except by reading its prose description.tools.schemanow projects the three fields declared inToolAnnotations, anddescribe.toolpasses them through.Linked issue
Part of #1979 (defect 3). Not
Fixes, because that issue also covers two Cloudflare-host defects this PR does not touch.Verification
Added
describes a tool's declared annotations, and omits the key when it has noneinpackages/core/execution/src/tool-invoker.test.ts. It describes two tools on the same test connection:createContact, which declaresrequiresApprovalandapprovalDescription, andlistContacts, which declares nothing. I reverted only the one-line change intool-invoker.tsand re-ran, and the new test failed while the other 39 in the file passed, so the test observes the behaviour rather than restating it.bun run format:checkbun run lintbun run typecheck— 45/45bun run test— 36/39 tasks green. The one failure is@executor-js/mcp-apps-shellmcp-app.browser.test.ts, which launches Chromium from/usr/bin/google-chrome. That path does not exist on macOS, so the suite never starts. It is unrelated to this diff and fails the same way on a clean checkout of this machine.describe.tool's payload shape, and this change adds no user-visible surface. Happy to add one if you want it.Checklist
.changeset/describe-tool-annotations.md).Design notes
The three fields are picked explicitly, not spread. Plugins keep private bookkeeping in the same column as the contract.
packages/plugins/mcp/src/sdk/plugin.tsstamps{ requiresApproval, approvalDescription?, mcp: { toolName, upstream?, _meta? } }and casts the result toToolAnnotations, so a spread would hand a caller the upstream tool name and the server's_metamap.toolAnnotationsViewcopies only whatpackages/core/sdk/src/tool.tsdeclares.One consequence worth naming: an MCP server's own hints (
readOnlyHint,destructiveHint,title) still do not reachdescribe.tool, because the plugin nests them undermcp.upstreamrather than the declared contract. Surfacing those is a separate decision about what the contract should be, and it is yours to make. If you want them, the smallest version is a declaredupstreamfield onToolAnnotationsplus one line intoolAnnotationsView, and I will open a follow-up.Both
ToolSchemaView.makesites are covered — the static-tool branch and the persisted-row branch intoolSchema.The key is absent when a tool declares nothing, so the describe payload does not grow for tools with nothing to say. The
describe.toolself-description string inBUILTIN_TOOL_DESCRIPTIONSwas updated to match.Where this came from: I run
apps/host-cloudflarein production and hit this while writing agent code that needed to branch on whether a tool was a read or a write.🤖 Generated with Claude Opus 5