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.

Assessment

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

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.

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.

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

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.

More from modelcontextprotocol/typescript-sdk

All issues in modelcontextprotocol/typescript-sdk

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.