Skip to content

Server SDK support for scope challenges on tool calls #1151

Closed

Description

@pcarleton

Summary

Server SDK authors currently have no ergonomic way to trigger OAuth scope challenges during tool execution. While the MCP spec (SEP-835) supports returning 403 responses with WWW-Authenticate headers to request additional scopes, server SDKs don't provide facilities to easily declare required scopes per tool or dynamically trigger scope challenges during tool execution.

Use Case

Consider a server like GitHub's MCP server that wraps an API with granular permissions:

  1. A user connects with a valid OAuth token but minimal/no scopes
  2. They call a tool that may or may not need additional scopes depending on the specific resource (e.g., accessing a public vs private repo)
  3. The server makes a request to its backend service, which responds indicating more scopes are needed
  4. The server wants to pass this back as a scope challenge rather than a failed tool call

Currently, server authors must implement this entirely outside SDK land:

  • Parse raw JSON-RPC
  • Match tool names
  • Check required scopes against active scopes
  • Manually construct and return the 403 response with WWW-Authenticate header

Proposed Features

1. Declare required scopes when registering a tool (minimum viable)

server.registerTool(
  'get_private_repo',
  {
    description: 'Get private repository details',
    inputSchema: { ... },
    requiredScopes: ['repo:read']  // New field
  },
  async (args) => { ... }
);

The SDK would automatically check scopes before tool execution and return a 403 scope challenge if the token lacks required scopes.

2. Dynamically trigger scope challenge during tool execution (ideal)

server.registerTool(
  'get_repo_issue', 
  {
    description: 'Get repository issue',
    inputSchema: { ... }
  },
  async (args, context) => {
    const response = await fetchFromBackend(args);
    
    if (response.needsAdditionalScopes) {
      // Trigger scope challenge mid-execution
      throw new ScopeChallengeError(['repo:read']);
      // or: context.requestScopes(['repo:read']);
    }
    
    return { content: [...] };
  }
);

This would allow servers to defer scope decisions to downstream services and pass through their authorization requirements.

Additional Considerations

  • Scope hierarchy: Some OAuth systems have hierarchical scopes (e.g., repo includes repo:read). SDKs may need to support scope resolution/comparison utilities.
  • Access to current scopes: Tool handlers need a way to inspect what scopes the current token has (perhaps via context parameter).

Related

Context

Discussion from Discord with @SamMorrowDrums (GitHub MCP server author) about server-side SDK support for scope challenges.
https://discord.com/channels/1358869848138059966/1441013745496227870

Activity

  1. SamMorrowDrums commented on Nov 21, 2025

    @SamMorrowDrums
    Contributor

    Changes to streamable http might make this impossible, and perhaps it might need to be rolled into a sort of MCP preflight check eventually?

    modelcontextprotocol/modelcontextprotocol#1862 (comment)

    It's a similar problem, might need to determine certain things before it is possible to make a tool call to keep scopes minimal and accurate tool annotations.

  2. added
    enhancementRequest for a new feature that's not currently supported
    ready for workEnough information for someone to start working on
    P1Significant bug affecting many users, highly requested feature
    authIssues and PRs related to Authentication / OAuth
    on Dec 16, 2025
  3. added
    needs decisionIssue is actionable, needs maintainer decision on whether to implement
    and removed
    ready for workEnough information for someone to start working on
    on Apr 15, 2026
  4. ghost removed
    P1Significant bug affecting many users, highly requested feature
    on Apr 16, 2026
  5. ghost added
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    on Apr 16, 2026
  6. felixweinberger commented on Oct 5, 2026

    @felixweinberger
    Contributor

    Shipped in 2.1.0 with #1624: scopeChallenge on a tool registration answers the call with a 403 scope challenge before the handler runs, and its callback sees the request and the token's scopes. A challenge raised from inside a running handler is tracked in #2957. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Moderate issues affecting some users, edge cases, potentially valuable featureauthIssues and PRs related to Authentication / OAuthenhancementRequest for a new feature that's not currently supportedneeds decisionIssue is actionable, needs maintainer decision on whether to implement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions