Skip to content

fix(validators): adopt boundary-anchored mcp-name match in PyPI and NuGet (behavior change)#1331

Draft
rdimitrov wants to merge 1 commit into
followup/cargo-hardeningfrom
followup/registry-anchoring
Draft

fix(validators): adopt boundary-anchored mcp-name match in PyPI and NuGet (behavior change)#1331
rdimitrov wants to merge 1 commit into
followup/cargo-hardeningfrom
followup/registry-anchoring

Conversation

@rdimitrov
Copy link
Copy Markdown
Member

Stacked on #1330 (base = followup/cargo-hardening), so the diff here is just the PyPI/NuGet change. Opened as a draft because it's a deliberate behavior change that needs a maintainer decision — not a merge-when-green.

What

Adopt the boundary-anchored containsMCPNameToken helper (introduced in #1330) in the PyPI and NuGet validators, replacing their bare strings.Contains ownership-token checks. This closes prefix confusion: a README declaring a longer name (e.g. io.github.acme/widget-pro) no longer satisfies an ownership claim for a shorter prefix (io.github.acme/widget).

⚠️ This is a behavior change for PyPI/NuGet (not additive)

The new match is strictly stricter — it can only flip a previously-passing publish to failing, never the reverse. The realistic case that flips: a README whose only occurrence of the token is immediately followed by a server-name character [A-Za-z0-9._/-] — most plausibly a trailing period in prose:

...published as mcp-name: io.github.acme/widget.

Token on its own line, in backticks, or followed by whitespace/newline/HTML-tag is unaffected (the documented/common form).

Blast radius (verified): ownership validation runs only at publish (CreateServer); edits/status updates don't re-check it and there's no background re-validation — so already-stored servers are not retroactively affected. But an existing PyPI/NuGet publisher pushing a new version with the token in the glued form would fail where they previously succeeded.

Given the v0.1 API freeze, this warrants a conscious call (and arguably a changelog note) rather than riding in silently. Live positive tests (time-mcp-pypi, TimeMcpServer) still pass.

Why separate

Cargo (in #1330) is brand new, so anchoring it is non-breaking and ships there. This PR isolates the part that touches already-live registries so it can be accepted/declined/announced on its own. NPM is unaffected (it compares an exact metadata field, not README text).

🤖 Generated with Claude Code

…uGet

Stacked on the cargo follow-up (introduces containsMCPNameToken). This extends
the boundary-anchored ownership-token match to the PyPI and NuGet validators,
replacing their bare strings.Contains checks so a README declaring a longer name
(e.g. io.github.acme/widget-pro) no longer satisfies a claim for a shorter
prefix (io.github.acme/widget).

⚠️ BEHAVIOR CHANGE for PyPI/NuGet (not just additive):
The new match is strictly stricter — it can only flip a previously-passing
publish to failing, never the reverse. The realistic case that flips is a README
whose ONLY occurrence of the token is immediately followed by a server-name
character [A-Za-z0-9._/-], e.g. a trailing period in prose
("...published as mcp-name: io.github.acme/widget."). The token on its own line,
in backticks, or followed by whitespace/newline/HTML-tag is unaffected.

Re-validation runs only at publish time (CreateServer); edits/status updates do
not re-check ownership and there is no background re-validation, so already-
stored servers are not affected — but an existing PyPI/NuGet publisher pushing a
NEW VERSION with the token in the glued form would fail where it previously
passed. Given the v0.1 API freeze, this should land deliberately and not be
promoted to prod without sign-off. Live positive tests (time-mcp-pypi,
TimeMcpServer) still pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant