modelcontextprotocol / modelcontextprotocol/python-sdk

[v2] RFC 9728 PRM URLs and resource matching drop query components

Aberta
#3,065 2 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

auth bug needs confirmation P2 v1 v2
Linguagem predominante
Python
Estrelas
24.3k
Forks
4k
Merge médio
1d 1h
PRs com merge (30d)
31

Descrição

What happened?

While testing the v2 auth/protected-resource-metadata path, I noticed query-bearing resource identifiers are treated as if the query is not part of the resource.

For a resource server URL like:

https://api.example.com/mcp?tenant=a

three SDK paths currently drop or ignore ?tenant=a:

  1. mcp.server.auth.routes.build_resource_metadata_url() returns:
https://api.example.com/.well-known/oauth-protected-resource/mcp
  1. mcp.client.auth.utils.build_protected_resource_metadata_discovery_urls(None, resource) also tries:
https://api.example.com/.well-known/oauth-protected-resource/mcp
https://api.example.com/.well-known/oauth-protected-resource
  1. mcp.shared.auth_utils.check_resource_allowed() treats different query components as matching, so the client accepts protected resource metadata for ?tenant=b when the server URL was ?tenant=a.

This is latent for path-only deployments, but it matters for query-routed or multi-tenant resource identifiers.

What did you expect?

RFC 9728 derives the protected-resource metadata URL by inserting /.well-known/oauth-protected-resource before the protected resource path and/or query. If the resource identifier includes a query component, the derived metadata URL and resource validation should not silently collapse it with a different query.

For https://api.example.com/mcp?tenant=a, I expected the path-specific metadata URL to be:

https://api.example.com/.well-known/oauth-protected-resource/mcp?tenant=a

And a PRM document whose resource is https://api.example.com/mcp?tenant=b should not validate for a client configured with https://api.example.com/mcp?tenant=a.

Code to reproduce

import anyio
from pydantic import AnyHttpUrl, AnyUrl

from mcp.client.auth import OAuthClientProvider
from mcp.client.auth.utils import build_protected_resource_metadata_discovery_urls
from mcp.server.auth.routes import build_resource_metadata_url
from mcp.shared.auth import OAuthClientMetadata, ProtectedResourceMetadata
from mcp.shared.auth_utils import check_resource_allowed
from tests.interaction.auth._harness import InMemoryTokenStorage


async def main() -> None:
    resource = "https://api.example.com/mcp?tenant=a"

    print(build_resource_metadata_url(AnyHttpUrl(resource)))
    print(build_protected_resource_metadata_discovery_urls(None, resource))
    print(check_resource_allowed(
        "https://api.example.com/mcp?tenant=a",
        "https://api.example.com/mcp?tenant=b",
    ))

    provider = OAuthClientProvider(
        server_url=resource,
        client_metadata=OAuthClientMetadata(
            client_name="probe",
            client_uri=AnyHttpUrl("https://example.com"),
            redirect_uris=[AnyUrl("http://localhost:3030/callback")],
        ),
        storage=InMemoryTokenStorage(),
    )
    prm = ProtectedResourceMetadata(
        resource=AnyHttpUrl("https://api.example.com/mcp?tenant=b"),
        authorization_servers=[AnyHttpUrl("https://auth.example.com")],
    )
    await provider._validate_resource_match(prm)
    print("accepted mismatched query")


anyio.run(main)

Current output:

https://api.example.com/.well-known/oauth-protected-resource/mcp
['https://api.example.com/.well-known/oauth-protected-resource/mcp', 'https://api.example.com/.well-known/oauth-protected-resource']
True
accepted mismatched query

SDK version

Current main branch, v2 development line.

Area

Auth

AI-assisted (Claude/Codex) for navigation and review; change authored and understood by me.

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Direção de pesquisa

Comece com mcp.server.auth.routes.build_resource_metadata_url(), mcp.client.auth.utils.build_protected_resource_metadata_discovery_urls() e mcp.shared.auth_utils.check_resource_allowed(), depois rastreie OAuthClientProvider._validate_resource_match(). Reproduza os casos que contêm query mostrados na issue e adicione testes de auth focados; considera-se concluído quando as URLs de metadados preservarem a query e componentes de query diferentes não corresponderem mais.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
python
Domínio
authentication
Tipo de issue
Bug
Dificuldade
3/5
Tempo estimado
1-2 dias
Status de atividade
Ativa
Clareza
Claramente especificada
Facilidade para iniciantes
74/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.