Skip to content

fix(core-internal): support RFC 6570 prefix modifiers in UriTemplate (#3000) - #3003

Open
MokuLakshithReddy wants to merge 2 commits into
modelcontextprotocol:mainfrom
MokuLakshithReddy:fix/uri-template-prefix-modifiers
Open

MokuLakshithReddy wants to merge 2 commits into
modelcontextprotocol:mainfrom
MokuLakshithReddy:fix/uri-template-prefix-modifiers

Conversation

@MokuLakshithReddy

Copy link
Copy Markdown

Motivation and Context

Fixes #3000

The SDK's UriTemplate previously treated an RFC 6570 prefix modifier (:N) as part of the variable name because getNames() stripped * but retained :N. As a result:

  • template.variableNames returned ["name:3"] instead of ["name"].
  • template.expand({ name: "abcdef" }) looked for variables["name:3"] and dropped scalar values from the expanded URI.
  • template.match() looked for an argument named "name:3".

Description of Changes

  • VarSpec parsing: Introduced parseVarSpec() in UriTemplate to separate the variable name, explode modifier (*), and prefix modifier (:N).
  • Clean variable names: names and variableNames now preserve the clean variable name (["name"]).
  • Scalar prefix truncation: Added applyPrefix() to truncate scalar values to the specified prefix length using code point spreading ([...value].slice(0, prefix).join('')), ensuring correct handling of multi-byte and supplementary Unicode characters before percent-encoding.
  • RFC 6570 compliance: Prefix modifiers are applied across all template operators, and per RFC 6570 §2.4.1, composite values (arrays) ignore prefix modifiers.
  • Regex matching: Updated partToRegExp to use clean variable names when generating matching regexes.
  • Unit tests: Added 17 unit tests in packages/core-internal/test/shared/uriTemplate.test.ts covering ASCII, non-ASCII Unicode, supplementary characters, prefixes longer than values, missing variables, array values, and .match().
  • Changeset: Added .changeset/uri-template-prefix-modifiers.md.

How Has This Been Tested?

  • Added unit tests in packages/core-internal/test/shared/uriTemplate.test.ts covering all prefix modifier behaviors; all 55 tests pass.
  • Verified type check and ESLint cleanly.

Copilot AI balanced review requested due to automatic review settings October 11, 2026 19:31
@changeset-bot

changeset-bot Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2e8e0c9

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

@MokuLakshithReddy
MokuLakshithReddy requested a review from a team as a code owner October 11, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@pkg-pr-new

pkg-pr-new Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

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

@modelcontextprotocol/codemod

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

@modelcontextprotocol/core

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

@modelcontextprotocol/server

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

@modelcontextprotocol/server-legacy

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

@modelcontextprotocol/express

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

@modelcontextprotocol/fastify

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

@modelcontextprotocol/hono

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

@modelcontextprotocol/node

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

commit: 2e8e0c9

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

@koriyoshi2041 koriyoshi2041 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The valid Unicode path looks good, but malformed prefix specs are now silently reinterpreted as valid variable names. RFC 6570 defines max-length as [1-9][0-9]{0,3} and makes prefix/explode mutually exclusive. At this head I get:

{name:0}     -> abcdef
{name:10000} -> abcdef
{name:abc}   -> abcdef
{name:3*}    -> abc

All four also report variableNames === ['name']. Before this change they did not resolve name, so this broadens invalid templates into successful expansions. Could parseVarSpec accept only :[1-9][0-9]{0,3} and reject (or preserve the old unresolved behavior for) malformed/combined modifiers? Focused regression cases for :0, five digits, non-digits, and :N* would pin the boundary.

@MokuLakshithReddy

Copy link
Copy Markdown
Author

@koriyoshi2041 Thank you for the detailed review! I have updated the implementation to address this:

  1. Strict max-length validation: parseVarSpec now validates that the prefix length matches ^[1-9]\d{0,3}$ (:[1-9][0-9]{0,3}), enforcing non-zero integers under 10000 per RFC 6570 §2.4.1.
  2. Mutual exclusivity: Enforced mutual exclusivity between prefix and explode modifiers; combined specs like :N* are not treated as valid prefix modifiers.
  3. Preserved unresolved behavior: Malformed or combined modifiers now preserve the previous behavior — the literal unparsed text is retained (e.g. name:0, name:10000, name:abc, name:3), so variableNames does not resolve to ['name'] and scalar values are not expanded.
  4. Regression tests: Added focused unit tests in uriTemplate.test.ts for :0, five digits (:10000), non-digits (:abc), combined (:3*), and valid upper boundary (:9999).

@koriyoshi2041

Copy link
Copy Markdown

Confirmed on 2e8e0c95: the parser now accepts only :[1-9][0-9]{0,3}, keeps prefix/explode mutually exclusive, and the four malformed cases remain unresolved rather than expanding name. The added :9999 case pins the valid upper boundary. All hosted checks are green; my finding is resolved.

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.

UriTemplate treats RFC 6570 prefix modifiers as variable-name text and drops scalar values

3 participants