Skip to content

[FEATURE] Adopt rmcp 3.2.0 for MCP initialize/session negotiation - #90

Merged
puretensor merged 1 commit into
mainfrom
grok/review/rmcp-3-2-0
Sep 6, 2026
Merged

puretensor merged 1 commit into
mainfrom
grok/review/rmcp-3-2-0

Conversation

@puretensor

Copy link
Copy Markdown
Owner
  • Seat: grok-4.6 / xhigh (adversarial review wave 4, 2026-09-06)

  • Category: [FEATURE]

  • Problem / Opportunity: pTask's MCP surface is rmcp::transport::streamable_http_server::StreamableHttpService mounted at /mcp (plus stdio via pt mcp). The repo pins rmcp 3.1.4. rmcp 3.2.0 (crates.io, published 2026-08-31) fixes initialize negotiation on that exact tower path so a handshake cannot be routed as a modern stateless session.

  • Evidence: Fetched this session.

crates.io JSON (https://crates.io/api/v1/crates/rmcp): "default_version":"3.2.0", "max_stable_version":"3.2.0", version 3.2.0 "created_at":"2026-08-31T23:16:49.374902Z", "yanked":false. 3.1.4 remains listed as the previous stable.

Changelog (https://raw.githubusercontent.com/modelcontextprotocol/rust-sdk/main/crates/rmcp/CHANGELOG.md):

## [3.2.0](...) - 2026-08-31
### Added
- *(auth)* coordinate OAuth refreshes through credential stores (#1232)
- add request-state key rotation (#1128)
### Fixed
- keep initialize on legacy protocol versions (#1228)
- *(transport)* fall back after sessionless HTTP discover rejections (#1211)
- allow concurrent streamable http requests (#1186)

Server-side contract, from modelcontextprotocol/rust-sdk#1228 (merged 2026-08-31):

The 2026-07-28 versioning spec is very clear about how a server that supports both eras should behave.
Two parts of the implementation broke that contract:

  1. negotiate_protocol_version returned the client's requested version whenever supported_protocol_versions() included it. That also applied to 2026-07-28 and later, even though those versions do not use a handshake.
  2. In the Streamable HTTP tower service, is_legacy_request used the protocolVersion from the initialize body to decide between session and stateless routing. As a result, a 2026-07-28 handshake took the stateless path and did not create a session.
    The fix makes these two parts consistent. Any initialize request is treated as a legacy client, regardless of the version it names. It always uses the session path and negotiates a version that still supports the handshake.

pTask uses that tower service:

crates/ptask-server/src/lib.rs
    let mcp_service = StreamableHttpService::new(
        move || Ok(mcp::PtaskMcp::new(mcp_db.clone(), "hal".into())),
        LocalSessionManager::default().into(),
        StreamableHttpServerConfig::default().with_allowed_hosts(Vec::<String>::new()),
    );

Not claimed: #1186 concurrent HTTP. That PR is client-transport (StreamableHttpClientTransportConfig::max_concurrent_requests); quote from the PR: "The shared worker's control queue is opt-in; server scheduling is unchanged." pTask is a server. OAuth (#1232) and request-state (#1128) are unused (those features are not enabled).

  • Change: Workspace pin rmcp = "3.1.4" → "3.2.0". cargo update -p rmcp --precise 3.2.0 moved rmcp and rmcp-macros 3.1.4 → 3.2.0. pTask 3.24.1 → 3.25.0. No pTask source changes; the public MCP tool surface is unchanged.

  • Verification:

$ cargo update -p rmcp --precise 3.2.0
    Updating rmcp v3.1.4 -> v3.2.0
    Updating rmcp-macros v3.1.4 -> v3.2.0

$ cargo test --workspace --locked
# ptask-server 59 passed; ptask-distill 26 + 7; ptask-notify 3; ptask-tui 2; remaining crates ok
# exit 0

$ cargo clippy --workspace --all-targets --locked --offline -- -D warnings
    Checking rmcp v3.2.0
    Checking ptask-server v3.25.0
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 10.02s
# exit 0

$ bash scripts/ci-version-check.sh
version-check: workspace, lockfile, internal requirements, and manpage agree on 3.25.0

$ bash scripts/generated-artifacts.sh --check
generated-artifacts: checked-in files match the CLI

Lockfile delta is 22 lines (rmcp + rmcp-macros + workspace package stamps).

  • Risk & rollback: rmcp 3.2.0 documents no public API break for 3.1.4 → 3.2.0 (#1228: "There is no public API change"). HAL sessions that send initialize keep a session instead of the 3.1.4 stateless mis-route. Revert is a clean single-commit revert.

rmcp 3.2.0 treats any initialize as a legacy handshake and keeps it on
the session path (modelcontextprotocol/rust-sdk#1228). pTask's /mcp
mount is StreamableHttpService; 3.1.4 could accept a 2026-07-28
initialize and then handle the session with modern-lifecycle semantics.
@puretensor
puretensor force-pushed the grok/review/rmcp-3-2-0 branch from c9ddce4 to b0519f8 Compare September 6, 2026 08:17
@puretensor
puretensor merged commit 688df21 into main Sep 6, 2026
@puretensor
puretensor deleted the grok/review/rmcp-3-2-0 branch September 6, 2026 08:17
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