Skip to content

fix(core): expand RFC 6570 list and multi-variable expressions correctly - #3050

Open
surlymochan wants to merge 1 commit into
modelcontextprotocol:mainfrom
surlymochan:fix/uri-template-prefix-expansion
Open

surlymochan wants to merge 1 commit into
modelcontextprotocol:mainfrom
surlymochan:fix/uri-template-prefix-expansion

Conversation

@surlymochan

Copy link
Copy Markdown

Summary

UriTemplate.expand() doesn't follow RFC 6570 for multi-variable expressions or non-exploded lists under the . and / operators:

template variables before RFC 6570
{x,half,y} x=1024, half=50%, y=768 1024,50%,768 1024,50%25,768 (§3.2.1)
{/who,dub} who=fred, dub=me/too fred,me/too /fred/me%2Ftoo (§3.2.9)
{.who,who} who=fred fred,fred .fred.fred (§3.2.8)
X{.list} list=[red,green,blue] X.red.green.blue X.red,green,blue (§3.2.8)
{/list} list=[red,green,blue] /red/green/blue /red,green,blue (§3.2.9)

The multi-variable branch in expandPart returned the raw values joined with ,, skipping both encoding and the operator prefix, so you could get an unencoded / that changes the path. The . and / cases also joined every list with the operator separator, but RFC 6570 only does that for the exploded (*) form.

Change

  • Multi-variable expressions now encode each value for the operator, join the values with the operator's separator, and add the prefix once.
  • A non-exploded list under . or / is joined with ,. Exploded lists and single-variable expansion are unchanged.
  • Added a patch changeset for @modelcontextprotocol/core-internal.

Testing

  • New cases in packages/core-internal/test/shared/uriTemplate.test.ts use the RFC's own examples. Three of them fail on main and pass with this change.
  • packages/core-internal: vitest run passes 1529/1529, and typecheck and lint are clean.
  • packages/server: vitest run passes 577/577.

This touches expandPart only. #3003 (prefix modifiers) and #2810 (decoding in match()) are about other parts of UriTemplate.

UriTemplate.expandPart had two gaps against RFC 6570:

- A multi-variable expression returned its raw values joined with ",",
  without encoding or the operator prefix. `{x,half,y}` produced
  `1024,50%,768` and `{/who,dub}` produced `fred,me/too`.
- Under the `.` and `/` operators a non-exploded list was joined with the
  operator separator, so `{.list}` gave `.red.green.blue` instead of
  `.red,green,blue`. Only the exploded form uses the operator separator.

Each value of a multi-variable expression is now encoded for the operator,
joined with the operator separator and prefixed once, and a non-exploded
list joins with ",". Exploded lists and single-variable expansion are
unchanged. Tests use the RFC's own examples (3.2.1, 3.2.8, 3.2.9).
@surlymochan
surlymochan requested a review from a team as a code owner October 19, 2026 02:49
@changeset-bot

changeset-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6bbf23c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@3050

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@3050

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@3050

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@3050

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@3050

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@3050

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@3050

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@3050

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@3050

commit: 6bbf23c

@claude claude Bot added the v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes label Oct 19, 2026
@0xamlab

0xamlab commented Oct 19, 2026

Copy link
Copy Markdown

Verified locally. On main the five RFC 6570 examples from the description all fail: {x,half,y} returns 1024,50%,768, {/who,dub} returns fred,me/too, etc. The fix encodes each value and applies the operator prefix once via packages/core-internal/src/shared/uriTemplate.ts:108 (prefixOf) and packages/core-internal/src/shared/uriTemplate.ts:118 (separatorOf), while the multi-variable branch at :156-164 now uses them instead of raw comma joining. With the PR branch pnpm --filter @modelcontextprotocol/core-internal test passes 1529/1529 tests.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Ideas, requests and plans for v2 of the SDK which will incorporate major changes and fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants