MCP Client Ignores authorization_servers Path from oauth-protected-resource Metadata - Always Resolves Well-Known Endpoints Against APIM Root Domain
Environment
| Component | Detail |
|---|---|
| Gateway | Azure API Management (Basic v2) |
| MCP Client | VS Code (GitHub Copilot) and Claude Desktop |
| Auth spec | MCP Authorization |
| Transport | Streamable HTTP |
Background
I deployed APIs and operations on an existing Azure API Management instance to act as the resource server for a remote MCP server endpoint, with OAuth 2.0 discovery implemented following the MCP Authorization spec (2025-03-26), RFC 9728 (Protected Resource Metadata), and RFC 8414 (Authorization Server Metadata).
The intended discovery flow is:
1. Client → POST https://example.azure-api.net/mcp
← 401 Unauthorized
WWW-Authenticate: Bearer realm="...",
resource_metadata="https://example.azure-api.net/my-path/.well-known/oauth-protected-resource"
2. Client → GET https://example.azure-api.net/my-path/.well-known/oauth-protected-resource
← 200 OK
{
"resource": "https://example.azure-api.net/mcp",
"authorization_servers": ["https://example.azure-api.net/my-path"]
}
3. Client → GET https://example.azure-api.net/my-path/.well-known/oauth-authorization-server
← 200 OK (expected — but this step never happens)
Problem
Steps 1 and 2 work correctly. The /.well-known/oauth-protected-resource endpoint is called and returns HTTP 200 with the correct JSON body, including "authorization_servers": ["https://example.azure-api.net/my-path"].
However, in step 3, instead of deriving the Authorization Server Metadata URL from the declared authorization_servers value, the client appears to strip the path prefix and resolve the well-known endpoint against the root domain only:
# Expected (per RFC 8414 §3 + RFC 9728):
GET https://example.azure-api.net/my-path/.well-known/oauth-authorization-server
# Actual (observed in both VS Code and Claude Desktop):
GET https://example.azure-api.net/.well-known/oauth-authorization-server
The path component (/my-path) from the declared authorization server URL is being ignored entirely.
What I Have Verified
- The
/.well-known/oauth-protected-resourceendpoint returns HTTP 200 - The response body contains a valid
authorization_serversarray with the full URL including path - The
Content-Typeheader isapplication/json - The APIM policy correctly exposes both well-known endpoints under the
/my-pathprefix - The behavior is reproducible with both VS Code (GitHub Copilot MCP) and Claude Desktop
Questions
- Is this a known limitation or bug in current MCP client implementations (VS Code / Claude Desktop) where the path component of
authorization_serversis not respected when constructing the/.well-known/oauth-authorization-serverURL? - Is there a recommended APIM topology or naming convention that avoids subpaths in the authorization server URL (e.g., keeping everything at the root domain) to work around this behavior?
- Has anyone successfully configured APIM with a non-root authorization server prefix for MCP OAuth discovery?
-
Pravallika KV 17,025 Reputation points • Microsoft External Staff • Moderator
It looks like you’ve run into a client implementation quirk rather than something you’ve mis-configured in APIM.
According to the spec (RFC 9728 + RFC 8414), the client should take the full URL you publish in the authorization_servers array (including any path segments) and append
/.well-known/oauth-authorization-server. In practice, both the VS Code Copilot MCP client and Claude Desktop today ignore the path portion and default back to the root domain.Here’s what you can do in the meantime:
- Workaround by hosting your OAuth metadata at the root
- Move or proxy
/my-path/.well-known/oauth-protected-resourceand/my-path/.well-known/oauth-authorization-serverto/.well-known/...on your APIM domain. - That ensures clients will discover everything correctly without subpath logic.
- Use a custom domain or per-API host to eliminate subpaths
- If you give each resource its own hostname (e.g.
resource1.yourdomain.com), you can keep all well-known endpoints at the host root. - No more path ambiguity for the MCP clients.
- File feedback with the MCP client teams
- This is likely a bug/limitation in the current Copilot and Claude implementations.
- Opening an issue on the GitHub Copilot MCP repo or the Claude feedback channel will help get this prioritized.
At this time, we’re not aware of any APIM-specific policy magic or topology that forces those clients to respect a non-root path, so flattening your well-known endpoints to the root is the most reliable workaround.
-
Pravallika KV 17,025 Reputation points • Microsoft External Staff • Moderator
@Cesare Farina Busetto , following up to see if you had a chance to check the above response and if it was helpful. Please let me know if you have any issues.
-
Cesare Farina Busetto 0 Reputation points
Thank you for the response. I evaluated the first option but unfortunately it doesn't align with my business requirements. As a workaround, we went with registering a custom domain for each auth endpoint - the implementation isn't ideal, but it works for now. We're looking forward to any future improvements on this topic.
Sign in to comment
1 answer
-
AI answer
The behavior described matches current MCP client behavior when used with Microsoft Entra–protected resources and is effectively a client limitation: the clients don’t fully honor arbitrary
authorization_serverspaths from the protected resource metadata and instead probe well-known endpoints in a fixed way.From the documented MCP server authorization flow with Microsoft Entra ID:
- The MCP client (VS Code / GitHub Copilot) sends an initialization request.
- The MCP server responds with an authorization error that includes a pointer to Protected Resource Metadata (PRM).
- The client fetches the PRM and uses it to identify the authorization server.
- The client then attempts to obtain Authorization Server Metadata (ASM) from a well-known endpoint on the authorization server.
- Because Microsoft Entra ID does not support ASM on the “expected” well-known endpoint, the client falls back to the OpenID Connect metadata endpoint and tries multiple patterns, including inserting the well-known segment before or after path information, until it finds the working location.
In other words, current MCP clients implement a hard-coded discovery strategy tailored to Microsoft Entra ID rather than a generic RFC 9728 / RFC 8414 implementation that strictly respects arbitrary path components in
authorization_servers. The documentation explicitly notes that:- The client first tries a well-known endpoint pattern that Entra does not support.
- It then falls back to the OpenID Connect metadata endpoint and adjusts the path ordering to match where Entra actually hosts it.
This is consistent with what is observed: the client effectively normalizes discovery against the base authority and then probes well-known endpoints, instead of using the full path from
authorization_serversas a strict base URL.Given the available information, the practical guidance is:
- Treat this as a client limitation rather than an APIM misconfiguration.
- Align the topology with what current MCP clients expect:
- Expose the protected resource metadata and authorization server metadata in a way that works when the client resolves well-known endpoints relative to the root authority (host) rather than a subpath.
- Avoid relying on non-root path prefixes in the
authorization_serversURL for discovery, because the clients may ignore or reorder that path.
- When integrating with Microsoft Entra ID, follow the documented pattern used by Azure App Service and Azure Functions MCP samples, which rely on:
- A PRM endpoint at
/.well-known/oauth-protected-resource. - Client-side logic that falls back to the OpenID Connect metadata endpoint hosted by Entra ID (with the well-known segment after path information) instead of a custom subpath on the resource server.
- A PRM endpoint at
There is no example in the provided material of a successful MCP configuration that uses a non-root authorization server prefix behind APIM; all documented flows assume discovery against the standard well-known locations associated with the Entra authority rather than a custom APIM subpath.
For a robust workaround with today’s clients, design the APIM surface so that:
- The PRM endpoint is reachable at the standard well-known location for the resource host.
- The
authorization_serversvalue points to an authority whose metadata is available at the standard OpenID Connect / OAuth well-known locations without requiring additional path prefixes.
References:
- Tutorial: Host an MCP server on Azure Functions (programming-language-powershell)
- Tutorial: Host an MCP server on Azure Functions (programming-language-python)
- Tutorial: Host an MCP server on Azure Functions (programming-language-typescript)
- Tutorial: Host an MCP server on Azure Functions (programming-language-javascript)
- Tutorial: Host an MCP server on Azure Functions (programming-language-csharp)
- Secure Model Context Protocol calls to Azure App Service from Visual Studio Code with Microsoft Entra authentication
- Troubleshoot MCP servers on Azure Container Apps
AI-generated content may be incorrect. Read our transparency notes for more information.
