Skip to content

DRAFT: Rust: negotiate 2026-07-28, call the Messages API directly, and bump rmcp to 3.4 - #205

Open
a-akimov wants to merge 1 commit into
modelcontextprotocol:mainfrom
a-akimov:feat/rust-examples-upgrade
Open

a-akimov wants to merge 1 commit into
modelcontextprotocol:mainfrom
a-akimov:feat/rust-examples-upgrade

Conversation

@a-akimov

Copy link
Copy Markdown
Contributor

Motivation and Context

Three problems in the Rust examples, all found while reviewing #200.

1. The client could not reach protocol 2026-07-28. rmcp's serve only performs the legacy
initialize handshake, and ProtocolVersion::LATEST is still 2025-11-25 even in rmcp 3.4, so bumping
the SDK does not fix this on its own. Under 2025-11-25 a server cannot offer this era's features, so the
client could not call any tool with an array-rooted outputSchema — including get_alerts, which every
weather server in this repo declares that way. Against the Python server it failed at tools/list;
against the TypeScript server and the test mock it failed at tools/call.

2. The genai crate could not express three things the client needs. The first was raised by Copilot
on #200:

  • Signed thinking blocks. genai 0.4.2 keeps Anthropic's thinking / redacted_thinking blocks out of
    ChatResponse.content and does not retain the signature, so the follow-up request after a thinking turn
    could not echo them back as the API requires.
  • Tool errors. ToolResponse has no is_error field, so a failed tool call reached the model looking
    like a successful one.
  • A configurable endpoint. It reads no environment variable for the API base URL, which is why the Rust
    client was the one client excluded from the tool-loop smoke test added in Fix the tool-use loop in the Go, Rust, and Ruby clients and add a tool-loop smoke test #200.

I checked whether a genai bump would solve any of this. It does not: as of 0.6.5 the Anthropic adapter
still drops ThoughtSignature parts when sending, and ToolResponse still has only call_id and
content.

3. Both examples were several rmcp releases behind, 3.1.2 against 3.4.0, and each carried tracing and
tracing-subscriber dependencies that no source file references.

What changed

mcp-client-rust

  • Negotiates with serve_with_lifecycle and ClientLifecycleMode::Auto: one server/discover probe for
    2026-07-28, falling back to the 2025-11-25 initialize handshake. This is rmcp's equivalent of the
    auto mode the Python and TypeScript clients already use. The negotiated revision is printed on
    connect, as the Python client does.
  • Sends its own clientInfo via ClientConfig. It previously identified itself as rmcp 3.4.0.
  • Replaces genai with a direct reqwest call to the Messages API. There is no official Anthropic SDK
    for Rust, and calling the endpoint directly is what makes the other two fixes possible: an assistant
    turn is kept as raw content blocks and fed back byte-for-byte, signatures included, and a tool result
    carries a real is_error. ANTHROPIC_BASE_URL now overrides the endpoint, matching the official SDKs.
  • Bumps rmcp to 3.4, jsonschema to 0.56, reqwest to 0.13, tokio to 1.53, and drops the tracing,
    tracing-subscriber and server-feature dependencies, none of which were referenced. Dropping genai
    takes the lockfile from 312 crates to 256.
  • Prints the full error chain on a failed query ({:#}), so a wrapped cause is no longer hidden.

weather-server-rust

  • Bumps rmcp to 3.4, tokio to 1.53, reqwest to 0.13, and drops the unreferenced tracing and
    tracing-subscriber dependencies.
  • Moves off the ServerInfo alias, which rmcp 3.4 deprecates in favour of ServerConfig.

Tests

  • Adds the Rust client to the tool-loop smoke test, so all five clients are now covered.
  • Corrects a stale comment above those tests: the helper sends three queries, not one.

Note that rmcp 3.4's MSRV is 1.88, which is exactly the "Rust 1.88+" the READMEs already asked for. That
requirement is now justified rather than arbitrary.

How Has This Been Tested?

  • The Rust client passes the tool-loop smoke test, all 91 checks, including the two checks that assert
    thinking blocks come back with their signature and the one that requires is_error. It could not have
    passed any of those before this change.
  • It now reports Connected over protocol 2026-07-28 against the Python, TypeScript and Rust weather
    servers. The Python server previously rejected its tools/list outright.
  • ./tests/smoke-test.sh passes every step my machine has a toolchain for, which is all of them except
    Go and Ruby; those two were exercised in golang:1.25 and ruby:3.4 containers and are unaffected by
    this PR.
  • cargo build is clean, no warnings, for both examples in debug and release.

Breaking Changes

None for anyone running the examples. The client's command line, output and no-key behaviour are
unchanged. Worth flagging for reviewers: this swaps the Rust client's LLM library, so the diff in
src/main.rs is larger than a dependency bump would suggest.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

AI assistance

The investigation, code changes and this description were prepared with Claude Code and
reviewed by me.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The direct LLM protocol implementation and lifecycle negotiation warrant final human validation despite strong smoke-test coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Updates the Rust MCP examples for modern protocol negotiation and direct Anthropic Messages API integration.

Changes:

  • Adds MCP 2026-07-28 negotiation with legacy fallback.
  • Replaces genai with reqwest, preserving thinking blocks and tool errors.
  • Upgrades Rust dependencies and adds tool-loop smoke coverage.
File Description
mcp-client-rust/​src/​main.rs Implements negotiation and direct Messages API calls.
mcp-client-rust/​Cargo.toml Updates and simplifies dependencies.
mcp-client-rust/​Cargo.lock Records client dependency changes.
mcp-client-rust/​README.md Documents API access and negotiation.
weather-server-rust/​src/​main.rs Migrates to ServerConfig.
weather-server-rust/​Cargo.toml Upgrades and removes unused dependencies.
weather-server-rust/​Cargo.lock Records server dependency changes.
tests/​smoke-test.sh Adds Rust tool-loop testing.
tests/​README.md Documents complete client coverage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants