Add tool annotations and structured output#37
Open
itz4blitz wants to merge 3 commits into
Open
Conversation
itz4blitz
marked this pull request as ready for review
July 12, 2026 15:16
itz4blitz
force-pushed
the
justin/tool-annotations
branch
from
July 12, 2026 15:35
a8a2bd2 to
4ec572b
Compare
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.
What
Adds MCP tool annotations and structured output to every tool the server exposes, so clients can auto-allow safe reads, gate destructive calls, and consume typed results.
MCPToolDefinitionnow requires anannotationsfield, so the compiler enforces that every current and future tool ships a reviewed classification. Four factories insrc/tool-annotations.ts(readOnlyToolAnnotations,additiveToolAnnotations,idempotentMutationToolAnnotations,destructiveToolAnnotations) each emit all four hints (readOnlyHint,destructiveHint,idempotentHint,openWorldHint) with per-tool overrides available.convertToolDefinitionnow advertisesoutputSchemafor every tool, and successful tool results carrystructuredContentalongside the existing JSON text payload (which is unchanged). Error results stay text-only withisError: true.Classification rules
get*/search*reads; always idempotentupdate*,assignIssue,setIssuePriority,add/removeIssueLabel,markNotificationAsRead,addToFavorites,completeCycle,unarchive*, ...)create*), plusduplicateIssueandaddAttachment, which mint a new entity per calldelete*,archive*,logout*— repeating converges on the same end stateEvery tool talks only to the configured Linear workspace, so
openWorldHintisfalseacross the board; both the unit tests and the smoke test pin that no tool advertises open-world behavior.Array wrapping decision
MCP requires
outputSchemaandstructuredContentto be top-level JSON objects, but many tools return arrays. Array-shaped output schemas are wrapped as{ type: "object", properties: { items: <array schema> }, required: ["items"] }, andbuildStructuredContentmirrors that wrapping on results ({ items: [...] }), sostructuredContentalways validates against the advertised schema. Object schemas pass through unchanged. The existing top-level input-schema sanitization (strippingoneOf/anyOf/allOf/enum/not) is preserved exactly.Verification
jest: 26 suites, 186 tests passing, including a parity test that every definition declares complete boolean annotations (removing annotations from any definitions file fails the suite at compile time), classification spot tests, and wire-format tests forconvertToolDefinition/buildStructuredContent.npm run build: clean.npm run test:mcp-smoke(real stdio round-trip): passes for 185 tools, 6 resources, 4 prompts — asserts every listed tool carries explicit boolean annotations and an object-typedoutputSchema,linear_getIssuesadvertises the requireditemsenvelope, real local calls (linear_getServerStatus,linear_getRateLimitStatus) returnstructuredContentmirroring the JSON text payload (SDK-validated against the advertised schema), and error results stay text-only withoutstructuredContent.npm pack --dry-runandgit diff --check: clean. No package version bump.Based on #35 (MCP SDK 1.29) — required because the older SDK types lack annotations/outputSchema; contains its single commit until it merges.