Skip to content

1.0.81-1 sends legacy initialize after successful modern server/discover, causing -32022 #4525

Description

@dmbutko

Describe the bug

Copilot CLI 1.0.81-1 fails MCP initialization against a stdio server using the Python MCP SDK 2.0.0 dual-era runner.

The CLI opens the connection with a modern server/discover probe whose _meta declares io.modelcontextprotocol/protocolVersion: 2026-07-28. The server replies with a valid successful DiscoverResult (resultType: "complete", supportedVersions: ["2026-07-28"]). The CLI then sends a legacy initialize requesting 2025-11-25 on that same connection, and the server rejects it with -32022.

Per the stdio backward-compatibility rules, a successful DiscoverResult identifies a modern server; legacy initialize fallback is only for a non-modern error or timeout. The CLI declares two protocol eras on one connection.

Related to #4370, but exercises the other probe outcome: #4370 concerns fallback after a non-modern error; this occurs after a successful modern DiscoverResult.

Affected version

1.0.81-1

Verified working on 1.0.80, 1.0.80-1 and 1.0.81-0 with the same server and config. 1.0.81-0 (works) and 1.0.81-1 (fails) were both run via node index.js from the same cache layout, so the difference is the version, not the invocation path. 1.0.81-1 also fails when run as the native binary.

Steps to reproduce the behavior

  1. Configure a stdio MCP server that implements server/discover. Reproduced with scrapling 0.4.14 (scrapling mcp), resolved dependency mcp==2.0.0.
  2. Run Copilot CLI 1.0.81-1.
  3. The server's tools are missing. The CLI log shows:
    failed to initialize MCP client: JSON-RPC error: -32022: connection is serving the 2026-07-28 protocol; the initialize handshake is not accepted({"supported":["2026-07-28"],"requested":"2025-11-25"})

Expected behavior

After a successful DiscoverResult, the CLI should select a mutually supported advertised version and continue in that era without sending legacy initialize on that connection. Legacy initialize fallback should occur only when the probe returns a non-modern error or times out.

Additional context

Wire capture on 1.0.81-1 (abridged — capabilities and instructions elided, marked "..."):

// 1. client -> server
{"jsonrpc":"2.0","id":0,"method":"server/discover","params":{"_meta":{
  "io.modelcontextprotocol/protocolVersion":"2026-07-28",
  "io.modelcontextprotocol/clientInfo":{"name":"copilot-cli","version":"0.0.0"},
  "io.modelcontextprotocol/clientCapabilities":"..."}}}

// 2. server -> client  (valid modern discovery success)
{"jsonrpc":"2.0","id":0,"result":{"resultType":"complete",
  "supportedVersions":["2026-07-28"],"capabilities":"...","instructions":"..."}}

// 3. client -> server  (legacy handshake on a modern-locked connection)
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25",
  "capabilities":"...","clientInfo":{"name":"copilot-cli","version":"0.0.0"}}}

// 4. server -> client  (verbatim)
{"jsonrpc":"2.0","id":1,"error":{"code":-32022,
 "message":"connection is serving the 2026-07-28 protocol; the initialize handshake is not accepted",
 "data":{"supported":["2026-07-28"],"requested":"2025-11-25"}}}

Server side, the Python SDK locks the connection's era from the first message: a non-initialize opening request carrying the reserved io.modelcontextprotocol/protocolVersion key selects the modern runner, which then rejects initialize (mcp/server/runner.py).

Environment: Linux x64, Node v24.15.0, server scrapling 0.4.14 on mcp 2.0.0.

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

    area:mcpMCP server configuration, discovery, connectivity, OAuth, policy, and registry

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions