Skip to content

chore(deps): migrate rmcp and rmcp-macros to 3.1.4 in lockstep - #6995

Merged
forkwright merged 2 commits into
mainfrom
chore/rmcp-3.1
Aug 26, 2026
Merged

chore(deps): migrate rmcp and rmcp-macros to 3.1.4 in lockstep#6995
forkwright merged 2 commits into
mainfrom
chore/rmcp-3.1

Conversation

@forkwright

@forkwright forkwright commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary

Migrates rmcp and rmcp-macros from =1.5.0 to =3.1.4 as one atomic change, superseding #6968 and #6973.

The two crates must move in exact lockstep: rmcp-macros generates code that calls rmcp runtime APIs directly, and a lock regeneration that moved one without the other broke every #[tool] site with a missing-function error naming neither crate (#6502). Bumping either alone reproduces that break, so the two single-crate dependabot PRs cannot land independently. Two majors is a real migration of the MCP SDK surface (MCP spec 2025-11-25 alignment in 2.0; SEP-2322 MRTR, SEP-2567 stateless draft serving, SEP-2549 cache hints, and DNS-rebinding Host validation in 3.0), not a version bump — every adaptation below was verified against the published rmcp-3.1.4 / rmcp-macros-3.1.4 crate sources, not guessed from memory.

The = exact pins are kept (now =3.1.4) in all three manifests (diaporeia, aletheia-memory-mcp deps + dev-deps, aletheia's optional client dep), and the lockstep WARNING on crates/diaporeia/Cargo.toml is preserved.

Changes

API adaptations (1.5.0 → 3.1.4):

  • rmcp::model::Content was removed; the unified content union is ContentBlock. All Content::text(...) sites (~40 in diaporeia/src/tools/mod.rs, 7 in aletheia-memory-mcp/src/tools.rs) now use ContentBlock::text(...).
  • RawResource/RawResourceTemplate are gone; Resource/ResourceTemplate are flat structs built via ::new(uri, name) + with_* builders (diaporeia/src/server.rs, resources/nous.rs, resources/config.rs and their tests).
  • ListResourcesResult/ListResourceTemplatesResult gained result_type (SEP-2322) and ttl_ms/cache_scope (SEP-2549) fields; the struct literals in server.rs now use the ::with_all_items(...) constructor.
  • ServerHandler::read_resource returns the new MRTR enum ReadResourceResponse; the ReadResourceResult is wrapped via the provided From impl.
  • Peer<RoleClient>::call_tool was removed; RunningService::call_tool is the high-level path and additionally drives SEP-2322 input_required rounds through the local client handler. Used in diaporeia/src/client.rs and the in-process test harness in tools/mod.rs.
  • StreamableHttpServerConfig::with_stateful_modewith_legacy_session_mode (SEP-2567: the 2026-07-28 draft is always stateless) in the five streamable-HTTP test setups.
  • Tool/ToolAnnotations are #[non_exhaustive]; the external_tools.rs test helper uses Tool::new_with_raw + ToolAnnotations::from_raw.
  • The streamable HTTP server validates the Host header by default (DNS-rebinding hardening, new in the 1.6–3.x line), and answers a missing/insufficient Accept header with 406 Not Acceptable where 1.5.0 answered 400. Transport tests that assert a request reaches the MCP protocol layer now send Host: localhost and expect the 406, so the rejection still originates from the layer they describe rather than the earlier host check.
  • scripts/generate-diaporeia-mcp-inventory.py accepts the ResourceTemplate::new constructor shape (Raw prefix optional), so the committed-inventory drift gate keeps seeing all six resource templates.
  • Lockfile delta is contained: rmcp/rmcp-macros 1.5.0 → 3.1.4, plus new transitive darling 0.24.1 for the macros crate; rmcp drops js-sys/wasm-bindgen and moves to base64 0.23.
  • DEPENDENCIES-AUDIT.md chrono-attribution line updated to rmcp v3.1.4.

Deliberately untouched: the [tool] tool names/descriptions (the committed MCP inventory is unchanged), the stdio transport wiring, and the auth middleware — all sit on APIs that did not change shape.

Test plan

Local (this box does not compile per fleet thermal law): cargo +1.94.0 fmt --all -- --check, _llm L3 extractor, scripts/run-gate-coverage.py (23/23 PASS, including the diaporeia MCP inventory generator self-tests), generate-diaporeia-mcp-inventory.py --check (no drift), resolver-only cargo update/cargo metadata/cargo fetch for the lockfile.

CI proves the #[tool] surface:

  • hybrid-gate / full-gate-build: cargo check --workspace --all-targets --features test-core compiles every #[tool_router]/#[tool_handler] expansion against rmcp 3.1.4 — the exact failure mode of rmcp is exact-pinned but rmcp-macros floats — a lock regeneration moved it to 1.8.0 and broke the build against rmcp 1.5.0 #6502 cannot pass this leg; clippy with -D warnings; cargo nextest run --workspace --features test-core runs:
    • diaporeia suites: public_api_scoped_access, public_api_resources, public_api_repomix, public_api_rate_limit, public_api_auth_resolution, public_api_transport (real streamable-HTTP round trips incl. RBAC, rate limits, resource reads), in-process session_create/session_message client-server tests in tools/mod.rs, and mcp_inventory_drift (both the --check drift gate and the generator self-tests).
    • aletheia-memory-mcp tests/integration.rs: in-process duplex client driving every read/write tool, including write-token gating via ToolRouter::remove_route.
    • aletheia external_tools MCP reversibility tests against the non-exhaustive Tool/ToolAnnotations constructors.
  • gate-coverage-scripts: the MCP inventory generator self-tests as a script step.

Acceptance criteria

  • rmcp and rmcp-macros both at exactly 3.1.4 in Cargo.lock; no other dependency version moved by the resolver (verified: only darling 0.24.1 added).
  • All call sites compile against the real 3.1.4 API (CI full-gate-build green).
  • The required gate context is green.

Blast zone

crates/diaporeia (MCP server + client), crates/aletheia-memory-mcp (stdio MCP server), crates/aletheia (external_tools.rs behind the mcp feature), Cargo.lock, scripts/generate-diaporeia-mcp-inventory.py, DEPENDENCIES-AUDIT.md. No other workspace member depends on rmcp (proskenion's separate lockfile has zero rmcp entries).

Cody Kickertz added 2 commits August 25, 2026 16:19
rmcp 1.5.0 -> 3.1.4 crosses two majors of MCP SDK churn. The macro crate
must move in exact lockstep with the runtime because its expansion calls
rmcp runtime APIs directly; a lock regeneration that moved one without
the other broke every #[tool] site in #6502, so this supersedes the two
single-crate dependabot PRs (#6968 for rmcp, #6973 for rmcp-macros) with
one atomic change. Exact pins are kept at =3.1.4 and the lockstep WARNING
on the diaporeia manifest is preserved.

API adaptations, verified against the published 3.1.4 crate sources:

- rmcp::model::Content was removed; the unified content union is now
  ContentBlock (ContentBlock::text across diaporeia and
  aletheia-memory-mcp tool implementations).
- RawResource/RawResourceTemplate are gone; Resource/ResourceTemplate
  are flat structs built via ::new + with_* builders.
- ListResourcesResult/ListResourceTemplatesResult gained SEP-2322
  resultType and SEP-2549 ttl/cache fields; struct literals replaced
  with the ::with_all_items constructor.
- ServerHandler::read_resource now returns the MRTR enum
  ReadResourceResponse; the complete result is wrapped via From.
- Peer<RoleClient>::call_tool was removed; RunningService::call_tool is
  the high-level path and also drives SEP-2322 input_required rounds
  through the local client handler.
- StreamableHttpServerConfig::with_stateful_mode was renamed to
  with_legacy_session_mode (SEP-2567: the 2026-07-28 draft version is
  always served statelessly).
- Tool/ToolAnnotations are #[non_exhaustive]; the external_tools test
  helper uses Tool::new_with_raw + ToolAnnotations::from_raw.
- The streamable HTTP server now validates the Host header by default
  (DNS-rebinding hardening); transport tests that assert a request
  reaches the MCP protocol layer send Host: localhost so their 400 still
  originates from the layer they describe.
- generate-diaporeia-mcp-inventory.py accepts the ResourceTemplate::new
  constructor shape so the committed-inventory drift gate keeps seeing
  all six resource templates.
rmcp 3.x's streamable HTTP server answers a missing/insufficient Accept
header with 406 Not Acceptable (spec-correct content negotiation) where
1.5.0 answered 400. The three transport tests assert that a request
clears the auth middleware and reaches the MCP protocol layer; a 406
from the service's Accept check proves exactly that, same as the 400
did. The Host header added in the parent commit is what lets the
request reach the Accept check past the new DNS-rebinding validation.
@sonarqubecloud

Copy link
Copy Markdown

@forkwright
forkwright merged commit fa63f73 into main Aug 26, 2026
46 checks passed
@forkwright
forkwright deleted the chore/rmcp-3.1 branch August 26, 2026 13:44
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