Multi-user Authorization #234
Replies: 12 comments 16 replies
-
|
Big plus to this proposal! We encountered the exact same concern of In addition to Wils' proposal, to make MCP Server even more stateless, we can add more variants to the authorization field, to support more auth types required by building Tools with underlying services. MCP Server transparently forwards the auth tokens from client to the underlying service, and relies the underlying service to validate token. For example: In this case, it allow production MCP Server to optionally run with no auth requirements. It runs like an API Gateway, that only does request conversion and forwarding. This could make production MCP servers much more scalable. Regarding Wils' open question:
Why could MCP Client but MCP Server own the token? Think of this story: In some company, Customer Support IT department is developing their Customer Support agent, which needs access to their internal systems.Customer Support department has an existing web based application, application backend server, and have already got the credentials to connect their application backend server to other services (say Order Management service) hosted by other departments. The Customer Support backend server uses API Key to connect to Order Management service. Order Management Service also accepts connections from other department using other API keys. Order Management department wants to build a lightweight MCP Server for everyone, to avoid every single department to build MCP server for order management. Since Order Management department already a service (as an internal API) already, they want make a Order Management MCP Server that everyone inside this company can use. They don't have much bandwidth to implement the MCP Server, and want it to be as lightweight as possible. An OAuth based MCP Server is a bit too heavy - The API Key they've been using for years has already handles the authentication, and the roles associated with the API Key handles authorization. Having OAuth doesn't provide any additional value add. Back to Customer Support IT department, they have API key configured with their backend service. They want to use the same API key to connect to all services provided by the Order management department, including the new Order Management MCP Server. In this case:
We believe that this story happen very frequently across enterprises, and it would be hard for enterprise to implement an extra OAuth layer and additional auth scopes. Making auth requirement optional from MCP server while making MCP a transparent proxy that forwards client tokens would have huge benefit in boosting MCP adoption for enterprises. Let us know what you think! |
Beta Was this translation helpful? Give feedback.
-
|
Requiring that the MCP client has direct access to access tokens/keys to 3rd party services seems like it goes against the point of the MCP server itself issuing its own token — which ensures that the MCP client never has a token that grants direct access to the 3rd party service. This is an important part of the design of the spec, as it ensures that even if the client token is compromised, a bad actor doesn't gain direct access, only access to tools/resources/etc that the MCP server exposes. It does however seem to me like it could sense for MCP tools to be able to specify the scopes they need, or for there to exist some other way for the MCP server to say, "you don't have the right authorization(s) to use this tool" — and then send the end user through the relevant authorization flow to obtain this permission. Another example of this would be #256 – how would a tool call respond with "unauthorized" — and then how would the MCP client know to send the end user through authorization flow? Certainly ways to hack around this in userspace, but does seem like there could be benefit to standardizing this so that clients handle it the same way. |
Beta Was this translation helpful? Give feedback.
-
|
Supporting separate access levels for tools makes sense. However, I don't think anything is needed to be added to each resource type in the API to do this, and existing standards can be used. (This proposal doesn't really need to refer to anything being "multi-user" since that already is already supported by the OAuth spec. But point taken that part of supporting multiple users is that each user can have access to different tools) My impression is an example way to accomplish this is:
My impression is this is standard and how any OAuth flow would work for any API and does not need anything MCP specific. It could be improved with #195 which could be another way to provide scopes as well. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @irvinebroque @wdawson for the insight! So far there are two somehow overlap, but very different user flows. I'd like to clarify about the differences before proceeding with the discussion. MCP Client as End User client (Claude Desktop), MCP Server hosted locallyIn this case, MCP Client act as "something runs together with the end user", like Claude Desktop. Currently this is 99% the case, given most servers are local stdio servers or npx / pypi packages served on stdio (from mcp.so, awesome-mcp-servers in Github, and from the example servers from MCP). Both MCP Server and MCP Client runs on the desktop of the end user. MCP Servers are like Apps we installed on our mobile phone, our VS Code Extensions, or our npm packages downloaded from the npmjs registry. Say the use case for MCP is "A user want's to upload a doc from Google Drive to Claude Chat":
For GenAI User to use Google Drive, they have to get 2 credentials
The problems with this model are:
MCP Client as Intermediate Client, MCP Server hosted remotelyThis flow implies a different journey. Now MCP Client is NOT with the user. Instead, it is an Agent created by a random company with an Agent SDK supporting MCP. Agent is a Python application code sitting on an application server hosted by that company. The MCP Server is no longer the npx/pypi package installed by the end user, it's a HTTP Server hosted internally. On the MCP Server it hosts the tools internally/externally to that company. MCP Servers are like numerous APIs we use from the web. This is the case we envision MCP Servers to get into production. It's not the only way, but should be one of the most common paradigms. Also in this case, per @wdawson
This journey has similar parties, but a very different architecture. Let's say "A user is using Amazon Shopping Agent, and wants to upload a picture they want to search, with a photo from Google Drive"
This has a great user experience:
What should "Auth on MCP Server" protect against?
Agree that MCP Server should have its own OAuth scope. MCP Server hosts Tools, Prompts and Resources, they are all resources and should be carefully protected. Additionally, not all Tools are leveraging existing backends. Some tools may be running complex Python logic, but not talking to any backend services. These tools themselves becomes valuable resources that definitely need to be protected. Thus, if there are indeed a strong need, MCP Server should ask user for an OAuth login so that "User can use the tools provided by that MCP Server (not the consumed services, just the tools)". And per @irvinebroque
I'm not sure if we should store auth tokens on MCP Server. It's great for performance - as caching tokens reduces the need to login every time a tool is invoked. However this also means if a server is compromised, lots of tokens for lots of different services are leaked all at once. Although production MCP Servers are OAuth protected, a carelessly designed MCP Server could still result in token leakage, if the tokens are not properly stored and encrypted. Should MCP Server always ask for an OAuth login?Maybe, but not always. If a MCP Server does have to protect its tools, it must be OAuth protected. However, if a MCP Server simply exposes Tools that are already mature and public and well protected by existing security mechanisms, MCP Server itself should be able to work as a lightweight proxy. In this case, it may not ask for auth, but works as an auth exchange forwarder. The MCP Client owns part of the credentials (say OAuth client secrets), and the GenAI user owns the other part (the password, the token). This grants the maximum safety, as if the token is leaked, it can only be leaked from the end user, and affects just that auth grant to that service. No other services will be affected. As most of the modern services have matured auth protection and expose them as APIs that everyone can access, lots of MCP Servers should work this way. If some, or many tools is a "pass through to the underlying service", why not relying on the existing auth mechanisms from them? Should MCP Server require auth scope?If MCP Server requires OAuth, then yes. If a MCP Server hosts lots of Tools, and the server owner wants a granular access, they can do it both ways:
Auth scope is not the solution, but it's a good enough one to start with. |
Beta Was this translation helpful? Give feedback.
-
|
Great proposal and discussions. There are indeed significant challenges around authorization in multi-user, multi-service MCP agent systems. From an authentication/authorization standpoint, these scenarios represent solved problems in established environments. Enterprise contexts like the sales agent example from @wdawson typically leverage federation and SSO solutions. Consumer environments like Google Drive already implement granular OAuth scopes for varying use cases (https://developers.google.com/workspace/drive/api/guides/api-specific-auth). The core challenge is integrating these existing solutions into the MCP ecosystem. I think focusing on OAuth is a pragmatic first step:
|
Beta Was this translation helpful? Give feedback.
-
|
Hi @wdawson and everyone, Great discussion. Handling authorization correctly in multi-user agent scenarios where different users need access to different external services via MCP is definitely necessary for production systems. As the developer of the Ithena Governance SDK ( My perspective:
Overall, I think the proposal to have clients pass necessary external service tokens via Looking forward to seeing how this evolves! |
Beta Was this translation helpful? Give feedback.
-
|
This is interesting from the server development perspective, but it seems to blur the trust boundary between MCP client and server. Ideally, the server would act as an API gateway or passive proxy, but in practice, it can be considered a kind of man-in-the-middle, which could introduce attack vectors, especially with remote MPC servers. When using remote MCP servers, it makes more sense for users to trust the server over the MCP client, since the server is the one accessing user resources. e.g. in OAuth flows, it seems more reasonable for users to consent to the MCP server instead of the MCP client. That way, if something goes wrong, users can revoke access by tracking the server’s ClientId with the auth provider. If we shift this trust to the MCP client (e.g., Claude, Cursor), then by approving access, users are trusting the MCP client to securely handle auth tokens. But based on this proposal, the client may share those tokens with tool developers and servers, which doesn’t align well with OAuth principles. If the MCP server is run by the resource provider (e.g., Google for Gmail), they likely already offer authorization, so it would make sense to host the MCP server behind that existing auth system. This setup simplifies implementations for 3rd-party MCP providers, but those are the entities outside the original resources trust boundary, which in fact need stronger authentication. Also, if this is believed to be the right model, is there a reason auth tokens are sent via _meta in the RPC request instead of standard Authorization headers in the Http request? |
Beta Was this translation helpful? Give feedback.
-
|
fyi I added a link to this discussion about documenting a convention of |
Beta Was this translation helpful? Give feedback.
-
|
@wdawson — thanks for putting together this discussion. Fine-grained control totally makes sense, and I’d love to see it encompass not just tools but the underlying resources as well. A couple of additional thoughts: Adding _meta for clients & new error codes – really like this; it gives clients a clear contract and room for future expansion. Beyond simple scope – I’m not convinced scope alone will cover cases where different tools need different auth servers. One option is to use /.well-known/oauth-protected-resource/ in two ways: As a single GlobalResource (the current proposal) that applies to the whole MCP. Or allow callers to request a specific resource, e.g. Suggested flow – if the user calls a tool/read resource and receives an auth error, the client could: Hit the relevant oauth-protected-resource endpoint. Unified stdio discovery – could we expose the same /.well-known/oauth-protected-resource discovery endpoint for raw stdio sessions? We have CLI/stdio clients that run over SSH, and giving them an identical discovery path would keep the auth flow consistent across transports. Curious what you (and others) think — especially whether the per-resource option would simplify multi-tenant or mixed-auth setups. Thanks again for driving this conversation forward! |
Beta Was this translation helpful? Give feedback.
-
|
Hey folks! Thanks for all the discussion! After some deliberation with Anthropic and others around the Authorization spec and others, @nbarbettini and I have created the user interaction spec to get a lot of what we think we'll need here. Please check those out! It's not exactly what's in this discussion, but since we now have Authorization, I think the context of this discussion needs to be different if it should continue. I'm going to close this as a result. Thanks again for all the ideas! |
Beta Was this translation helpful? Give feedback.
-
|
@wdawson Circling back on this. I think there’s still a significant open question when the MCP Server is acting purely as a Resource Server and doesn't need to call out to third-party APIs. A lot of the surrounding discussion seems to assume that it does, but that's not always the case. I can see how #475 tackles the delegated access scenario for downstream tools, but what about first-party tools that require their own scopes, even though there's no passthrough involved? Thanks for your thoughts! |
Beta Was this translation helpful? Give feedback.
-
|
Curious what the outcome of this was? I'm trying to understand if it's bad practice to pass user session or token information via the |
Beta Was this translation helpful? Give feedback.


Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Pre-submission Checklist
Your Idea
Proposal: Multi-user Authorization
Hello everyone! I’d like to propose adding tool-level authorization to MCP. This would let servers declare which OAuth scopes a tool needs and let clients pass user tokens at call time. Passing tokens at call time unlocks the ability for MCP servers to be multi-user.
I can open a formal PR, but I want to gather community feedback first to refine the solution.
Background
Recent discussions highlight the need for a clear, standardized way to handle multi-user authorization at the tool level:
We already have MCP Authorization describing how clients authenticate themselves to servers. However, that doesn’t solve tool-level authorization—especially if an agent is acting on behalf of multiple end users who each have multiple OAuth tokens for external services.
For example, imagine a sales agent (as a service) that manages leads, contacts, and opportunities in Salesforce or Hubspot from recordings of Zoom meetings, on behalf of many human end-users (salespeople). Each end-user needs to authorize OAuth connections to those services so the agent can act on their behalf by interacting with tools expressed by MCP servers. These servers ultimately must call the APIs of those services with user-specific OAuth tokens for each end-user.
The key here is that the agent would be both multi-user (it services many end-users), and each end-user could have tokens for multiple external services. The agent may leverage one MCP server that connects to all of those services, or several MCP servers, each connected to a subset of services.
Proposal
1. Tools declare required authorization in
tools/listServers MAY add an
authorizationfield to a Tool schema object:{ "name":"zoom_listPastMeetingParticipants", "authorization":{ "method":"oauth2", "requiredScopes":[ "meeting:read:list_past_participants" ] }, "description":"List the participants of a past meeting", "inputSchema":{ "type":"object", "properties":{ "meetingId":{ "type":"string", "description":"The Zoom meeting ID" } }, "required":[ "location" ] } }method: either"oauth2"(meaning a scoped bearer token is required) or "none" (no token needed). This can be extended with other methods in the future.Note:
"oauth2"here means OAuth 2.0 broadly, including (but not mandating) OAuth 2.1. See the note in step #2 about which flow the client SHOULD implement.requiredScopes: ifmethod == "oauth2", the server MAY include an array listing the OAuth scope(s) needed by this particular tool. Not all services use scopes, so this array MAY be empty.2. Client supplies the token in
tools/callWhen the client wants to call a tool that needs
oauth2authorization, it must first perform an OAuth 2.x flow (which SHOULD be an OAuth 2.1 authorization code flow) to the external service provider. In our example, the client is the agent, which should be knowledgeable about which service providers it ultimately wants to connect to, and therefore should know about the OAuth 2.x authorization configuration of that service provider (i.e. the issuer, authorization endpoint, discovery document locations, etc.).When a token has been obtained for the user, the client includes it in the
tools/callrequest:{ "jsonrpc": "2.0", "id": 42, "method": "tools/call", "params": { "name": "zoom_listPastMeetingParticipants", "arguments": { "meetingId": "5555555555" }, "_meta": { "authorization": { "method": "oauth2", "token": "eyJhbGciOi..." } } } }The
"meta"property is officially described in the MCP protocol schema as a way to allow for additional metadata in the exchange. For now, I’ve included the authorization inside of that property.If
method == "none", the client MAY omit_meta.authorizationentirely; this is identical to the existing behavior oftools/call.The client MAY receive an error from the MCP server indicating a missing or invalid token. Those errors are explored below.
3. Handling missing/invalid tokens
Two new error codes describe tool-level authorization failures:
-32001— no token provided, but the server expected one.-32003— token present but invalid/insufficient (expired, missing scope, etc).These error codes are numbered similarly to HTTP 401 and 403 status codes, but may change in value for the final specification. They follow the json-rpc 2.0 specification for error objects.
Note: Because OAuth tokens vary wildly in composition, the server SHOULD treat the client-supplied token as an opaque string. Error code
-32003does not necessarily distinguish between expired tokens, insufficient scopes, etc. It is the client’s responsibility to provide a valid token.Example error:
{ "jsonrpc": "2.0", "id": 42, "error": { "code": -32003, "message": "Token invalid or insufficient.", "data": { "tool": "zoom_listPastMeetingParticpants", "reason": "Token expired" } } }Design considerations
Q: Why does the client pass a token to the server, instead of the server managing tokens?
A: This adheres to MCP’s ethos of keeping servers focused on their job (tools and resources). If servers also had to store user tokens, they’d need additional state and token management logic. By letting the client handle token orchestration, we keep the complexity on the client side, and the server simply checks for the presence of a token and forwards it with the tool call. It also means that the client can choose to obtain tokens for the end-user at any time–for example, when onboarding a new user to the agent before any call is made to an MCP server.
Q: Doesn’t MCP Authorization already cover this?
A: The OAuth 2.1-based authorization in the spec ensures that a given client is allowed to connect to a particular server. That is separate from authorizing an action on behalf of an end-user, especially when a single agent may serve many different end-users (each with their own tokens). This proposal covers that scenario where the agent needs to acquire authorization from the user to act against a service provider made available through an MCP server.
Q: Why not rely on OAuth 2.0 Token Exchange?
A: Token exchange (RFC 8693) isn’t widely supported by most external services yet. Relying on it would mean devs building today would still have to implement custom solutions for the majority of APIs. This approach instead allows clients to implement the authorization code flow, which is widely supported.
Open questions
Naming: Are
authorization.methodandrequiredScopesintuitive names?Error Codes: Are
-32001(missing token) and-32003(invalid token) sufficient?Next steps
Let me know what you think! If folks agree, I’ll open a PR updating the MCP spec (e.g.,
tools.mdand similar) with these fields, flows, and error code guidelines.Scope
Beta Was this translation helpful? Give feedback.
All reactions