Repository navigation
Conversation
modelcontextprotocol#1055 noted that crates.io has ~1,800 MCP-related packages with no direct path into the registry, only the MCPB binary-packaging workaround. This commit adds the schema-side wiring for `registryType: cargo`: - `pkg/model/constants.go`: `RegistryTypeCargo` + `RegistryURLCrates` - `server.json` schema and `openapi.yaml`: `cargo` in the example enum for `registryType`; `https://crates.io` in `registryBaseUrl` - `generic-server-json.md`: new minimal Cargo example, with a runtime-model note. `cargo install` puts the binary on PATH at `~/.cargo/bin` and the MCP client invokes it by name. `npx` (npm), `uvx` (PyPI), and `dnx` (NuGet, .NET 10 SDK) were the cross-ecosystem precedents considered; cargo has no single-shot analog, so `runtimeHint` is omitted. - `tools/validate-examples/main.go`: `expectedServerJSONCount` bumped 16 → 17 to match the new example (caught by `make validate`). Validator and `publish-cargo.md` follow on this branch once the schema-side direction is settled. Refs modelcontextprotocol#1055
Closes modelcontextprotocol#1055. Verification mirrors the PyPI validator: substring-match `mcp-name: <serverName>` against the package's rendered README. The publisher adds a single line to their README before publishing. Two-call retrieval pattern: 1. `GET /api/v1/crates/{name}/{version}/readme` returns 200 with a JSON pointer `{"url": "https://static.crates.io/readmes/.../...html"}` — crates.io hands us the URL rather than emitting a 302. 2. Follow the pointer to the rendered HTML. The two-call pattern stays on the documented public crates.io API surface. The CDN URL layout is observed-stable, but treating it as the entry point would mean depending on an undocumented path. With two calls, crates.io controls where the README lives. Missing crates and missing versions surface as 403 from the CDN (S3's default for missing keys), not 404. The validator treats any non-200 as "not found" and surfaces the actual status code in the error message. Tests are integration-only (matching the npm/pypi pattern). 16 sub-cases across input validation, registry-baseURL rejection (four variants), ownership against real crates (serde, tokio, rand), and server-name format variations. The positive-path case is gated on `rust-faf-mcp` v0.2.3+ being published with `mcp-name: io.github.Wolfe-Jam/rust-faf-mcp` in its README — the commented-out test in `cargo_test.go` will uncomment to become the live anchor once that publish happens. Refs modelcontextprotocol#1055
26eb180 to
6b2b006
Compare
|
@rdimitrov — hey, any thoughts on the review + the runtime-model direction? Once that's settled I can land publish-cargo.md and close out #1055. Review-ready whenever you have a window — lmk if I can help. |
This comment was marked as spam.
This comment was marked as spam.
Adds <!-- mcp-name: io.github.Wolfe-Jam/rust-faf-mcp --> to README as the ownership-verification marker for the upcoming MCP Registry cargo validator (modelcontextprotocol/registry#1207). Hidden HTML comment per the documented Cargo ownership-verification convention; pairs with the existing faf-meta line as substrate metadata. Validator does a substring match against the rendered README on crates.io.
v0.3.0 shipped the mcp-name token as an HTML comment, which crates.io strips during markdown→HTML rendering — the token was invisible to substring-matching validators (modelcontextprotocol/registry#1207). Surfaces mcp-name as visible markdown in the README Links section. v0.3.0 binary is identical and stays installable; v0.3.1 is the MCP-Registry-verifiable version. Also: - Bumps version across Cargo.toml + manifest.json + server.json + project.faf + CLAUDE.md (tier4_aero drift-detection enforced). - Refreshes CLAUDE.md bi-sync timestamp (was 12 weeks stale). - server.json fileSha256 zero-sentinel for v0.3.1 MCPB package; CHANGELOG Known-limitation section explains the chicken-and-egg with CI binary build. Intended registration path is registryType: cargo once #1207 merges. - Cargo packaging excludes .well-known/ (SEP-2127 staging).
Addresses @P4ST4S's PR modelcontextprotocol#1207 review (all 3 items): - Positive-path test coverage (mildly blocking) — added two complementary tests in cargo_test.go: TestValidateCargo_PositivePathMock (hermetic, httptest.Server stand-in for crates.io) and TestValidateCargo_LivePositivePath (live anchor against rust-faf-mcp v0.3.1 on real crates.io). The HTTP pipeline is split into a package-private validateCargoREADME, exposed to tests via export_test.go without weakening the exact-baseURL guard in the public ValidateCargo. - 5xx as transient (defer-able, done anyway) — 403 from static.crates.io (S3 default for missing keys) stays 'not found'; 5xx now reports as 'likely transient, retry later' with the actual status code. Applied symmetrically to both the metadata endpoint and the README endpoint. - CargoReadmeMetaResponse doc comment (minor) — clarified that the 200+JSON shape requires Accept: application/json; without it, the endpoint emits a 302. Also lands docs/modelcontextprotocol-io/package-types.mdx 'Cargo (Rust) Packages' section, including: - Runtime-model resolution: cargo (source-distributed) and MCPB (prebuilt-binary) both documented as first-class paths for Rust MCP authors; the schema is additive and doesn't force a recommendation. - Cargo-specific 'gotcha' caveat in the Ownership Verification section: crates.io strips HTML comments during markdown→HTML rendering (unlike PyPI/NuGet which preserve them), so cargo authors MUST include the mcp-name token as visible markdown text — the <!-- ... --> hidden form documented elsewhere does not work for cargo. Caught live by shipping rust-faf-mcp v0.3.0 with the hidden form (validator rejected), then v0.3.1 with the visible form (validator accepts — see live test). Tests: 19/19 cargo tests pass (16 existing + 2 hermetic + 1 live anchor). make validate: clean. golangci-lint: 0 issues. Closes modelcontextprotocol#1055 (once merged + the two queued real-world Rust MCP servers register: rust-faf-mcp v0.3.1 and perfetto-mcp-rs).
|
@P4ST4S — thanks for the careful read and the live API verification. All three items addressed in 1f3be53: Mildly blocking — positive-path test coverage
Defer-able — 5xx surfaces as "not found" Minor — doc comment precision Cargo-specific gotcha discovered while testing live (and addressed in crates.io strips HTML comments during markdown→HTML README rendering — unlike PyPI/NuGet, which preserve them in their raw description payloads. So the Caught this by shipping
@rdimitrov — quick state-of-the-PR summary:
Ready for review whenever you have a window, @rdimitrov. |
This comment was marked as spam.
This comment was marked as spam.
…otocol#1321 pattern (P4ST4S review polish)
Fixes CI lint (golangci-lint gofmt formatter) flagged on internal/validators/registries/cargo_test.go. Whitespace-only; no behavior change. Verified locally with golangci-lint v2.11.4: 0 issues. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
Lint is fixed in The failure was a CI is now green: Build, Lint, and Validate ✓ and Tests ✓ (run). Assisted by Claude, approved by Wolfejam. |
|
Thanks for the thorough work on this, @Wolfe-Jam and for patiently working through all the review rounds. 🙏 I gave it a pass and I'm happy with it. Merging now so it can land on I noted a few minor follow-ups during review, I'll send those as separate upstream PRs; nothing here should block this. I thought opening a stacked PR against yours but thought it's easier to merge this and iterate on top of it Thanks again for helping move Cargo support forward! 👍 🙌 |
|
@rdimitrov — thank you. Appreciate you shepherding this through all the rounds and merging via staging, and the call to iterate on top rather than block on the minor follow-ups is spot on. Point me at the stacked PRs whenever they land — happy to pick up any or review. @P4ST4S — the external review made this materially better. The positive-path push (the hermetic mock + live-anchor pair) closed a real gap, the 5xx-vs-403 split is a genuine operational win, and the HTML-comment-stripping gotcha only surfaced because you took the two-call flow against live crates.io seriously. Thank you for the careful read. With Good to help move Cargo support forward 🦀 Assisted by Claude, approved by Wolfejam. |
…eholder mcpb) Register via the new cargo (crates.io) package type — modelcontextprotocol/registry#1207 (merged 2026-06-03) — instead of the never-functional mcpb placeholder (0000 SHA, no real binary). identifier rust-faf-mcp, v0.3.1: the validator's live-anchor crate, with the visible mcp-name token verified in the published README. Ready to publish the instant cargo support reaches the production registry. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
FYI — the first cargo server is up: |
…tests Follow-up to #1207, addressing items from review of the cargo validator. Scoped to cargo + shared helpers only — no behavior change for existing npm/pypi/nuget/oci/mcpb publishers. SSRF hardening of the two-call README retrieval: - Pin the step-2 README URL to an allowed host (static.crates.io in prod; the base host under test) before fetching, so a metadata response cannot steer the validator at an internal/attacker host. - CheckRedirect policy pins every redirect hop to the same allowlist. - Cap the README body with io.LimitReader (5 MiB). Clearer status handling (previously any non-5xx/non-200 collapsed to "not found"): - 429 is reported as transient/retryable rather than "not found", at both steps. - A 403 from static.crates.io is disambiguated via the crate-version endpoint: genuinely-missing stays "not found"; exists-but-no-README gets an actionable "add a README with mcp-name and republish" message (mirrors NuGet). This continues the 5xx-vs-403 diagnostic split @P4ST4S started in the #1207 review. Add a shared, boundary-anchored containsMCPNameToken helper (prevents prefix confusion, e.g. a README declaring io.github.acme/widget-pro satisfying a claim for io.github.acme/widget) and use it from the cargo validator. Adopting it in the PyPI/NuGet validators is a follow-up (it is a behavior change for those already-live registries). Tests: hermetic positive ServerNameFormats; combined fixture gains a version-existence endpoint + cases for 403-missing vs 403-no-readme, 429, and prefix-confusion rejection; new foreign-README-host (SSRF) test; internal test for the helper. Docs: list crates.io in registry requirements + the Package doc. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…tests (#1330) Follow-up to #1207, addressing items from the cargo validator review. **Scoped to cargo + shared helpers — no behavior change for existing npm/pypi/nuget/oci/mcpb publishers.** Safe to merge and promote. ### Changes **SSRF hardening of the two-call README retrieval** - Pin the step-2 README URL to an allowed host (`static.crates.io` in prod; the base host under test) *before* fetching, so a metadata response can't steer the validator at an internal/attacker host. - `CheckRedirect` policy pins every redirect hop to the same allowlist (the initial URL being pinned isn't enough if an upstream 3xx is followed). - Cap the README body with `io.LimitReader` (5 MiB). > Not publisher-exploitable today (the URL comes from crates.io), so this is defense-in-depth — but it makes the "host is pinned" guarantee hold in code rather than rely on crates.io's behavior. **Clearer status handling** (previously any non-5xx/non-200 collapsed to "not found") - **429** → reported as transient/retryable, at both the metadata and README steps. - **403** → disambiguated via the crate-version endpoint: genuinely-missing stays "not found"; *exists-but-no-README* gets an actionable "add a README with `mcp-name` and republish" message (mirrors the NuGet validator). This continues the 5xx-vs-403 diagnostic split @P4ST4S started in the #1207 review — thanks! **Shared `containsMCPNameToken` helper** Boundary-anchored ownership-token match (prevents prefix confusion, e.g. a README declaring `io.github.acme/widget-pro` satisfying a claim for `io.github.acme/widget`), used here **by the cargo validator only**. Adopting it in PyPI/NuGet is a separate follow-up because it's a behavior change for those already-live registries. **Tests & docs** Hermetic positive `ServerNameFormats`; combined fixture gains a version-existence endpoint + cases for 403-missing vs 403-no-README, 429, and prefix-confusion rejection; new foreign-README-host (SSRF) test; internal test for the helper. Docs: list `crates.io` in the registry-requirements list + the `Package` model doc. ### Testing `go build`, `go vet`, full `./internal/validators/...` suite (incl. live cargo positive), `make check-schema`, `validate-examples` all pass. No new `golangci-lint` findings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Promotes production to the [`v1.8.0`](https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.0) release. - `deploy/Pulumi.gcpProd.yaml` → `imageTag: 1.8.0` (one line). - The release build for `v1.8.0` completed successfully, so the image is present in ghcr. - **Merging this triggers `deploy-production.yml`** (it's path-filtered to `deploy/Pulumi.gcpProd.yaml`); the PR itself doesn't deploy. ### Notable behavior changes in v1.8.0 - **Org-namespace publishing now requires org Owner** (via GitHub login / PAT). Member-level publishers lose org publish — intended tightening. - Stricter validation may reject some previously-accepted package metadata / names (#1310, #1331, #1411). - New: cargo (crates.io) package registry support (#1207). ### After merge - Confirm prod `/v0/version` reports `1.8.0` before treating the rollout as done. Co-authored-by: Claude Opus 4.8 <[email protected]>
|
@rdimitrov — been out for a few days (watching Argentina beat my England 😞 in Atlanta…), so some good news: quick close-out now that prod is on v1.8.0. io.github.Wolfe-Jam/rust-faf-mcp v0.3.1 is active on production with registryType: cargo (crates.io [email protected], visible mcp-name token, isLatest: true). Published 2026-07-17. Verified: Thanks again for merging #1207, the #1330 hardening, and promoting cargo to prod. Happy to help if anything looks off on the registry side. 🦀 |
The cargo registry type has been live since v1.8.0 (#1207). This PR only updates the schema examples so they match reality. - Add "cargo" to registryType.examples - Add "https://crates.io" to registryBaseUrl.examples No behaviour change. Note: versioned schemas are synced from modelcontextprotocol/static. A follow-up there keeps this durable across schema sync. Co-authored-by: Wolfe-Jam <[email protected]>
The registry has supported `registryType: "cargo"` since modelcontextprotocol/registry#1207, and it is live in production, but this page never listed it. The section is reflected verbatim from the source of this page: https://github.com/modelcontextprotocol/registry/blob/main/docs/modelcontextprotocol-io/package-types.mdx
…r published (#40) The MCP Registry added cargo (crates.io) as a package registryType in registry v1.8.0 (2026-07-13, PR modelcontextprotocol/registry#1207). sudo-proxy 1.0.0 is now published to the official registry as io.github.tarides/sudo-proxy with a cargo package, so the tripwire has served its purpose. It was also never going to turn GREEN as written: its signal counted pre-existing cargo-type servers in the public listing, which was the wrong heuristic — the registry accepts cargo regardless of whether any cargo server is already listed. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
mcp-publisher 1.8.0 Created-by: HarmonybrewBot Commit-by: HarmonybrewBot Merged-by: HarmonybrewBot Description: Created by `brew bump` --- Created with `brew bump-formula-pr`.<details> <summary>release notes</summary> <pre>## What's Changed * deploy: update prod to v1.7.9 by @rdimitrov in modelcontextprotocol/registry#1282 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.237.0 to 3.238.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1283 * chore(deps): reduce dependabot frequency from daily to weekly by @rdimitrov in modelcontextprotocol/registry#1284 * build(deps): bump github.com/go-git/go-git/v5 from 5.19.0 to 5.19.1 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1292 * build(deps): bump github.com/google/go-containerregistry from 0.21.5 to 0.21.6 by @dependabot[bot] in modelcontextprotocol/registry#1295 * build(deps): bump github.com/danielgtaylor/huma/v2 from 2.37.3 to 2.38.0 by @dependabot[bot] in modelcontextprotocol/registry#1296 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.238.0 to 3.242.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1297 * build(deps): bump goreleaser/goreleaser-action from 7.2.1 to 7.2.2 in the actions group by @dependabot[bot] in modelcontextprotocol/registry#1299 * build(deps): bump golang.org/x/net to v0.55.0 by @rdimitrov in modelcontextprotocol/registry#1308 * build(deps): bump github.com/pulumi/pulumi-kubernetes/sdk/v4 from 4.30.0 to 4.31.1 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1298 * docs: update maintainer/collaborator matrix in README by @tadasant in modelcontextprotocol/registry#1324 * build(deps): bump the actions group with 2 updates by @dependabot[bot] in modelcontextprotocol/registry#1314 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.242.0 to 3.243.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1313 * build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys from 1.4.0 to 1.5.0 by @dependabot[bot] in modelcontextprotocol/registry#1312 * build(deps): bump the opentelemetry group with 5 updates by @dependabot[bot] in modelcontextprotocol/registry#1311 * feat: add cargo (crates.io) as a package registry type by @Wolfe-Jam in modelcontextprotocol/registry#1207 * build(deps): bump go.opentelemetry.io/contrib/instrumentation/runtime from 0.68.0 to 0.69.0 in the opentelemetry group by @dependabot[bot] in modelcontextprotocol/registry#1332 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.243.0 to 3.244.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1333 * build(deps): bump github.com/jackc/pgx/v5 from 5.9.2 to 5.10.0 by @dependabot[bot] in modelcontextprotocol/registry#1334 * fix(cargo): harden README fetch, clarify status handling, strengthen tests by @rdimitrov in modelcontextprotocol/registry#1330 * fix(validators): harden mcp-name matching (PyPI/NuGet anchoring, comment-form safe) + cargo follow-ups by @rdimitrov in modelcontextprotocol/registry#1331 * fix: client-cancelled GET /v0/servers returns 499 without error log by @advancedresearcharray in modelcontextprotocol/registry#1335 * fix: don't leak internal error detail in GET /v0/servers 500 response by @rdimitrov in modelcontextprotocol/registry#1338 * build(deps): bump the actions group with 2 updates by @dependabot[bot] in modelcontextprotocol/registry#1392 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.244.0 to 3.248.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1391 * build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.13.1 to 1.14.0 by @dependabot[bot] in modelcontextprotocol/registry#1375 * build(deps): bump github.com/coreos/go-oidc/v3 from 3.18.0 to 3.19.0 by @dependabot[bot] in modelcontextprotocol/registry#1374 * build(deps): bump github.com/google/go-containerregistry from 0.21.6 to 0.21.7 by @dependabot[bot] in modelcontextprotocol/registry#1373 * Fix broken reference documentation links by @kriptoburak in modelcontextprotocol/registry#1387 * build(deps): bump github.com/pulumi/pulumi-kubernetes/sdk/v4 from 4.31.1 to 4.32.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1353 * ci: auto-close PRs that try to publish servers via the repo by @rdimitrov in modelcontextprotocol/registry#1393 * build(deps): bump golang.org/x/mod from 0.37.0 to 0.38.0 by @dependabot[bot] in modelcontextprotocol/registry#1428 * build(deps): bump github.com/coreos/go-oidc/v3 from 3.19.0 to 3.20.0 by @dependabot[bot] in modelcontextprotocol/registry#1429 * build(deps): bump the actions group across 1 directory with 4 updates by @dependabot[bot] in modelcontextprotocol/registry#1430 * build(deps): bump github.com/pulumi/pulumi/sdk/v3 from 3.248.0 to 3.251.0 in /deploy by @dependabot[bot] in modelcontextprotocol/registry#1431 * fix(auth): grant org namespace only to org Owners, not all members by @tadasant in modelcontextprotocol/registry#1383 * build(deps): bump golang.org/x/crypto from 0.51.0 to 0.52.0 by @dependabot[bot] in modelcontextprotocol/registry#1433 * docs(auth): document fine-grained PAT permission for org publishing (+ pagination-cap test) by @rdimitrov in modelcontextprotocol/registry#1435 * docs: add polygraph to community projects by @RubenSousaDinis in modelcontextprotocol/registry#1421 * fix(ci): re-validate author association via REST in close-invalid-publish-prs by @rdimitrov in modelcontextprotocol/registry#1440 * fix: reject mangled publisher metadata by @he-yufeng in modelcontextprotocol/registry#1310 * fix(api): allow PATCH in CORS so browsers can call the status endpoints by @JosephDoUrden in modelcontextprotocol/registry#1436 * test(api): remove placeholder CORS test superseded by #1436 by @rdimitrov in modelcontextprotocol/registry#1441 * fix(validators): distinguish a missing package from a missing version on PyPI/NPM by @sronix in modelcontextprotocol/registry#1411 ## New Contributors * @Wolfe-Jam made their first contribution in modelcontextprotocol/registry#1207 * @advancedresearcharray made their first contribution in modelcontextprotocol/registry#1335 * @kriptoburak made their first contribution in modelcontextprotocol/registry#1387 * @RubenSousaDinis made their first contribution in modelcontextprotocol/registry#1421 * @he-yufeng made their first contribution in modelcontextprotocol/registry#1310 * @sronix made their first contribution in modelcontextprotocol/registry#1411 **Full Changelog**: https://github.com/modelcontextprotocol/registry/compare/v1.7.9...v1.8.0</pre> <p>View the full release notes at <a href="https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.0">https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.0</a>.</p> </details> <hr> See merge request: Harmonybrew/homebrew-core!14181
Adds support for
registryType: cargoso Rust MCP servers published to crates.io can be registered through thedocumented validation flow rather than the MCPB binary-packaging workaround. Closes #1055.
Motivation and Context
#1055 noted that crates.io has ~1,800 MCP-related packages with no direct path into the registry — only the MCPB
binary-packaging workaround. This PR adds first-class support for cargo as a package registry type: schema +
API surface, validator, integration tests, and a documented example. The publishing guide
(
docs/guides/publishing/publish-cargo.md) follows on this branch once the runtime-model direction inAdditional context is settled.
How Has This Been Tested?
make validate— clean. Schema-vs-openapi sync verified; 17/17 examples ingeneric-server-json.mdvalidate against the schema;
expectedServerJSONCountbumped 16 → 17 to match the new Cargo example.go test ./internal/validators/...— passes. 16 cargo validator sub-cases across 4 test functions, runagainst real crates.io (~2.5s wall):
serde,tokio,rand) — all correctly rejected for missingmcp-nametokenio.github.OWNER/REPO, multi-hyphen, underscore, numeric suffix)rust-faf-mcpv0.2.3+ being published withmcp-name: io.github.Wolfe-Jam/rust-faf-mcpin its README. Reserved as a TODO incargo_test.go; uncomments to become thelive anchor once that publish lands.
make test-unit— not run due to a Go toolchain version quirk on my workstation (projectauto-downloads 1.26.0; my local
gois 1.25.6, causing compile mismatch). CI will exercise the fullPostgreSQL-backed suite.
Breaking Changes
None. This is an additive change —
cargojoins the supportedregistryTypeenum alongsidenpm/pypi/nuget/oci/mcpb. Existing publishes continue to work unchanged.Types of changes
generic-server-json.md)Checklist
Additional context
Validator design — two-call retrieval on the documented API
internal/validators/registries/cargo.gomirrors the PyPI validator's README-token approach (substring-matchmcp-name: <serverName>), with a two-call retrieval pattern to stay on the documented public crates.io API:GET /api/v1/crates/{name}/{version}/readmereturns 200 OK with a JSON pointer ({"url": "https://static.crates.io/readmes/.../...html"}) — crates.io hands us the URL rather than emitting a 302.The two-call pattern stays on the documented public surface. The CDN URL layout is observed-stable, but treating
it as the entry point would mean depending on an undocumented path. With two calls, crates.io controls where
the README lives — if they move it, the metadata endpoint hands us the new URL.
Missing crates and missing versions surface as 403 from the CDN (S3's default for missing keys), not 404.
The validator treats any non-200 as "not found" and surfaces the actual status code in the error message.
Open question — runtime model
Cargo's runtime model is genuinely different from npm/PyPI/NuGet.
cargo installis one-time (binary lands onPATH at
~/.cargo/bin), not per-invocation likenpx,uvx, ordnx(the new one in .NET 10 SDK Preview 6+).The new Cargo example in
generic-server-json.mdannotates this honestly and omitsruntimeHint.If a different framing is preferred — e.g. recommending MCPB (prebuilt binary distribution via GitHub
Releases) as the primary path for Rust MCP servers instead of cargo — happy to adjust the documentation
accordingly. The schema + validator code in this PR is additive and doesn't force a recommendation either
way; a Rust author who chooses cargo can use it, and one who prefers MCPB still can.
Out of scope (deferred)
docs/guides/publishing/publish-cargo.md— follows on this branch once the runtime-model direction aboveis settled.
Cargo.tomlautodetect incmd/publisher/commands/init.go— separate concern, separate PR.rust-faf-mcpv0.2.3+ publishing as noted in How Has This BeenTested?.