modelcontextprotocol / modelcontextprotocol/python-sdk

A resource template with a non-ASCII or space literal is advertised but can never be read

Offen
#3,526 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

v1 v2
Vorherrschende Sprache
Python
Sterne
24.3k
Forks
4k
Ø Merge
1 T. 1 Std.
Gemergte PRs (30 T.)
31

Beschreibung

Initial Checks
  • I confirm that I'm using the newest release of my line (main @ 6affe5c)
  • I confirm that I searched for my issue in the issue tracker before opening this issue
Release line

2.x (current stable)

Description

UriTemplate copies literal runs into the expansion verbatim. RFC 6570 §3.1 requires a literal that the URI grammar does not allow (ucschar such as café, or a space) to be pct-encoded as UTF-8 when the template is expanded, so expand() currently returns a string that is not a valid RFC 3986 URI:

UriTemplate.parse("file:///docs/café/{name}").expand({"name": "a.txt"})
# 'file:///docs/café/a.txt'      (uritemplate-test "Literal Encoding" expects caf%C3%A9)

match() is built from the same verbatim literals, so it accepts only that invalid form and rejects the encoded one:

t = UriTemplate.parse("file:///docs/café/{name}")
t.match("file:///docs/caf%C3%A9/a.txt")   # None
t.match("file:///docs/café/a.txt")        # {'name': 'a.txt'}

That second line is the part that bites in practice. A resource URI crosses the wire as a pydantic AnyUrl, which pct-encodes non-ASCII and spaces (AnyUrl('file:///docs/café/a.txt')file:///docs/caf%C3%A9/a.txt). So the encoded form is the only one a server ever sees, and the template can never match it: the resource is listed in resources/templates/list and is permanently unreadable. The same applies to a literal space (file:///my docs/{name}my%20docs).

I hit this while building resource templates whose paths carry Spanish accents, which is ordinary for non-English servers.

Expected: expand() pct-encodes literals per §3.1, and match() accepts the encoded URI a conforming client sends, so an expanded URI round-trips.

Note the direction of the behavior change this implies: after the fix, the raw (unencoded) form stops matching. I believe that is correct, since it is not a valid RFC 3986 URI and it is not what reaches a server over the wire, but it is a visible change for anyone calling UriTemplate.match() directly with a raw IRI, so it seems worth your call rather than mine. Accepting both forms is possible (a fallback scan over the raw atoms) at the cost of a second pass and an ambiguity to document.

I have a patch (the literal encoding applied in both directions, sharing the existing _encode helper) plus unit tests, a routing test, and the official uritemplate-test "Literal Encoding" vector. The full suite passes (5978 passed, 10 skipped, 1 xfailed; baseline 5968), and the new assertions fail on main. Happy to open a PR if you'd like it and can assign this to me.

Example Code
import anyio
from mcp.client.client import Client
from mcp.server.mcpserver import MCPServer

mcp = MCPServer()


@mcp.resource("file:///docs/café/{name}")
def doc(name: str) -> str:
    return f"contents of {name}"


async def main() -> None:
    async with Client(mcp) as client:
        templates = await client.list_resource_templates()
        print(templates.resource_templates[0].uri_template)
        # file:///docs/café/{name}

        # what a conforming client puts on the wire (AnyUrl pct-encodes it)
        await client.read_resource("file:///docs/caf%C3%A9/a.txt")
        # McpError: Unknown resource: file:///docs/caf%C3%A9/a.txt


anyio.run(main)
Python & MCP Python SDK
Python 3.11.3, mcp-python-sdk main @ 6affe5c0d3588fd1705713b3703dc68015cfe3eb

Disclosure: this was found and written with Claude Code. It ran the official uritemplate-test vectors against mcp.shared.uri_template, reduced the failure to this case, and drafted this report and the patch. I reviewed it before posting and can walk through the change.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit mcp.shared.uri_template und dem vorhandenen _encode-Hilfsprogramm und untersuche anschließend die im Bericht beschriebenen Unit- und Routing-Tests. Überprüfe den offiziellen uritemplate-test Literal Encoding-Vektor und den Roundtrip von resource-template; die Aufgabe ist abgeschlossen, wenn Expansion und Matching bei percent-kodierten Literalen übereinstimmen und die vollständige Testsuite erfolgreich durchläuft.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
api
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.