Skip to content

The authorization spec is unclear when multiple Authorization servers are involved #1349

@spacewander

Description

@spacewander

Describe the bug

When an MCP client registers with an authorization server, it persists a client ID that is only valid for that specific authorization server. If the MCP server later changes to a different authorization server, the client will fail to get a new token because its old client ID is not recognized by the new server.

To Reproduce
Steps to reproduce the behavior:

  1. Set up Authorization servers A and B. A and B don't share the data source (for example, using different databases).
  2. Configure Authorization server A as the AS via the MCP server's protected resource metadata.
  3. MCP client communicates with MCP server. To be authorized, it registers itself with the Authorization server A.
  4. MCP client persists the registered client ID. This ID is only recognized by the Authorization server A.
  5. Some days later, the MCP server changes its Authorization Server to B.
  6. MCP client tries to get a new token with the registered client ID with the Authorization Server B, and fails. There is no built-in way to refresh the registered client info.

I have checked the Python and Typescript SDKs, none of them have bound the client ID/secret with the Authorization Servers. So if the Authorization Servers change, there is no way to update the persistent client info.

In Python, the SDK only checks if the client is registered, but doesn't care whether the client is registered to the given Authorization Server.

https://github.com/modelcontextprotocol/python-sdk/blob/c7671e470c235971b63c41be183537074ff8fa91/src/mcp/client/auth.py#L281

async def _register_client(self) -> httpx.Request | None:
    """Build registration request or skip if already registered."""
    if self.context.client_info:
        return None

In Typescript, the same clientInformation is returned no matter what the authorizationServerUrl is:
https://github.com/modelcontextprotocol/typescript-sdk/blob/4a63974049e27efb3c99325b29454127eed33adf/src/client/auth.ts#L344

  const metadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, {
    fetchFn,
  });

  // Handle client registration if needed
  let clientInformation = await Promise.resolve(provider.clientInformation());

A similar issue is that the spec allows configuring multiple Authorization servers at the same time. What if these Authorization servers don't share any data?
So far, only the first server is used in the SDK: #1331

It would be better to clarify the multiple Authorization servers (and Authorization server migration) situation in the spec.

Metadata

Metadata

Assignees

Labels

authbugSomething isn't workingdocumentationImprovements or additions to documentationsecurity

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions