spring-projects / spring-projects/spring-ai

MCP server - Support OAuth scopes

Open
#6,740 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

Expected Behavior

I want to build an MCP server that uses OAuth for authorization and requires different OAuth scopes for diffferent tools and resources. According to the MCP spec, an MCP server should respond with something like this if a required scope is missing:

HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
                         scope="files:write",
                         resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
                         error_description="File write permission required for this operation"

Current Behavior

I managed to protect the whole /mcp endpoint with OAuth2 using spring-security-oauth2-resource-server, but I am struggling to enforce scopes on tools/resources.

I tried throwing an OAuth2AuthenticationException which should get handled by spring-security-oauth2-resource-server and create a HTTP 403 response with the correct WWW-Authenticate header.

@Component
public class EchoTools {
    @McpTool(name = "echo", description = "Echo the input string")
    public String echo(@McpToolParam(description = "input string", required = true) String str ) {
        if (SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream().map(GrantedAuthority::getAuthority).noneMatch("SCOPE_echo"::equals)) {
            throw new OAuth2AuthenticationException(BearerTokenErrors.insufficientScope("missing scope", "echo"));
        }
        return "echo: " + str;
    }
}

Unfortunately in spring-ai 2.0.0 this exception gets caught by SyncMcpToolMethodCallback and the MCP server responds with a JSON-RCP error instead:

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Error invoking method: echo\nmissing scope"
      }
    ],
    "isError": true
  }
}

I also tried 2.0.1-SNAPSHOT because the exception handling was changed a bit in https://github.com/spring-projects/spring-ai/pull/6534, but OAuth2AuthenticationException is still converted to a JSON-RPC error because it is a RuntimeException.

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 SyncMcpToolMethodCallback and trace how OAuth2AuthenticationException is converted into a JSON-RPC error, then compare that path with spring-security-oauth2-resource-server handling of BearerTokenErrors.insufficientScope. Reproduce the EchoTools example and verify that a missing scope produces an HTTP 403 response with the expected WWW-Authenticate header instead of an MCP tool error.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
api, backend, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.