Skip to content

Server accepts duplicate initialize after initialization, while Peer<RoleServer>::peer_info() remains unchanged #851

@cclabadmin

Description

@cclabadmin

Describe the bug

After a normal initialization flow, the server accepts a second initialize request and returns a normal initialize result. Repeated initialize requests with changed capabilities, changed clientInfo, and an older protocolVersion were also accepted, and the server continued responding to later requests.

In my tests, the later initialize succeeded but the stored peer state did not change: Peer<RoleServer>::peer_info() continued to reflect the original initialization parameters. This makes the post-initialization semantics unclear, because the client receives a successful initialize result but the server continues operating on the original peer info.

This makes the duplicate-initialize semantics unclear, because the request succeeds but the stored peer_info() appears to remain unchanged.

To Reproduce

Steps to reproduce the behavior:

  1. Start a Rust SDK MCP server.
  2. Complete a normal initialize followed by notifications/initialized.
  3. Send a second initialize request on the same stdio connection or HTTP session.
  4. Repeat with changed capabilities, changed clientInfo, or an older protocolVersion.
  5. Send ping after the duplicate initialization.

Expected behavior

If duplicate initialization is not intentional, the server should reject the second initialize with a JSON-RPC error such as -32600 Invalid Request.

If duplicate initialization is intentional, the behavior should be documented explicitly, including whether a later successful initialize is intended to be a no-op with respect to Peer<RoleServer>::peer_info().

Logs

Observed with:

  • Stable release rmcp-v1.7.0 (3529c3675ff64db805bd947ca6ece6090809e43d)
  • main snapshot cc66e3091e1584f48ee1e0058a2a1201a1d35c81 from 2026-05-15

The same transport-level behavior was reproduced on stdio and stateful HTTP:

  • Second initialize accepted
  • Duplicate initialize with an older protocolVersion accepted
  • Fve repeated duplicate initialize requests accepted
  • Later ping succeeded.

Code:

  • The initial client initialization parameters are stored as peer info when the server creates the Peer<RoleServer>.
  • Peer::peer_info() reads that value from a OnceCell.
  • Peer::set_peer_info() warns if peer info is already initialized and does not replace it.
  • Server-side capability helpers such as sampling/elicitation checks read from peer_info().

Session state after duplicate initialization

I compared the stored peer_info() before and after a duplicate initialize on the same running session, focusing on the stored client info, client capabilities, and protocol version.

Description stdio stateful HTTP
Same parameters No change No change
Changed clientInfo and capabilities No change observed No change observed
Older protocolVersion (2024-11-05) No change observed No change observed

In all scenarios, the server accepted the duplicate initialize and returned an initialize result, but Peer<RoleServer>::peer_info() continued to reflect the original initialization state.

The confusing part is that a client receives a successful response to a post-initialization initialize, but the server continues to use the original peer info for capability checks and client identity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is not working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions