Skip to content

fix(server): escape regex special chars in resource template literals#2963

Closed
Bartok9 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Bartok9:fix/2961-resource-template-regex-escape
Closed

fix(server): escape regex special chars in resource template literals#2963
Bartok9 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Bartok9:fix/2961-resource-template-regex-escape

Conversation

@Bartok9

@Bartok9 Bartok9 commented Jun 25, 2026

Copy link
Copy Markdown

Summary

  • ResourceTemplate.matches() now treats regex-special characters in the literal parts of a URI template (., ?, +, etc.) as literals instead of regex metacharacters.
  • Fixes false positives where a template like data://.well-known/{name} matched URIs it should not.

Motivation

Closes #2961.

matches() converted the URI template to a regex with plain string replacement:

pattern = self.uri_template.replace("{", "(?P<").replace("}", ">[^/]+)")

This left regex-special characters in the literal portions unescaped, so they acted as metacharacters and produced incorrect matches:

Template False match
data://.well-known/{name} data://Xwell-known/hello (. = any char)
data://items/{id}.json data://items/123Xjson (. = any char)

Fix

Escape the whole template with re.escape() first, then substitute the escaped {param} markers with named capture groups:

_PARAM_PATTERN = re.compile(r"\\\{([^}]+?)\\\}")
...
pattern = _PARAM_PATTERN.sub(lambda m: f"(?P<{m.group(1)}>[^/]+)", re.escape(self.uri_template))

Literal characters are now matched literally; parameters still capture [^/]+ as before.

Verification

  • uv run pytest tests/server/mcpserver/resources/test_resource_template.py — 16 passed
  • uv run ruff check / ruff format --check — clean

Real behavior proof

Regression test test_template_matches_escapes_regex_special_chars reproduces the issue cases. It fails without the source fix and passes with it:

# Without the source fix (test present):
TestResourceTemplate::test_template_matches_escapes_regex_special_chars  53 / 71  AssertionError
Results: 1 failed

# With the fix:
Results: 16 passed

Closes modelcontextprotocol#2961

ResourceTemplate.matches() built its regex via plain string replacement
("{" -> "(?P<", "}" -> ">[^/]+)"), leaving regex-special characters in the
literal parts of the URI template (".", "?", "+", etc.) unescaped. They were
then interpreted as metacharacters, causing false matches:

  data://.well-known/{name}  matched  data://Xwell-known/hello  (. = any char)
  data://items/{id}.json     matched  data://items/123Xjson     (. = any char)

Escape the whole template with re.escape() first, then substitute the
escaped "{param}" markers with named capture groups so literal characters
are matched literally while parameters still capture.

Adds a regression test that fails without the fix.
@Kludex

Kludex commented Jun 25, 2026

Copy link
Copy Markdown
Member

You've opened a duplicated pull request, please search opened PRs before creating new ones. Duplicated from #2749.

@Kludex Kludex closed this Jun 25, 2026
@modelcontextprotocol modelcontextprotocol locked as resolved and limited conversation to collaborators Jun 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] ResourceTemplate.matches() does not escape regex special chars in URI template literals

2 participants