Skip to content

support MCP 2026-07-28 stateless protocol with backward compatibility #314

Description

@foundev

Summary

MCP revision 2026-07-28
is live and makes the protocol stateless: protocol-level sessions and the initialize handshake
are gone. Anvil implements its own MCP client and currently speaks 2025-11-25, so it needs an
explicit compatibility migration.

This is the Anvil counterpart to BrokkAi/mjolnir#521. Mjolnir is moving its MCP servers forward;
Anvil must be able to connect to those servers without breaking configured servers that still use
older revisions.

Where we are today

src/mcp.rs:19 hard-codes:

const PROTOCOL_VERSION: &str = "2025-11-25";

All three client transports use the old lifecycle:

  • stdio sends initialize, then notifications/initialized, then tools/list
    (src/mcp.rs:666-689)
  • Streamable HTTP does the same and stores Mcp-Session-Id
    (src/mcp.rs:735-779)
  • legacy HTTP+SSE opens a GET event stream, waits for an endpoint event, then performs the same
    handshake (src/mcp.rs:785-850)

The HTTP request path sends and captures Mcp-Session-Id (src/mcp.rs:1351-1397). A 404 is
treated as an expired session and triggers a fresh initialize plus one retry
(src/mcp.rs:976-1010, src/mcp.rs:1478-1524).

Anvil does not use rmcp; this is a migration of our custom client implementation, not a
dependency bump.

What the new revision changes for us

  1. Sessions are gone. Mcp-Session-Id is removed from Streamable HTTP. The
    HttpSessionNotFound error path, stored HTTP session ID, and reinitialize-on-404 workaround
    become legacy-only behavior.
  2. No initialize/notifications/initialized handshake. Each request carries protocol
    version and client capabilities in _meta
    (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities).
  3. server/discover is mandatory. Use it to discover supported versions, capabilities, and
    server identity before selecting the request format.
  4. Streamable HTTP POSTs require Mcp-Method and Mcp-Name. Our request and notification
    helpers need to set them consistently.
  5. All results carry resultType (complete or input_required). Multi-round-trip requests
    replace server-initiated requests.
  6. List/read results are cacheable. Parse ttlMs and cacheScope on tools/list and decide
    whether/how Anvil should cache or refresh tool definitions.
  7. GET and resources/subscribe are replaced by subscriptions/listen. SSE resumability is
    removed; interrupted requests must be re-issued. The configured legacy sse transport remains
    useful only for older servers.
  8. Removed methods and renumbered errors. ping, logging/setLevel, and
    notifications/roots/list_changed are removed; protocol errors now include the new header,
    capability, and version codes.

Main risk: mixed-version servers

Anvil connects to both its bundled Bifrost server and arbitrary user-configured MCP servers. They
will not all adopt 2026-07-28 at once. The client needs version-aware behavior rather than a
hard cutover:

  • discover and use 2026-07-28 where supported
  • preserve the current initialize/session flow for older servers
  • produce a clear error when no mutually supported revision exists
  • keep stdio, Streamable HTTP, and legacy SSE compatibility explicit and tested

The bundled Bifrost version and its supported MCP revisions should be checked as part of this work.

Work

  • Add server/discover and version selection for MCP connections.
  • Implement the 2026-07-28 per-request _meta fields and required HTTP headers.
  • Make HTTP session storage, Mcp-Session-Id, and 404 reinitialization legacy-version-only.
  • Update stdio and Streamable HTTP setup so 2026-07-28 does not send the removed handshake.
  • Treat the configured SSE transport as legacy and document/version-gate it.
  • Parse and validate resultType; support input_required/multi-round-trip behavior.
  • Parse cache metadata on tools/list and define refresh semantics.
  • Audit cancellation and reconnect behavior now that a broken stream loses the in-flight
    request.
  • Confirm compatibility with bundled Bifrost, Mjolnir's upgraded servers, and at least one
    older MCP server.
  • Add transport/version matrix tests covering discovery, headers, _meta, fallback, and
    unsupported-version errors.
  • Run cargo test and cargo clippy --all-targets -- -D warnings.

Notes

The exact wire details should be verified against the final 2026-07-28 specification during
implementation. This issue intentionally describes Anvil's current client surface and the required
compatibility outcome; it does not assume an MCP SDK migration.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions