modelcontextprotocol / modelcontextprotocol/typescript-sdk

UriTemplate.match() does not percent-decode extracted values

Open Beginner friendly
#2,728 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
3d 15h
Merged PRs (30d)
4

Description

Describe the bug

expand() percent-encodes variable values, but match() returns them still encoded, so the two are not inverses:

const t = new UriTemplate("file:///{path}");
t.expand({ path: "My File.txt" }); // "file:///My%20File.txt"
t.match("file:///My%20File.txt");  // { path: "My%20File.txt" }  <- expected "My File.txt"

Round-tripping 10 templates against 20 values, 147 of 200 fail — every value containing a space, /, ?, #, &, =, %, or a non-ASCII character. A few from that sweep:

template value expand match returns
file:///{path} a b file:///a%20b a%20b
file:///{path} a/b file:///a%2Fb a%2Fb
file:///{path} ü file:///%C3%BC %C3%BC
x://h/{a}/{b} a#b x://h/a%23b/a%23b a%23b

There is no decodeURIComponent call anywhere in packages/core-internal/src/shared/uriTemplate.ts.

Impact

ResourceTemplate routes resource URIs through match(), so a handler receives the encoded string rather than the value the client asked for. Any resource whose template variable contains a space or a non-ASCII character is handed the wrong value, silently.

Prior art I checked

The open uriTemplate PRs — #2633, #2170, #2429, #2216, #2218 — all cover multi-variable or optional matching, and none of them adds a decode call. #1785's title mentioned encoded query parameters, but it closed unmerged and the decoding does not appear in its successors, so this axis looks genuinely open.

Environment

Reproduced on @modelcontextprotocol/sdk 1.30.0 and confirmed present on main.


Happy to open a PR if you assign this to me.

Disclosure, per the org AI policy: I used AI assistance for this investigation and write-up — the differential harness that surfaced it and the drafting of this issue. The finding is reproduced and verified, and I can discuss any part of it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/core-internal/src/shared/uriTemplate.ts at match(), then trace how ResourceTemplate routes resource URIs through it. Use the expand/match examples and the reported value sweep to verify behavior; done means extracted values round-trip as decoded strings, including spaces, reserved characters, percent signs, and non-ASCII text.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.