Skip to content

Conversation

@bzsurbhi
Copy link
Contributor

@bzsurbhi bzsurbhi commented Jun 7, 2025

OAuth Authentication Support for MCP Java SDK

Overview

This PR adds comprehensive OAuth 2.0 authentication support to the MCP Java SDK, enabling secure communication between clients and servers.

Key Features

  • OAuth 2.0 Authorization Code Flow with PKCE support
  • Server-side authentication middleware for validating access tokens
  • Client-side authentication for obtaining and refreshing tokens
  • Seamless integration with existing transport layer
  • Example Implementation of an authenticated MCP client and server

Implementation Details

Server-Side Components

  • OAuthHttpServletSseServerTransportProvider: Extends the standard transport provider to handle OAuth endpoints
  • AuthContext: Thread-local storage for authentication information
  • BearerAuthenticator: Validates Bearer tokens in Authorization headers
  • ClientAuthenticator: Validates client credentials

Client-Side Components

  • OAuthClientProvider: Manages OAuth flow and token lifecycle
  • TokenStorage: Interface for storing tokens securely
  • HttpClientAuthenticator: Adds authentication headers to outgoing requests
  • AuthenticatedTransportBuilder: Adds authentication to transport builders

Authentication Flow

  1. Client requests authorization via /authorize endpoint
  2. User authenticates and grants permissions
  3. Server redirects to client with authorization code
  4. Client exchanges code for access and refresh tokens via /token endpoint
  5. Client includes access token in subsequent API requests
  6. Server validates token and provides access to protected resources

Example Implementation

The PR includes a complete example in the auth-example directory demonstrating:

  • Server setup with OAuth endpoints
  • Client authentication flow

Breaking Changes

This is a completely new change

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

this.redirectHandler = redirectHandler;
this.callbackHandler = callbackHandler;
this.timeout = timeout;
this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the OAuth HttpClient configurable like it is in HttpClientSseClientTransport?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed an update

Comment on lines 31 to 40
return builder.customizeRequest(requestBuilder -> {
String token = authProvider.getAccessToken();
if (token != null) {
requestBuilder.setHeader("Authorization", "Bearer " + token);
}
}).requestInterceptor(new RequestResponseInterceptor() {
@Override
public CompletableFuture<HttpRequest> interceptRequest(HttpRequest.Builder requestBuilder) {
return authenticator.authenticate(requestBuilder).thenApply(HttpRequest.Builder::build);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like these 2 blocks set the Auth header twice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the redundancy

}

try {
String requestBody = objectMapper.writeValueAsString(clientMetadata);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing with mcp.wix.com I had to add .setSerializationInclusion(JsonInclude.Include.NON_NULL) and .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE). The server did not accept optional fields with null values, and redirectUris had to be redirect_uris. Ideally we just @JsonProperty annotations to the OAuthClientMetadata object according to the spec.

throw new RuntimeException("Registration failed: " + response.statusCode());
}
try {
return objectMapper.readValue(response.body(), OAuthClientInformation.class);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with mcp.wix.com this failed because the server returned an unknown registration_client_uri. OAuthClientInformation should probably have @JsonIgnoreProperties(ignoreUnknown = true)

Comment on lines +172 to +176
String authUrl = buildAuthorizationUrl(clientInfo);

// Redirect user for authorization
return redirectHandler.apply(authUrl)
.thenCompose(v -> callbackHandler.apply(null))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we untie, or at least allow executing these steps independently?

In many cases I can imagine the URL generation, and the callback visit cannot be part of the same process that gets blocked until the user responds. So we would need to allow storing state during URL generation, and looking it up during the callback for the final token exchange.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realised this problem is shared across SDKs. Also opened an issue in the python SDK modelcontextprotocol/python-sdk#992

@bzsurbhi
Copy link
Contributor Author

@andrey-star thanks for reviewing the PR, I'll address your comments by tomorrow

@stantonk
Copy link
Contributor

@bzsurbhi really excited for this!! :)

@stantonk
Copy link
Contributor

stantonk commented Jun 21, 2025

@bzsurbhi i've spent some time reviewing, I am curious how Authn/Z can be performed on a per-tool basis, e.g. like https://quarkus.io/blog/secure-mcp-sse-server/#tool?

Authn/z for connecting to an MCP Server and then having access to all of its Tools, Prompts, etc. is insufficient for many use cases.

@jgrandja
Copy link

@bzsurbhi Thank you for your initiative with this MCP Authorization implementation. At first glance, there is quite a bit of code to digest here which makes it difficult and time consuming to review.

I'm not sure if you noticed the Contributing Guidelines:

For non-trivial changes, please clarify with the maintainers in an issue whether you can contribute the change and the desired scope of the change.

I'm guessing you did not see it, since this was only recently added (May 16). Either way, before any major features are added to a release, it's very common in the OSS world to have an initial discussion with the team and community to see if the feature is needed or in demand from the community perspective. If it is, then it would be prioritized for a specific release. Furthermore, if the feature has an added level of complexity then it likely will get broken down into sensible chunks of work that can more easily be reviewed and ultimately merged.

Having said that, we are already tracking this major feature in spring-security#16992 and have been having ongoing discussions around implementation strategies for providing this support.

Many years have been invested in providing OIDC/OAuth2 support in Spring Security and Spring Authorization Server so the plan is to reuse this expertise as one of the implementation strategies.

We realize that some of our target audience are not Spring users so we do need to address that end as well. I will say that application security is a cross cutting concern and we will likely not embed the security logic directly in the Java SDK. Instead, we will define hooks where MCP Authorization implementations can plug into to provide the features defined in the spec.

I hope this all makes sense?

@stantonk
Copy link
Contributor

@jgrandja glad to see it is on y'alls radar. I am curious how folks can plug into the efforts there or get additions here in the framework agnostic SDK, as the lack of various forms of Authentication & Authorization capabilities are a huge blocker for pretty much anyone who wants to put stuff into production -- and there's more approaches required than the full OAuth 2.1 spec since not every internal-only architecture fits well with the full blown OAuth 2.1 approach.

@bzsurbhi
Copy link
Contributor Author

@bzsurbhi i've spent some time reviewing, I am curious how Authn/Z can be performed on a per-tool basis, e.g. like https://quarkus.io/blog/secure-mcp-sse-server/#tool?

Authn/z for connecting to an MCP Server and then having access to all of its Tools, Prompts, etc. is insufficient for many use cases.

@stantonk The current implementation only handles server-level authentication, similar to the python-sdk. The specification doesn't currently address tool-specific authorization controls.

@asaikali
Copy link
Contributor

asaikali commented Jun 23, 2025

@stantonk I see this as a design tradeoff about layering and responsibility.

To keep the MCP SDK truly framework-agnostic, we need to acknowledge that it can’t—and shouldn’t—do everything on its own. Especially for remote servers, a host framework (like Spring, Quarkus, or Micronaut) is essential. It handles things the SDK isn’t designed to own: HTTP, security, and application wiring.

Responsibilities of the host framework:

  • HTTP request routing – e.g. url of the MCP server /mcp, /checkout/mcp, or something else
  • Security stack integration – including support for:
  • Idiomatic integration – security configuration, DI, error handling, observability, and other platform-native behaviors

The idea is that MCP server authors should be able to pick the framework they already use and build a secure, idiomatic MCP server using its existing infrastructure.

Responsibilities of the MCP SDK:

The SDK’s job is to provide a clean, minimal surface for protocol compliance. That includes:

  • Core message types that represent the JSON-RPC protocol used by MCP
  • Pluggable interfaces for things like session handling (e.g. how to manage Mcp-Session-Id)
  • Abstractions for protocol-level concepts, like tools and prompts, without assuming any specific transport or runtime

This separation allows host frameworks to do what they do best—HTTP and security—while the SDK stays focused, portable, and easy to embed across stacks.

If we push host-layer concerns like OAuth or routing into the SDK itself, we risk making it heavy, opinionated, and harder to maintain. Drawing this clear boundary keeps the SDK lean and gives each host framework the flexibility to integrate in a way that feels natural to its ecosystem.

And importantly: this also means that developers building production-grade MCP servers should not be working directly with the MCP SDK most of the time. They should rely on their host framework's integration layer—which wires up the SDK behind the scenes using idiomatic patterns they already know. In the ideal case, most app developers don’t even need to know the SDK exists.

@stantonk
Copy link
Contributor

@asaikali I understand the desire to have separation of concerns, but the idea that the official MCP implementation for Java (or any language for that matter) is neither production-grade, nor enables implementation of common sense security (including what is part of the specification), doesn't make any sense.

The current state of the interfaces and implementations actively fight putting authentication and authorization into individual Tool calls, which is a requirement for any responsible, production implementation of MCP. That's a much lower lift / maintenance burden than having all of the OAuth implementation present here. It's built directly on top of Servlet, and should allow for using all of the existing ecosystem of higher order libraries to add authentication and authorization as companies see fit.

Ultimately people should not be required to use Spring or Quarkus to build with MCP safely.

Where is the best place to discuss further? I and @bzsurbhi are certainly highly motivated to help out here and contribute in the most effective way for the project! I think there's a fairly smaller set of changes that could be made that at least make it possible for greater pluggability into other frameworks and codebases that are Servlet based and have pre-existing authentication and authorization libraries and requirements.

@asaikali
Copy link
Contributor

asaikali commented Jun 24, 2025

@stantonk I agree with your statement "Ultimately people should not be required to use Spring or Quarkus to build with MCP safely." that does not mean that MCP SDK should implement the OAuth RFCs needed per the Streamable HTTP spec. So what is the right way to do it?

create a project that depends on the mcp-java-sdk that integrates into servlets exactly the way you want to do it without needing Spring or Quarkus. As you implement this project if you find that the sdk is not exposing the hooks that you need, then contribute those hooks via issues, or pull requests, demos to help evolve the sdk so that it can be embedded inside a host framework. This enables the whole community to benefit and helps stress test the API surface of the SDK.

Can you elaborate on what you mean by

The current state of the interfaces and implementations actively fight putting authentication and authorization into individual Tool calls, which is a requirement for any responsible, production implementation of MCP.

I am assuming you want to be able to ask the sdk what user is currently making the request, and what permissions do they have? Is my assumption correct?

@jgrandja
Copy link

@stantonk

and there's more approaches required than the full OAuth 2.1 spec since not every internal-only architecture fits well with the full blown OAuth 2.1 approach

Agreed. And the spec clearly states:

Authorization is OPTIONAL for MCP implementations.

Implementations using alternative transports MUST follow established security best practices for their protocol.

Obviously, for a production deployment, secured interactions is a strict requirement, however, it appears that OAuth2 is not necessarily required and any industry standard appsec protocol can be used.

This further validates that an OAuth2 implementation, or any appsec protocol implementation SHOULD NOT live in the Java SDK.

I think there's a fairly smaller set of changes that could be made that at least make it possible for greater pluggability into other frameworks and codebases

At this point, I am thinking the same in that we might need to define a smaller set of core interfaces in the Java SDK that provide an abstraction around a "Security Context" and/or "Security Identity". Whatever these abstractions end up being, these will ultimately be the extension points for the external security frameworks/libraries (e.g. Spring Security).

One last point that I would like to re-emphasize is:

appsec protocol implementation SHOULD NOT live in the Java SDK

Application security is a very specialized domain that needs to be handled by engineers that work in that domain. If we were to embed that logic into the Java SDK, it would highly complicate the codebase and introduce very high risk. The OAuth2 set of specifications is a maze that one can easily get lost in. It has taken me many years to develop the expertise and it's not viable or sustainable for an engineer to "ramp up quickly" and provide security-related enhancements via PR's. Going down this path could easily introduce CVE's into the SDK and effectively lose the trust in the community leading to project failure. We need to be very careful with the next steps that we take.

Lastly, where do we stop? With an embedded OAuth2 implementation? What about SAML or mTLS or other authn/authz standards? I guarantee that if we provide an embedded OAuth2 implementation, other users will ask to support another authn/authz standard and this will ultimately put us in a bind.

@stantonk
Copy link
Contributor

@jgrandja

First of all, really appreciate you taking the time to respond and discuss! ❤️

and there's more approaches required than the full OAuth 2.1 spec since not every internal-only architecture fits well with the full blown OAuth 2.1 approach

Agreed. And the spec clearly states:

Authorization is OPTIONAL for MCP implementations.

Implementations using alternative transports MUST follow established security best practices for their protocol.

Obviously, for a production deployment, secured interactions is a strict requirement, however, it appears that OAuth2 is not necessarily required and any industry standard appsec protocol can be used.

Agreed! We're on the same page.

Application security is a very specialized domain that needs to be handled by engineers that work in that domain. If we were to embed that logic into the Java SDK, it would highly complicate the codebase and introduce very high risk. The OAuth2 set of specifications is a maze that one can easily get lost in.

Appreciate you calling this out, it's a really important consideration!! It helps inform why the separation of concerns makes sense, while still needing to create interfaces that allow for more flexibility and give downstream frameworks and teams ways to integrate the Authn/Z they require.

At this point, I am thinking the same in that we might need to define a smaller set of core interfaces in the Java SDK that provide an abstraction around a "Security Context" and/or "Security Identity". Whatever these abstractions end up being, these will ultimately be the extension points for the external security frameworks/libraries (e.g. Spring Security).

Yes!!! This in line with what I am thinking, that was my point here:

The current state of the interfaces and implementations actively fight putting authentication and authorization into individual Tool calls, which is a requirement for any responsible, production implementation of MCP. That's a much lower lift / maintenance burden than having all of the OAuth implementation present here. It's built directly on top of Servlet, and should allow for using all of the existing ecosystem of higher order libraries to add authentication and authorization as companies see fit.

Some kind of context object that is passed to all handlers of Client Messages would be ideal, but Tool Calls are so ubiquitous already that IMO starting there is really key.

To me it should be similar to how REST API frameworks have a context that includes things like the HTTP Headers, but perhaps also a set of K/V pairs that can be used for other context types that don't strictly fall under HTTP Headers.

Next steps:

  1. I already have a working example of Dropwizard + this Java SDK, I can put it up somewhere on github and take an initial crack at carrying the context down into the SyncToolSpecification and AsyncToolSpecification and share it here. How does that sound?
  2. If you already have some ideas on how this might work more generally, I'd love to see a mockup / pseudocode of what you're thinking.
  3. To your last question:

Lastly, where do we stop? With an embedded OAuth2 implementation? What about SAML or mTLS or other authn/authz standards? I guarantee that if we provide an embedded OAuth2 implementation, other users will ask to support another authn/authz standard and this will ultimately put us in a bind.

I see where your concern lies and it does make sense. The tricky part to me is you want to have enough "examples" of ways people wish to hook into the interfaces you expose in the SDK so you can develop a robust and flexible enough set of interfaces, and having real implementations to vet the interfaces is really helpful -- but you don't want to make them part of the SDK. Maybe a separate module that is only for integration testing? What have you seen work well in the past?

@Zizo-Vi
Copy link
Contributor

Zizo-Vi commented Jun 26, 2025

@bzsurbhi do we support Client Credentials grant type when the client is another application (not a human)?
https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#oauth-grant-types

image

@asaikali
Copy link
Contributor

asaikali commented Jun 26, 2025

@bzsurbhi do we support Client Credentials grant type when the client is another application (not a human)? https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#oauth-grant-types

According to the spec, the MCP server is an OAuth resource server. When the Mcp server gets a request, the host security framework extracts the http Authorization: Bearer header to get the access token, the security framework then validates the access token. The resource server does not know how the access token was created by the authorization server.

If the authorization server configured for the MCP server supports client credentials then you can use client credentials from the MCP client to obtain the access token and call the upstream Mcp Server.

If the client application is running on platform that issues application instance credentials it can trade those instance identity creds for an access token with the authorization server. For example, if the app is running on Kuberentes, it has JWT for a k8s service account, you can configure the Authorization server so that you can trade the k8s service account JWT for an access token to the MCP server. The configuration of something like this can be quite complex because there are a lot of security concepts that need to be understood, and the details depend on the platform like k8s, or a cloud provider.

Checkout this blog post https://aaronparecki.com/2025/05/12/27/enterprise-ready-mcp from an OAuth industry guru that gets into a lot of the details.

@bzsurbhi
Copy link
Contributor Author

@bzsurbhi do we support Client Credentials grant type when the client is another application (not a human)? https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#oauth-grant-types

The current implementation doesn't have support for client_credentials grant type. I was planning on adding that after these changes

@jgrandja
Copy link

@stantonk

I already have a working example of Dropwizard + this Java SDK, I can put it up somewhere on github and take an initial crack at carrying the context down into the SyncToolSpecification and AsyncToolSpecification and share it here. How does that sound?

That sounds good. I would like to see what ideas you have as well. Please share the GH repo.

If you already have some ideas on how this might work more generally, I'd love to see a mockup / pseudocode of what you're thinking.

I've been working with @Kehrlann who has been proofing out the OAuth2 integration. Please include Daniel as well and let's see what we can come up with.

you want to have enough "examples" of ways people wish to hook into the interfaces you expose in the SDK so you can develop a robust and flexible enough set of interfaces, and having real implementations to vet the interfaces is really helpful -- but you don't want to make them part of the SDK. Maybe a separate module that is only for integration testing? What have you seen work well in the past?

We should come up with at least 3 different examples each with their own authn/authz mechanism to ensure the core interfaces we introduce work for each of the 3 use cases. A separate module that is for integration testing is a good idea as well that we can consider.

@karianna
Copy link

karianna commented Jul 9, 2025

Hey folks, just adding a +1 here for framework agnostic support. We definitely have use cases where we would not want to rely on a framework like Spring or Quarkus to deliver the functionality of a Java based MCP tool. We definitely appreciate all of you doing the heavy lifting to add the OAuth MCP Security Spec support! Happy to test things as you folks have a alpha/beta for us to try as an extra use case.

@iamjatindersingh
Copy link

iamjatindersingh commented Jul 23, 2025

+1 on the amazing work in this PR—really well done! Just wanted to add a thought around another potential use case: the MCP server (remote) could sit behind a Gateway that fronts multiple MCP servers (remote) and provides standardized security aligned with the specification, especially OAuth2.1 and other best practices. In this setup, the Gateway would handle security in a centralized manner for all MCP servers—including tapping into fine-grained Authorization if needed—and obtain an Access Token, which is then passed to the MCP server to call any upstream applications. This allows the MCP server to remain lean, focusing only on processing requests with a valid token.

@jgrandja
Copy link

@chemicL @tzolov In case you are not aware, there is a proposal for changing the authorization interaction between the MCP Client and Server. See SEP-1299: Server-Side Authorization Management with Client Session Binding

In short, the proposal is to remove OAuth between the Client and Server and replace it with RFC 9421 HTTP Message Signatures. Authorization would be implemented at the MCP Server and local/upstream Resource Server(s), however, it wouldn't be required to use OAuth and would instead be left to the decision of the implementor how Authorization would be implemented/enforced.

FWIW, the SEP-1299 proposal does make a lot of sense to me and it will be very interesting to see where it goes.

Having said that, I would not be looking at merging this PR as I do believe major changes are coming.

@LucaButBoring
Copy link
Contributor

Having said that, I would not be looking at merging this PR as I do believe major changes are coming.

I haven't gotten any signals that SEP-1299 is going to be merged in the near future (certainly not by the next spec release), and I would be very surprised if it were merged in a way that creates a complete break with existing OAuth patterns. Given that MCP servers are using OAuth today and the Java SDK is already months behind on this front, I don't see a reason to hold off even longer just because it's possible that changes will happen in the future.

I do believe the authentication scheme should be pluggable, and perhaps this PR should be scoped down to not include a server implementation (per the guidance from modelcontextprotocol/modelcontextprotocol#1061), but it wouldn't help anyone to leave this in limbo for another month or longer.

@Zizo-Vi
Copy link
Contributor

Zizo-Vi commented Aug 19, 2025

Having said that, I would not be looking at merging this PR as I do believe major changes are coming.

I haven't gotten any signals that SEP-1299 is going to be merged in the near future (certainly not by the next spec release), and I would be very surprised if it were merged in a way that creates a complete break with existing OAuth patterns. Given that MCP servers are using OAuth today and the Java SDK is already months behind on this front, I don't see a reason to hold off even longer just because it's possible that changes will happen in the future.

I do believe the authentication scheme should be pluggable, and perhaps this PR should be scoped down to not include a server implementation (per the guidance from modelcontextprotocol/modelcontextprotocol#1061), but it wouldn't help anyone to leave this in limbo for another month or longer.

@LucaButBoring Totally agree! Now most MCP servers are using OAuth, and Java SDK is behind for months. Hopefully this PR can be merged ASAP.

@bzsurbhi Could you please also implement this OAuth things on the Streamable HTTP transport? The latest version of this Java SDK has already support Streamable HTTP Transport.

@ericdallo
Copy link

Any news on that? support for http streamable is a really nice to have thing as most remote MCP servers are adopting that.

c/c @bzsurbhi

@karianna
Copy link

karianna commented Dec 3, 2025

@jgrandja - I see that spring-projects/spring-security#16992 landed. Is there a plan to port the appropriate parts of that implementation to this SDK? It would be great for this core SDK to meet the MCP Auth specification. We (Microsoft) are happy to help but if there's already known good impls out there we'd rather start with those and not reinvent the wheel as such :-).

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 3, 2025

@karianna while we have added (some) of the building blocks for MCP authz in Spring Security proper (Dynamic Client Registration & Protected Resource Metadata), we have no plans to bring this into the SDK itself. Instead, we provide enough hooks for frameworks to plug their own authz. See the "Architecture & Design Decisions" section in the README of this project, specifically 4. Remote MCP Clients and Servers > Authorization in the SDK

On the Spring side, we have an MCP-Security project.

What has been discussed in the past is that if we want a "framework agnostic" authz layer, then we'd prefer having this outside of this repo, because we on the Spring team don't have the bandwidth to maintain a second implementation, nor to handle the potential CVEs.

@karianna
Copy link

karianna commented Dec 3, 2025

@karianna while we have added (some) of the building blocks for MCP authz in Spring Security proper (Dynamic Client Registration & Protected Resource Metadata), we have no plans to bring this into the SDK itself. Instead, we provide enough hooks for frameworks to plug their own authz. See the "Architecture & Design Decisions" section in the README of this project, specifically 4. Remote MCP Clients and Servers > Authorization in the SDK

On the Spring side, we have an MCP-Security project.

What has been discussed in the past is that if we want a "framework agnostic" authz layer, then we'd prefer having this outside of this repo, because we on the Spring team don't have the bandwidth to maintain a second implementation, nor to handle the potential CVEs.

Looking back I'm referencing: #297 (comment) it seemed that there was a plan to pull something together, is it safe to assume that's no longer the case and we should look to proceed with this PR?

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 4, 2025

Looking back I'm referencing: #297 (comment) it seemed that there was a plan to pull something together, is it safe to assume that's no longer the case

We have pulled something together on the Spring side. This drove many changes in the SDK to have the appropriate hooks to make authorization possible.

and we should look to proceed with this PR?

Unsure what you mean by "proceed with this PR", but I think this PR should be closed entirely:

  1. It does not use the hooks that were added more recently
  2. It is thoroughly outdated, and provides authz for the SSE transport, following the 2025-03-26 spec
  3. It is incomplete, even for the SSE transport
  4. It is not compatible with third party frameworks who would want to bring in their own authz
  5. It directly contradicts the architecture decision mentioned in my previous comment, "Pluggable authorization hooks for MCP servers; no built-in implementation" (source)

We are open to collaborating with framework maintainers and downstream projects (as we did with Spring and Micronaut). If the goal is to implement framework-agnostic authz for MCP, the best course of action is to setup a new project dedicated to it. If there's anything the core SDK is missing to make this work, we'll happily collaborate to make it possible. If that projects gets robust community support, then we can revisit our decisions.

@Kehrlann Kehrlann closed this Dec 4, 2025
@Kehrlann Kehrlann added the wontfix This will not be worked on label Dec 4, 2025
@ericdallo
Copy link

Just to add that as a Clojure user of this lib, I have no interest in spring inside the SDK, and I wish we have auth hooks to code even on my side, which doesn't seem possible ATM

@graemerocher
Copy link
Contributor

@Kehrlann can you point to how this was integrated on the Spring side?

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 4, 2025

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 4, 2025

@ericdallo could you please clarify what you're expecting exactly, and what you're missing? Possibly in a separate issue.

@meliora
Copy link

meliora commented Dec 4, 2025

@Kehrlann Are these referenced authentication-related hooks ("that were added recently") documented somewhere? Or is there a PR or Issue somewhere that contains the impl. of these? Just to clarify: The interest is on the "server" side of things - Are there any hooks available to (more easily) handle authorization there?

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 4, 2025

@meliora please note that these are not authn/authz -only hooks ; they are the hooks you need to implement your own authz.

Client-side, you can use McpSyncHttpClientRequestCustomizer and the async variant (docs) for HttpClient, and an ExchangeFilterFunction for WebClient (docs). These APIs allow you to modify outgoing HTTP requests. In the case of authz, this is where you add your Authorization: Bearer <...> header. You possibly need to add context information that these APIs can access through the TransportContextProvider API (docs).

Server-side, you can extract "request context" data from the incoming HTTP request with McpTransportContextExtractor, (source). This is made available in the McpSyncExchange or McpAsyncExchange of your handlers (see tools handler example). I need to write a blurb in the docs about this.

@ericdallo
Copy link

Client-side, you can use McpSyncHttpClientRequestCustomizer and the async variant (docs) for HttpClient, and an ExchangeFilterFunction for WebClient (docs). You possibly need to add context information through `TransportContextProvider (docs).

You can extract "request context" data from the incoming HTTP request with McpTransportContextExtractor, (source). This is made available in the McpSyncExchange or McpAsyncExchange of your handlers (see tools handler example). I need to write a blurb in the docs, on the server-side.

@Kehrlann I may be interested on this part as I'm using a MCP client that may need to authenticate with MCP servers like Github etc, am I right?

@Kehrlann
Copy link
Contributor

Kehrlann commented Dec 4, 2025

@ericdallo if you're writing a client, then only the first paragraph matters ; you capture data like personal access tokens or OAuth2 access tokens however you'd like, and then inject them into outgoing HTTP requests.

The second paragraph is for writing MCP Servers.

I've clarified my comment above to reflect this.

@meliora
Copy link

meliora commented Dec 5, 2025

@Kehrlann Thanks for the clarification, much appreciated. The README.md of the SDK states that it has "pluggable authorization hooks for MCP servers" which is, in my opinion, a bit misleading - as you said, it might be good to clarify this. The hooks you mentioned give an opportunity to intercept the incoming (and outgoing) requests. With these, currently, all MCP server implementors using the SDK will have to, in reality, implement the OAuth 2.1 from the ground up, which is bad from a security point of view. Having something like the "OAuthAuthorizationServerProvider" in this PR would really be quite ideal.

Edit: To add to the above, I was not clear on the fact that I'm not saying or suggesting the OAuth 2.1 bindings should be the responsibility of this SDK per se. I was talking in a general sense: if there were a different library (project) providing these on top of this SDK (like @asaikali above suggested), it would be fine with me. All architectural decisions discussed in this PR are justified as long as the implementation is agnostic (not relying on Spring for example).

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

Labels

wontfix This will not be worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.