Skip to content

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

Description

@MahathirMohammadShuvo

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.

Activity

  1. xianjianlf2 commented on Aug 27, 2026

    @xianjianlf2

    I have reproduced this on current main and prepared a focused fix with regression coverage for percent-decoding values returned by UriTemplate.match(), including exploded lists and malformed encodings. I would like to take this issue and open a small PR.

  2. MahathirMohammadShuvo commented on Aug 27, 2026

    @MahathirMohammadShuvo
    Author

    Thanks for taking a look. I offered to fix this when I filed it — I held off writing the PR because AGENTS.md says a PR needs an issue assigned to its author, so I have the differential harness that surfaced it but nothing pushed.

    Happy for a maintainer to assign whichever of us they'd rather have on it.

  3. edenbuilds commented on Aug 27, 2026

    @edenbuilds

    I prepared a ready-to-review fix on edenbuilds:codex/hunt-mcp-2728 (compare: main...edenbuilds:codex/hunt-mcp-2728).

    It decodes scalar and exploded-array captures in UriTemplate.match() with decodeURIComponent, while retaining malformed components as-is so matching stays non-throwing. The two regression tests were verified red with the source fix stashed, then green after the fix. Focused result: 2 passed, 38 skipped; core-internal typecheck passed; the repository pre-push hook passed Build (46s), Typecheck (52s), and Lint (137s).

    Commits e6bf4565 and b2ddf4fd are both attributed to edenbuilds. My account cannot create PRs in this repository (CreatePullRequest permission denied), so please open the PR from the branch or let me know if you prefer a maintainer cherry-pick.

  4. mikemikimike commented on Aug 29, 2026

    @mikemikimike

    I reproduced this on current main and confirmed that expand() percent-encodes variable values while match() returns the encoded capture. I plan to decode matched variable values with decodeURIComponent, add focused round-trip coverage for spaces, reserved characters, and non-ASCII input, and preserve malformed-escape handling without changing template matching semantics.

  5. added
    v1Issues / PRs related to v1.x
    v2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes
    on Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    v1Issues / PRs related to v1.xv2Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions