Skip to content

build(deps): adopt rmcp 3.7.0 - #413

Merged
plusky merged 1 commit into
mainfrom
build/rmcp-3.7.0
Nov 1, 2026
Merged

plusky merged 1 commit into
mainfrom
build/rmcp-3.7.0

Conversation

@plusky

@plusky plusky commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Moves rmcp and rmcp-macros to 3.7.0 as a matched pair and lifts rmcp 3.6's new 16 MiB stdio line cap (with_max_line_length(usize::MAX)), because otherwise it would drop frames that the policy-derived BoundedLines bound admits. New tests pin rmcp 3.6+'s refusal shapes, and DESIGN.md's rmcp notes and stamps are refreshed. Verified with the full workspace gates, cargo deny check, the local stamp-drift step and an OCR pass; supersedes Dependabot #409.

Two minor releases, read as one src diff of the vendored crates: 3.6.0
carries every server-side change; 3.7.0 touches only the OAuth client
(the GHSA-5p52-q7pq-9fq2 SSRF fix, #1385, #1302 — the `auth` feature this
crate never enables) and the reqwest client's 401/403 handling (#1341,
the test client only). rmcp-macros 3.7.0 is a version bump: its src is
byte-identical to 3.5.1.

What matters, and why each bugwarden change was made:

DEFAULT_MAX_LINE_LENGTH of 16 MiB and DISCARDS a longer one, logging
ERROR and reading on. That is the skip-and-resume DESIGN.md rejects for
stdio (the request id is inside the unparsed frame, rmcp clients set no
timeout, so a peer waits forever), and it sits below this build's own
policy-derived cap, which clamps to 64 MiB. Measured: under a 16 MiB
attachment cap the 3.5.1 build served a 17 MiB tools/call over stdio and
the bare 3.7.0 transport dropped it unanswered, logged the ERROR, and
read on. DiscoverAnswering::framed now builds the transport with
with_max_line_length(usize::MAX), rmcp's documented off switch, so
BoundedLines stays the one bound and closes as before. Two tests pin
it: a_frame_of_exactly_this_builds_cap_is_served_past_rmcps_line_bound
feeds a frame of exactly the cap a 16 MiB policy derives (~22 MiB)
through the real framed constructor and requires it to reach rmcp, so
any rmcp bound below the derived cap fails it (without the override it
reports `None`); stdio_a_frame_over_rmcps_line_bound_is_served_when_the
_policy_admits_it drives a 17 MiB tools/call through the shipped binary
under that policy and requires the reply, which fails the moment main
frames stdin through anything but `framed`. The 3.5.1 "unbounded Vec"
wording in stdio.rs, main.rs, server.rs, binary_shutdown.rs and
DESIGN.md is rewritten to say what each rmcp did, and DESIGN.md's stdio
serving line now quotes the real call and names the tuple form as the
trap. with_max_line_length is the only 3.6-only API the crate's
non-test code relies on (the test also reads DEFAULT_MAX_LINE_LENGTH),
so the manifest requirement moves from "3.5" to "3.6", not "3.7":
nothing 3.7 added over 3.6 is compiled in, and DESIGN.md quotes and
justifies the new requirement.

`Bad Request: Session ID is required` where 3.5.1 answered 422
`Unexpected message, expect initialize request`, and the stateless
branch now refuses a posted JSON-RPC response or error with 400/-32600
where 3.5.1 took it with a 202. Both are the transport's own answers
before any handler, so unrecorded either way. No test pinned the old
shapes; two raw-POST wiremock tests now pin the new ones
(a_session_less_non_initialize_post_is_refused_400_before_any_handler,
a_posted_json_rpc_response_on_the_stateless_path_is_refused_400), both
failing on the 3.5.1 lock, and DESIGN.md's mcp-session-id trap records
them — including that over http the #1283/#1346 shapes below never
reach either branch, because expect_json refuses them 415 with the
`unrecognized JSON-RPC message` text that any non-JSON-RPC JSON object
now draws.

beside `result`/`error`, both of those, or `method` with a null id is
refused -32600 in-band with no id, and an integral float id (1.0) is
read as that integer. 3.5.1 read a request with a float or null id as
a NOTIFICATION, which before initialize ended the stdio process through
the #261 path and in-session was dropped; 3.7.0 refuses it in-band and
keeps waiting. Two binary tests pin the stdio shapes, both failing on
the 3.5.1 lock (stdio_a_pre_initialize_float_id_request_is_refused_in
_band_and_the_session_survives; stdio_an_in_session_frame_with_method
_and_result_is_refused_not_served), and DESIGN.md's stdio trap records
them.

stateless path reads get_tool off the service built for that request,
the session path builds one per lookup, and the factory now runs before
the SEP-2243 check. For this build the factory is server.clone(), side-
effect free, and get_tool still takes no RequestContext, so the #116
record stays closed as a per-deployment, validate-vs-skip oracle; the
DESIGN.md text that described the cache is rewritten.

the serve loop's drain ends. The handler future is not dropped, this
build's handlers read no ct, and the record is written after dispatch,
so the #319 gap is unchanged; DESIGN.md says so beside it.

client-side validator now rejects the key on the root and off such a
chain. bugwarden authors none; the tripwire already bans the key at any
depth and any value type, so only its rationale and the comment naming
rmcp's functions move (reject_nested_annotations is gone).

Not relevant, with evidence: #1326 refuses server-to-client requests at
2026-07-28 (this server issues none; the only send_request sites are
test clients); #1304 stdio_pipes and the new Linux libc dependency
(this build wraps tokio::io::stdin itself and never calls rmcp's
stdio()); #1323 releases the session-map lock before awaiting a session
(liveness only, same API); #1329/#1314 feature gating; #1344 the rmcp
client's cancel-on-drop, #1366 pre-init ping answering, #1367 same-
origin 307/308 redirects, #1361 re-initialization errors, #1352/#1385/
serves a redirect, and the bearer-gate tests use raw reqwest).

Re-verified on 3.7.0 sources: parse_allowed_authority (I9),
is_legacy_request, strip_result_type_for_legacy_peer,
fill_missing_cache_hints, DiscoverResult, get_tool's signature,
handler/server.rs, router/tool.rs, model/meta.rs and model/serde_impl.rs
are byte-identical to 3.5.1; LATEST is still 2026-07-28,
LATEST_WITH_INITIALIZE 2025-11-25, KNOWN_VERSIONS the same five;
StreamableHttpServerConfig still has the ten public fields the DESIGN.md
table lists plus the private origin flag; serve_server_with_ct_inner's
pre-init paths are unchanged and the serve loop's drain differs only by
the #1333 cancel; no Span::record; the one new tracing::error! on a
per-request path is #1049's, carries only a numeric field, and is
unreachable with the bound off; no new bare % field fed from a client
(%client_requested and %id stay as the tracing-caps probe expects); the
mutants exclude_re premise holds (the single ExpectedInitializeRequest
site passes Some at service/server.rs:667, UnexpectedInitializeResponse
only on the handler-result path, Cancelled only under a token
ServiceExt::serve makes itself). Every line citation was re-read at
both ends, not shifted: service.rs -14, service/server.rs -15 with the
pre-init loop now :544-672, model.rs +163; the negotiate re-run
citation (:658) and set_peer_info (:323) were stale already and now name
their lines (:692, :322). The 3.5.x stamps in DESIGN.md, ci.yml and the
crate comments move to 3.7.0.

Served bytes, dumped from a 3.5.1 build of origin/main and this one
over stdio (initialize at each served revision and the fallbacks,
server/discover in five _meta shapes, handshake-free tools/list and
tools/call, the bare pre-initialize refusal, an over-cap frame at the
default policy) and over http (initialize, in-session and session-less
POSTs, header-only and per-request 2026-07-28, GET and DELETE without a
session): content-identical except the #1049, #1377 and #1283/#1346
shapes explained above, each of which this message names.

Cargo.lock is Dependabot's: rmcp and rmcp-macros 3.7.0, the matched
pair, tokio 1.54.1, schemars 1.2.3, serde_json 1.0.154, sha2 0.11.1,
plus libc as rmcp's new Linux dependency.

Supersedes Dependabot #409.
@plusky
plusky merged commit 2996f0d into main Nov 1, 2026
19 checks passed
@plusky
plusky deleted the build/rmcp-3.7.0 branch November 1, 2026 23:31
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