modelcontextprotocol / modelcontextprotocol/typescript-sdk

Server SDK support for scope challenges on tool calls

Open
#1,151 1 comment 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auth enhancement needs decision P2
Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
3d 15h
Merged PRs (30d)
4

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with SEP-835 and the linked Python SDK OAuth implementation to understand scope-challenge semantics, then locate the TypeScript SDK's tool-registration and server authorization entry points; the issue names no TypeScript files or tests. Define and test both declared tool scopes and dynamic challenges, including the 403 response and WWW-Authenticate header behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, authentication, authorization
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.