Repository navigation
Description
Discussed in #1599
Originally posted by arcaputo3 October 2, 2025
The MCP authorization spec currently requires clients to always send a resource parameter:
“MCP clients MUST implement Resource Indicators (RFC 8707)…
resourceMUST be included in both authorization requests and token requests… and MUST identify the MCP server.” ([MCP Authorization Section 2.5.1]1)
This contradicts two stated goals of the spec—interoperability and simplicity—and it’s not consistent with RFC 8707. RFC 8707 explicitly makes resource optional:
“In requests to the authorization server, a client MAY indicate the protected resource… by including the
resourceparameter.” ([RFC 8707 Section 2-1]2)
And §2.1 is explicit that omitting resource is permitted; servers MAY still process the request (or MAY require it and fail with invalid_target):
“If the client omits the
resourceparameter… the authorization server MAY process the request with no specific resource… Alternatively, the authorization server MAY require clients to specify the resource(s)… and MAY fail requests that omit the parameter with aninvalid_targeterror.” ([RFC 8707 Section 2.1-3]3)
The current MCP language therefore turns a MAY into a MUST, which (a) diverges from RFC 8707’s intent and (b) breaks interoperability with major IdPs that don’t accept resource at /authorize.
Real-world breakage
-
Microsoft Entra ID (v2) rejects
resourceat/authorizeand is scope-centric; the supported pattern isscope={resource}/.default(functional equivalent of v1resource=...). Developers routinely hitAADSTS901002: The 'resource' request parameter is not supported.([Microsoft Learn]4)
(See the MCP Inspector issue demonstrating this failure mode.) ([GitHub]5) -
OIDC Core centers consent/audience around
scope, notresource, and never requiresresource. ([OpenID Foundation]6)
Also: even when a client does send resource, RFC 6749 says servers MUST ignore unrecognized request parameters—so relying on universal enforcement is wishful thinking. Audience binding must be validated at the resource server regardless. ([RFC 6749 Section 4.1.2]7)
Standards compliance & discovery constraints
-
The MCP spec’s own standards-compliance goals emphasize interoperability and simplicity. Mandating
resourceacross the board undermines both by forcing non-portable client behavior. ([MCP Authorization Section 1.3]1) -
RFC 8707's resource parameter is an optional extension. Treating an RFC MAY as a protocol-level MUST is not RFC-aligned. ([IETF Datatracker]3)
-
No discovery signal exists to tell clients whether an AS supports or requires
resource. Neither OAuth 2.0 AS Metadata (RFC 8414) nor OIDC Discovery define a flag for RFC 8707 support. Providers legitimately differ, and clients can’t learn this from.well-known. ([RFC 8414]11, [OIDC Discovery 1.0]12)
Given that reality, the spec should not require resource unconditionally.
Proposed spec changes (minimal, standards-aligned)
-
Relax the requirement.
Change “resourceMUST be included in authorization and token requests” to:“MCP clients SHOULD use RFC 8707 Resource Indicators. When the AS supports RFC 8707 for the relevant endpoint(s), clients SHOULD send
resource. When the AS rejects or ignoresresource, clients MUST fall back to a scope-based audience signal.”This honors RFC 8707’s optional semantics and keeps the security goal.
-
Define an interoperable fallback.
Add explicit guidance for non-8707 IdPs (e.g., Microsoft Entra v2):- Authorization request: omit
resource; request scopes for a single API. - Token request (app-only /
.defaultcases): if the AS is Entra v2, usescope={resource}/.default. (Microsoft’s documented bridge from v1resourceto v2 scopes.) ([Microsoft Learn]8)
- Authorization request: omit
-
Discovery hint (non-normative).
Because there’s no metadata flag for RFC 8707 support:- Prefer explicit configuration (or PRM/server config) of ASs known to accept
resource. (MCP already leans on Protected Resource Metadata, RFC 9728.) ([RFC Editor]9) - If unknown, either (a) default to scope-only for a single API, or (b) try
resourceonce; oninvalid_targetor known provider-specific errors (e.g., AADSTS901002), retry withoutresourceand continue scope-based. ([IETF Datatracker]3)
- Prefer explicit configuration (or PRM/server config) of ASs known to accept
-
Keep audience checks a MUST.
Regardless of request shape, MCP servers MUST verify that received tokens are audience-restricted to themselves (e.g., viaaud) and MUST reject tokens not issued for them. This matches RFC 8707’s security rationale. ([IETF Datatracker]3)
Why this is the right trade-off
- Standards coherence: Honors RFC 8707’s optional model instead of redefining it.
- Interoperability: Works out-of-the-box with Entra v2 (and other scope-centric IdPs) and with providers that implement Resource Indicators. ([Microsoft Learn]4)
- Simplicity: No new discovery heuristics; one clean fallback path.
- Security preserved: Audience binding enforced where it matters (resource server), and clients use
resourcewhere it’s actually supported. ([IETF Datatracker]3)
References: RFC 8707 (Resource Indicators), RFC 6749 (OAuth 2.0), RFC 8414 (AS Metadata), OIDC Core & Discovery, Microsoft Entra docs on scopes/.default, MCP Inspector issue, MCP Authorization spec, RFC 9728 (Protected Resource Metadata), IETF Datatracker.
Activity
localden commentedon Oct 6, 2025
@arcaputo3 the MCP authorization spec, given that it's downstream from the OAuth RFCs, can be more opinionated and explicit about certain requirements.
resourcehere explicitly allows protection against vectors where malicious MCP servers can re-use auth artifacts for other previously-consented MCP servers.IMO, all clients must include
resource, and the authorization server needs to handle that gracefully (e.g., ignore it, if it doesn't processresourcedata). AS that error out if aresourceparameter is attached should instead handle this gracefully.dacamposol commentedon Oct 7, 2025
I believe the problem comes from how multiple RFCs impose conflicting or overly restrictive requirements on existing Authorization Servers.
With RFC 8707 — Resource Indicators for OAuth 2.0 and RFC 8693 — OAuth 2.0 Token Exchange, the
resourceparameter was introduced as a URI identifying the API that hosts the resource:Some enterprise Authorization Servers interpret this as allowing URNs (per RFC 3986) to identify APIs, since URNs can remain globally unique and persistent even when a resource moves or becomes unavailable. Example:
However, RFC 9728 — OAuth 2.0 Protected Resource Metadata enforces URL semantics for the
resourceparameter:Because the MCP specification mandates both RFC 9728 compliance and the presence of the
resourceparameter, this effectively enforces a URL-only interpretation. The result is an "all-or-nothing" model that limits interoperability and imposes opinionated constraints on Authorization Servers. Realistically, this will lead to fragmented workarounds, such as the OAuth proxies now emerging in front of MCP servers.arcaputo3 commentedon Oct 7, 2025
+1. This is exactly the reality my team has hit.
As it stands, MCP's strict requirement on
resourcecombined with RFC 9728 (URL-only semantics) leaves enterprise teams (mine included) with a narrow set of tough options:The intention behind requiring
resource(protecting users from token reuse across audiences) is absolutely right, but the current approach ends up hurting interop with mainstream IdPs like Microsoft Entra and Okta. It's asking large, established IdPs to come toward MCP, rather than MCP being broadly compatible out-of-the-box.Instead, MCP should:
Relax the requirement:
resourceif supported by the AS.aud,iss).Loosen RFC 9728 semantics (URL vs. URN):
Keep 9728 as recommended, not mandatory. Document explicitly how both URL-based and URN-based identifiers can safely coexist.
Clearly document trade-offs and aspirations:
State clearly that strict handling of
resourceand RFC 9728 semantics is ideal, but acknowledge the current reality and recommend best practices.This approach solves today's real-world pain. Right now, MCP carries the responsibility of interop. It's the new player that's rapidly becoming widely adopted. It makes more sense for MCP to fit existing ecosystems first, then tighten things later once major IdPs move toward stricter
resourcehandling—if and when they actually do.My team would have preferred using standard off-the-shelf IdPs from day one. Instead, we've had to implement workarounds that compromised the developer experience. It's suboptimal and a barrier to broader adoption.
localden commentedon Oct 7, 2025
On (1) from @arcaputo3, the problem here is that there is no way for the client to make a confident assertion that the AS supports
resource(maybe @aaronpk knows of a way I don't). There is an unbounded number of potential AS that can be in the pipeline.That being said, yes - right now it's URL-bound, but we're already requiring that for RFC 9728, so if we move away from this approach this needs to be a RFC change, IMO, since clients and servers already follow a specific convention.
sebastianGit commentedon Oct 8, 2025
My understanding is as follows:
resource identifierbeing a URL with scheme https, e.g. for being able to do metadata validation (see Section 3.3. of RFC 9728).resource indicatorsto be an absolute URI (see Section 1.1.2. in RFC 3986 for examples).resource indicatorsin theresourcequery parameter in authorization and token requests is not common when looking at the well-known OAuth Authorization Servers / OpenID Connect Providers.resource identifierin the protected resource metadata might NOT be the value that is expected by the OAuth Authorization Server / OpenID Connect Provider asresource indicatorin authorization and/or token requests (e.g., as the server might support only URNs or another URI compliant syntax forresource indicators).scopequery parameter in authorization requests is rather common when looking at the well-known OAuth Authorization Servers / OpenID Connect Providers.Would it be a feasible way forward in the context of MCP to:
resource identifierprovided in the protected resource metadata for the validation of the protected resource metadata (following RFC 9728), i.e., also expect a URL with scheme https for the resource.scopeparameter in the authorization request to indicate to the OAuth Authorization Server / OpenID Connect Provider. The handling of thescopeparameter when issuing a token (e.g. for deriving the audience) follows the policies of the OAuth Authorization Server / OpenID Connect Provider and may depend on the configuration of the OAuth client.openidorapi://foo.bar.baz/.default.resourceparameter must be omitted in authorization requests and token requests, when ascopeparameter has been used in the authorization request.This would leave the following question open:
WWW-Authenticatechallenge nor ascopes_supportedin the protected resource metadata. In this case, there might be arguments for:scopeparameter and trying to send theresourceparameter (providing the value received in the protected metadata), orresourceandscopeparameters from the authorization request (and token request).dacamposol commentedon Oct 8, 2025
I don’t see an issue with using the
resourcefield as a valid URL with thehttps://scheme to validate the returned Resource Metadata, as defined in RFC 9728. The real problem appears when this same identifier is forwarded to the AS during Authorization and Access Token requests (per RFC 8707), effectively requiring established Authorization Servers to adopt URL semantics for resource identification.From a discoverability and validation perspective, it makes sense for the
resourceto match the base URL (with scheme) that exposes the/.well-known/oauth-protected-resourceendpoint. However, there should be flexibility in how the MCP Client further communicates with the AS, without mandating that Authorization Servers MUST accept URLs as resource indicators.In regards of the proposal from @sebastianGit, RFC 8707 indicates the following:
So actually, it could be the use-case where someone wants to use both
scopeandresourceparameters to define the where and what of the provisioned token.I don’t think the client needs to verify in advance whether the AS supports the
resourceparameter. It can simply send an initial authorization request that includes both theresource(from the Protected Resource Metadata) and thescope(as defined by the Scope Selection Strategy). If the AS returns aninvalid_targeterror, the client can retry the request using only thescope.In this fallback scenario, it remains the AS's responsibility to determine which audience restrictions apply to authorization requests without a
resourceparameter.spacewander commentedon Oct 8, 2025
Since the
resourceparameter is optional, does this mean the server should check the aud claim like below?resourceparameter is given)resourceparameter is not given or the AS doesn't recognize the parameter)will-bartlett commentedon Oct 14, 2025
There is a security vulnerability in MCP clients that don't send the resource parameter. That's why the current specification says it is mandatory.
Consider MCP Server hosted at mcp.example that accesses a file storage hosted at files.example with both mcp.example and files.example protected by an OAuth server hosted at oauth.example. The expected pattern is that some scope mcp.do protects the clients access to mcp.example and some other scope files.read protects mcp.example's access to files.example. When the user adds the MCP server in the MCP client, mcp.example advertises scopes_supported:["mcp.do"]. The MCP client makes a request to oauth.example and oauth.example asks the user "Can MCP Client name access mcp.do?" and "Can MCP Server name access files.read?" These are the appropriate two consent prompts for this flow.
The attack: absent the resource parameter, mcp.example could advertise "scopes_supported":["files.read"] in its RFC 9728 metadata. The MCP client would duitifully makes a request to oauth.example which would ask the user "Can MCP Client Name access files.read?" The user would approve, and MCP Server would be able to access the user's data, even though the user had never seen a consent prompt that mentioned MCP Server. This is a privacy problem and a significant one, that would likely lead to many social engineering attacks.
How "resource" fixes this problem. The resource parameter causes oauth.example to receive a request with scope=files.read&resource=mcp.example. The OAuth server can then say "Wait a second! Files.read isn't hosted on mcp.example! It's hosted on files.example!" and error out of the flow (error=invalid_target).
If resource is to become optional, there must be some other way to solve the problem that the MCP Server can claim to be the owner of scopes that it does not actually own.
On some OAuth providers (like Entra), there are other ways to solve this problem. On Entra, scopes are domain prefixed - i.e. mcp.example wouldn't advertise "mcp.do", it'd advertise "https://mcp.example/mcp.do" - and the MCP client could verify the legitimacy of the scope with a simple string prefix comparison of the MCP server hostname with the scope. However, this scheme, while common (to at least Google and Microsoft), is not part of any OAuth standard. The only standard way to enable such a comparison is to have the MCP client send both scope and resource to the OAuth provider, and let the OAuth provider decide whether or not they are a match.
The original proposal suggests that security is preserved by the MCP server doing audience checks - but this is not so. It is the MCP Server that is the malicious entity in the example attack, and an attack mitigation cannot rely on the malicious entity doing a check.
will-bartlett commentedon Oct 14, 2025
@arcaputo3 Fwiw, I don't think of the proxy OAuth servers as such a bad solution. At least this solution gives the user a proper opportunity to control the flow of their data. I think there's one more option you didn't list:
That's the outcome I'm trying to avoid.
dacamposol commentedon Oct 15, 2025
@will-bartlett good point. That attack vector applies primarily to scenarios where Dynamic Client Registration (DCR) is enabled.
In our case (as with most enterprise OAuth servers) DCR is not supported. The authorization server enforces a static binding between each
client_idand its allowed scopes. Client credentials are then expected to be provisioned to the MCP client through a managed flow (similar to how GitHub Copilot handles it in VSCode, see #255633) when DCR is unavailable.With this setup, the AS rejects any token request for scopes not explicitly whitelisted for that client (for example, if the MCP client requests
files.read, it fails). The mapping of permitted scopes per client is explicitly configured on the AS by the resource owner.Given that enterprise OAuth providers such as Microsoft, Google, and SAP do not support DCR (and typically define resource indicators as URNs rather than URLs) from my point of view it seems unnecessary this enforcement to implement URL semantics for them.
will-bartlett commentedon Oct 15, 2025
@dacamposol it's a bit more nuanced than that, and I don't agree with some of those assertions.
Actually, it applies primarily to scenarios that permit third parties to register OAuth clients and scopes without extensive review. E.g. Entra does not support DCR, but it does allow low reputation enterprises (e.g. those that have signed up for one month at the lowest price tier) to register OAuth clients and scopes. Likewise for Github and Google, I believe.
Not something Entra or Github does. Only something Google does for certain "sensitive" scopes, not all scopes.
I'm not familiar with SAP's OAuth integration, but both Microsoft and Google typically define resource indicators as URLs, not URNs. See Google Microsoft.
Taking a step back. It's true that this sort of attack is mostly relevant to large OAuth providers that permit customer-owned resources (like Entra) and less relevant to small OAuth providers that only expose resources owned by the firm that operates the OAuth provider. My hope was that the optionality of resource support for authorization servers would provide a nice balance here. The larger OAuth providers would support the resource parameter and reject requests with invalid_target, while the smaller OAuth providers can simply ignore the resource parameter. I wanted to require MCP clients to send resource to give OAuth providers an opportunity to mitigate such attacks, if mitigating such attacks makes sense for their ecosystem.
Fwiw, Entra is working on fixing its non-compliance around RFC 8707. It's wrong that Entra rejects resource with invalid_request rather than either ignoring the parameter or validating it.
mcguinness commentedon Oct 17, 2025
A client is unable to detect if an Authorization Server supports RFC 8707 nor does it know what the result is of an authorization request which creates interoperability challenges and ambiguity in the client's interpretation of the token's audience, potentially resulting in resource mix-up attacks or incorrect token usage
I submitted a draft extension https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/ that would enable a client to detect the outcome of a resource indicator request which is tracked under #763. This was an action item that came out of workshop that drove #544.
Unfortunately there hasn't been any feedback since this was published.
sebastianGit commentedon Nov 19, 2025
Is there any update on this topic? The current draft version of the specification still states with respect to the resource parameter (see: https://modelcontextprotocol.io/specification/draft/basic/authorization#canonical-server-uri):
Would it be an option to include the flexibility that when an MCP client does not have an explicit configuration for how to set the resource parameter, it uses the URL value retrieved via the protected resource metadata? However, if the client is given an explicit configuration (e.g., via configuration file) - either to omit the resource parameter or to use a given URI (which might be a URL or a URN) - then this would override the default behavior?
dend commentedon Mar 4, 2026
@pcarleton @mcguinness @aaronpk reading through this, it feels like using
resourceis generally a good thing in this context, and removing the requirement would only weaken the general client security posture. For what it's worth, we should work with IdPs to ensure that their AS don't break if they don't support RFC8707, but I am not sure if removing is the right path.nub-vtl commentedon May 6, 2026
Is there an update on this? It seems that as it currently stands, it's not possible to connect to Entra-protected MCPs from clients which use official model context protocol SDKs (e.g. MCP Inspector etc)
will-bartlett commentedon May 6, 2026
Entra fixed its support for the resource parameter. So it should be possible to connect to Entra-protected MCPs now - or if it isn't, this issue should not be the reason.
sergey-tihon commentedon May 7, 2026
@nub-vtl This issue has been resolved, and I confirm that it works with Entra ID authentication. The setup is just a bit tricky.
You can follow the steps described here.
A separate issue (not related to this one) is that Entra ID requires an exact match between the resource name and the application identityUrl. There is currently no trailing slash normalization on the Entra side.
So, you need to check that the MCP SDK you are using does not normalize the URL or append a trailing slash.
Some SDKs may send
resource=https://mcp.example.com/during authentication, even if your server returnshttps://mcp.example.com. This will break authentication.akriaueno commentedon May 11, 2026
Sharing what I tested, in case it helps.
In my tenant, Entra v2 appears to implement
resourceas a URI, not specifically as the resource's canonical URL. It accepts any value that matches one of the app's registeredidentifierUris(the Entra app registration property listing acceptable resource indicator URIs — set viaaz ad app update --identifier-urisor the "Application ID URI" field in the portal). Three test combinations against the same MCP server:identifierUris: ["api://<appId>"]—resource=api://<appId>→ token issued.identifierUris: ["https://mcp.example.com/mcp"](only possible after the domain is verified at the tenant level) —resource=https://mcp.example.com/mcp→ token issued.identifierUris: ["api://<appId>"]—resource=https://mcp.example.com/mcp(MCP SDK default) → token not issued,AADSTS9010010: The resource parameter provided in the request doesn't match with the requested scopes.Worth noting: the error is
AADSTS9010010(resource/scope mismatch), notAADSTS901002("resource not supported"). So current Entra v2 does processresourceand validate it against the scope's API — it isn't rejectingresourceoutright.The practical block is the third case: MCP SDK defaults to sending the canonical HTTPS URL, but in many enterprise tenants only the
api://<appId>form can be registered as anidentifierUri(customer owns the domain, central IT controls verification, federated setups, etc.).I think the spec and SDK should allow overriding the default
resourcevalue, for example to useapi://<appId>, while still supporting the canonical HTTPS URL as the default.nub-vtl commentedon May 11, 2026
This is the error that i've been getting - not clear on whether this has been resolved?
will-bartlett commentedon May 11, 2026
Yes, this is the intended purpose of the resource parameter - to be checked against scope to ensure that only the legitimate owner of a scope can host a resource server for it, and thereby prevent the attack I described further up in the issue.
Can you explain how this might work that wouldn't introduce the social engineering attack described above?
Of course, it'd be nice to avoid domain verification, to have one fewer onboarding step, but not at the cost of making MCP insecure.
akriaueno commentedon May 11, 2026
@will-bartlett
Re-reading your explanation, I can see my proposal isn't secure. There doesn't seem to be a way to prevent the social engineering attack other than the MCP client enforcing that the
resourceit forwards to the AS matches the URL of the MCP server it's actually contacting.erwinkramer commentedon Oct 22, 2026
Proposing new MCP server setting
resource_indicators_supported, as demonstrated at: modelcontextprotocol/csharp-sdk#648 (comment)will-bartlett commentedon Oct 23, 2026
See the discussion above. Lack of resource indicator in an auto-discovery scenario like MCP means it's trivial for the MCP servers to impersonate the MCP client to the OAuth Provider. This is the same as not having it in the spec at all.