Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: reject trailing newline in tool-name validation#3076

Merged
maxisbey merged 2 commits into
modelcontextprotocol:mainfrom
Otis0408:fix/tool-name-regex-trailing-newline
Jul 10, 2026
Merged

fix: reject trailing newline in tool-name validation#3076
maxisbey merged 2 commits into
modelcontextprotocol:mainfrom
Otis0408:fix/tool-name-regex-trailing-newline

Conversation

@Otis0408

@Otis0408 Otis0408 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Closes #3084

Summary

TOOL_NAME_REGEX in src/mcp/shared/tool_name_validation.py is end-anchored with $:

TOOL_NAME_REGEX = re.compile(r"^[A-Za-z0-9._-]{1,128}$")

In Python's default (non-MULTILINE) mode, $ matches at end-of-string or immediately before a single trailing \n. So a tool name ending in exactly one newline passes validation:

>>> validate_tool_name("evil_tool\n").is_valid
True          # expected: False (newline is not an allowed SEP-986 character)
>>> validate_and_warn_tool_name("evil_tool\n")
True          # no warning logged

The length guard uses len() (which counts the \n), so "a" * 127 + "\n" (length 128) also slips past both the length and the character check. Embedded and non-\n trailing control chars are already rejected correctly — only the single-trailing-newline case leaks.

Fix

Anchor the end with \Z (strict end-of-string) instead of $. No valid name is affected — re.match(r"^[A-Za-z0-9._-]{1,128}\Z", "abc") still matches; only "abc\n" now correctly fails.

Tests

Adds test_validate_tool_name_rejects_trailing_newline (parametrized over a trailing-newline name and a 128-char name whose last char is \n). Verified it fails on main (is_valid=True) and passes with the fix; the file's existing 29 tests are unchanged (no valid-name fixture ends in a newline).

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 2 files

Re-trigger cubic

@Otis0408 Otis0408 force-pushed the fix/tool-name-regex-trailing-newline branch from 5ff1df7 to 7723356 Compare July 9, 2026 05:51
TOOL_NAME_REGEX was end-anchored with $, which in Python's default mode also
matches just before a single trailing newline. So validate_tool_name("x\n")
returned is_valid=True with no warning, and a 127-char name plus "\n" (len
128) slipped past both the length and character checks. Anchor with \Z so a
trailing newline is treated as the disallowed character it is.
With re.match, a $-anchored pattern also matches just before a single
trailing newline, so tool-name validation accepted "name\n". Switch the
tool-name and URI-template varname checks to re.fullmatch, which puts
the whole-string requirement at the call site, and fold the regression
cases into the existing invalid-character parametrizations.
@maxisbey

Copy link
Copy Markdown
Contributor

Thanks @Otis0408 — nice catch, and thanks for filing #3084 to track it per CONTRIBUTING.md. I pushed two small changes on top: switched the fix from \Z to re.fullmatch() (same behavior — it puts the whole-string requirement at the call site and matches how the rest of the codebase validates), and applied the same fix to the URI-template varname check in uri_template.py, which had the same $-with-.match pattern. Merging once CI is green.

AI Disclaimer

@maxisbey maxisbey enabled auto-merge (squash) July 10, 2026 12:55
@maxisbey maxisbey merged commit 1216c53 into modelcontextprotocol:main Jul 10, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool name validation accepts a trailing newline (regex uses $ instead of \Z)

2 participants