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-resource endpoint returns HTTP 200
  • The response body contains a valid authorization_servers array with the full URL including path
  • The Content-Type header is application/json
  • The APIM policy correctly exposes both well-known endpoints under the /my-path prefix
  • The behavior is reproducible with both VS Code (GitHub Copilot MCP) and Claude Desktop

Questions

  1. Is this a known limitation or bug in current MCP client implementations (VS Code / Claude Desktop) where the path component of authorization_servers is not respected when constructing the /.well-known/oauth-authorization-server URL?
  2. 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?
  3. Has anyone successfully configured APIM with a non-root authorization server prefix for MCP OAuth discovery?
  1. Pravallika KV 17,025 Reputation points Microsoft External Staff Moderator

    Hi @Cesare Farina Busetto ,

    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:

    1. Workaround by hosting your OAuth metadata at the root
    • Move or proxy /my-path/.well-known/oauth-protected-resource and /my-path/.well-known/oauth-authorization-server to /.well-known/... on your APIM domain.
    • That ensures clients will discover everything correctly without subpath logic.
    1. 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.
    1. 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.

  2. 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.

  3. Cesare Farina Busetto 0 Reputation points

    Hi @Pravallika KV

    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

  1. 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_servers paths 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:

    1. The MCP client (VS Code / GitHub Copilot) sends an initialization request.
    2. The MCP server responds with an authorization error that includes a pointer to Protected Resource Metadata (PRM).
    3. The client fetches the PRM and uses it to identify the authorization server.
    4. The client then attempts to obtain Authorization Server Metadata (ASM) from a well-known endpoint on the authorization server.
    5. 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_servers as a strict base URL.

    Given the available information, the practical guidance is:

    1. Treat this as a client limitation rather than an APIM misconfiguration.
    2. 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_servers URL for discovery, because the clients may ignore or reorder that path.
    3. 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.

    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_servers value points to an authority whose metadata is available at the standard OpenID Connect / OAuth well-known locations without requiring additional path prefixes.

    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.
Sign in to answer

Your answer