Skip to content

Conversation

@SamMorrowDrums
Copy link
Contributor

@SamMorrowDrums SamMorrowDrums commented Nov 21, 2025

Summary

This SEP proposes a tool resolution mechanism that enables servers to provide argument-specific metadata before tool invocation. The design takes inspiration from LSP's resolve pattern and HTTP preflight OPTION requests while adapting it for MCP's unique requirements.

Key Changes

  • New tools/resolve method: Clients can request refined tool metadata based on intended arguments
  • New resolve field: Tools can indicate they support resolution
  • New server capability: tools.resolve: true

The Problem

Tool definitions from tools/list are static. A manage_files tool must declare destructiveHint: true even though read operations are completely safe. This causes:

  • Over-prompting with unnecessary confirmation dialogs
  • Reduced trust from LLMs that avoid "destructive" tools
  • Poor UX for versatile, multi-action tools

The Solution

Before invoking a tool, clients can call tools/resolve with the tool name and intended arguments. The server returns a complete tool definition with annotations refined for that specific operation:

// Request
{ "method": "tools/resolve", "params": { "name": "manage_files", "arguments": { "action": "read" }}}

// Response - safe operation!
{ "tool": { "name": "manage_files", "annotations": { "readOnlyHint": true, "destructiveHint": false }}}

Why This Approach?

This design follows @findleyr's suggestion to adopt an LSP-inspired resolve pattern:

"we probably want to avoid a future where there are a bunch of separate preflight checks for a single tool call--it would be better to consolidate them into a single exchange"

By returning the full Tool object, we:

  1. Prevent method proliferation (tools/annotations, tools/scopes, tools/costs)
  2. Enable future extensions without protocol changes
  3. Provide a single preflight exchange for all metadata needs

Future Extensibility

The pattern supports future metadata beyond annotations:

  • Scope requirements: OAuth scopes needed for specific operations
  • Cost estimates: Token/credit costs that vary by arguments
  • Rate limits: Different operations may have different limits

These are explicitly out of scope for this SEP but the mechanism supports them.

Backward Compatibility

Fully backward compatible:

  • Existing servers work unchanged
  • Existing clients can ignore resolve: true
  • Static annotations remain the fallback

Checklist:

  • SEP follows the template format
  • Abstract and motivation are clear
  • Specification is complete with request/response formats
  • Backward compatibility addressed
  • Security implications considered
  • Reference implementations provided

@SamMorrowDrums SamMorrowDrums marked this pull request as ready for review November 21, 2025 13:34
@dsp-ant dsp-ant changed the title SEP: Dynamic Tool Annotations SEP-1862: Dynamic Tool Annotations Nov 21, 2025
@dsp-ant dsp-ant added proposal SEP proposal without a sponsor. SEP labels Nov 21, 2025
@SamMorrowDrums
Copy link
Contributor Author

SamMorrowDrums commented Nov 21, 2025

Coincidentally there may already be a case for a preflight request for other purposes. As @findleyr mentioned on Discord, we might not be able to support forwarding of 403 errors during tool calls due to SEP-1699 and so we might wish to enable a preflight checks to support scope challenges also.

cc @dend

@findleyr
Copy link
Contributor

findleyr commented Nov 24, 2025

By comparison, LSP has a notion of 'resolve', which is when the client asks the server to 'finish filling out' a particular stub. For example codeAction/resolve, though this exists for many constructs.

That's slightly different, because the client isn't passing in any specific arguments in the resolve request: it's simply exchanging the stub for a fully filled-out version, but I think there's something to be learned from the design: we probably want to avoid a future where there are a bunch of separate preflight checks for a single tool call--it would be better to consolidate them into a single exchange. I'm not sure what that means, concretely: do we return the entire tool from the preflight check, rather than just its annotations?

- Update creation date to 2025-11-21
- Consolidate duplicate file/API examples into single table-based example
- Remove redundant 'Why Return Full Tool?' section (already in Rationale)
- Clean up TypeScript comments
- Apply prettier formatting
@SamMorrowDrums
Copy link
Contributor Author

Revised Direction

Thanks @findleyr for the excellent feedback on adopting an LSP-inspired resolve pattern. I've substantially revised this SEP based on your suggestions and additional considerations around extensibility.

Key Changes

Renamed concept: tools/annotationstools/resolve

  • Field: dynamicAnnotationsresolve
  • Capability: dynamicAnnotationsresolve
  • Method: tools/annotationstools/resolve

Returns full Tool object instead of just annotations

  • Enables future extensions (scopes, costs, rate limits) without new preflight methods
  • Follows the principle of "consolidate into a single exchange"
  • Maintains structural consistency with tools/list responses

Added LSP context with comparison table

  • Clarified that we're adapting LSP's useful patterns for MCP
  • Key difference: MCP tools are fully functional from tools/list, resolution refines metadata based on intended arguments

Added Future Extensibility section

  • Discussed potential uses for scope requirements (addressing my comment about scope challenges)
  • Noted these are out of scope but the mechanism supports them

Cleaned up examples

  • Consolidated duplicate file examples
  • Removed redundant sections

Open for Discussion

I'd appreciate feedback on:

  1. The naming (resolve vs alternatives)
  2. Whether the LSP comparison is helpful or distracting
  3. The scope of "future extensibility" - should we be more or less specific?

The goal is a clean, extensible foundation that avoids the "proliferation of preflight methods" concern @findleyr raised.

@SamMorrowDrums SamMorrowDrums changed the title SEP-1862: Dynamic Tool Annotations SEP: Tool Resolution Nov 25, 2025
…eristics, and related SEPs

- Add authorization delegation context example (based on SEP-214 token exchange)
- Add execution characteristics example for long-running task indication
- Update motivation to mention execution characteristics and auth boundary crossings
- Add SEP-1385 (Tool Execution Requirements) to Related Work
- Add SEP-214 (On-Behalf-Of Token Exchange) to Related Work
@SamMorrowDrums
Copy link
Contributor Author

As an example trying to do Scope Challenge for GitHub MCP, I would ideally allow public repo access without a repo scope challenge, however then I won't be able to send a challenge for accessing private repos, so the granularity of 1 scope for one tool is definitely not sufficient for our use case. In order to allow least privilege generally, I am forced to provide a scope challenge for all available data, which is a problem when a legitimate user wants to access only public repo data and not give the token full repo scope.

This is currently not solvable.

SamMorrowDrums added a commit to SamMorrowDrums/modelcontextprotocol that referenced this pull request Nov 27, 2025
Introduces trust and sensitivity annotations for MCP requests and responses,
enabling clients and servers to track, propagate, and enforce trust boundaries
on data as it flows through tool invocations.

Key features:
- Result annotations: sensitiveHint, privateHint, openWorldHint, maliciousActivityHint, attribution
- Request annotations for propagating trust context
- Propagation rules ensuring sensitivity markers persist across agent sessions
- Integration with Tool Resolution (modelcontextprotocol#1862) for pre-execution annotations
- Per-item annotations for mixed results (e.g., search results)
- Defense-in-depth approach complementing tool-level annotations

Closes modelcontextprotocol#711
Adds argument-specific scope requirements as a key use case:
- Motivation: Over-scoping problem (e.g., GitHub repo scope for public repos)
- Future Extensibility: Dynamic securitySchemes example with noauth/oauth2
- Related Work: Cross-reference to SEP-1488 and SEP-711 (Trust Annotations)

The key insight is that static securitySchemes declarations require
maximum permissions upfront, but tool resolution enables servers to
return argument-specific requirements (e.g., noauth for public repos,
repo scope only for private repos).

This reduces unnecessary OAuth prompts and enables principle of least
privilege in MCP tool invocations.
@dsp-ant dsp-ant changed the title SEP: Tool Resolution SEP-1862: Tool Resolution Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proposal SEP proposal without a sponsor. SEP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants