modelcontextprotocol / modelcontextprotocol/typescript-sdk
UriTemplate.match() does not percent-decode extracted values
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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