spring-projects / spring-projects/spring-ai
MCP server - Support OAuth scopes
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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