You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MCP client sends legacy initialize after successful 2026-07-28 server/discover #4888
Copilot CLI sends a successful MCP 2026-07-28 discovery request and then sends a legacy 2025-11-25initialize request on the same stdio connection. A dual-era MCP SDK server correctly locks the connection to the modern protocol after server/discover, so it rejects the subsequent handshake with -32022.
This prevents Basic Memory from connecting even though the server successfully answers Copilot's discovery request.
The server correctly rejects that mixed-era request:
{"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"}}}
Copilot logs the server as failed to initialize.
Expected behavior
After a successful server/discover, Copilot should adopt the returned modern protocol and must not send initialize on that connection. If Copilot decides discovery failed or is unusable, it should close that connection and open a fresh connection before attempting the legacy handshake.
Additional verification
A fresh MCP 1.x client successfully negotiates 2025-11-25 with the same Basic Memory server.
Forcing the server into handshake-only mode makes Copilot connect and call Basic Memory tools successfully.
Disabling Basic Memory's initialization sync does not fix the issue; server/discover still succeeds and Copilot still sends initialize afterward.
Windows / 1.0.85 — the failure-path variant of this, and why it compounds
To be precise up front: I have not reproduced the exact case in the report (successful server/discover followed by initialize on the same connection). What I see is the other branch your "Expected behavior" section calls out — discovery that Copilot decides is unusable or times out, followed by a legacy handshake:
[WARNING] [rust:mcp::client] server/discover returned an unusable JSON response; retrying with legacy initialize
[WARNING] [rust:mcp::client] server/discover timed out; retrying with legacy initialize
Both variants appear on Windows with CLI 1.0.85 across a mixed set of 15 stdio and http MCP servers. They are not rare: I counted 26 of these warnings in a single 60-second window.
Adding this mainly because of how it compounds with #4892. That issue causes the whole MCP graph to be force-reloaded twice an hour by a no-op managed-settings refresh. Because each reload re-runs discovery, and each failed discovery costs a second handshake, the observed rate lands at 6 Service initialized as client events per logical server per hour — 90/hour across 15 servers, 1498 over 15 idle hours. Roughly half of that volume is the retry described here.
So the two issues multiply: #4892 sets the reload frequency, and this one sets the per-reload handshake cost.
One question that might matter for the fix: when the fallback fires, does the client open a fresh connection before sending legacy initialize, or reuse the existing one? Your report shows reuse on the success path. If the failure path also reuses, then strict dual-era servers would reject the retry for the same -32022 reason, and the cost of a discovery timeout would be a fully failed server rather than just a slow one.
Here's another data point for the server/discover timeout variant, triggered by a stdio bridge that starts slowly. Environment: GitHub Copilot app 1.1.30 (CLI runtime 1.0.99-2) on macOS 27.0.1 arm64.
Error shown in the app. The bridge is fastmcp-remote 4.1.0, which bundles mcp 2.3.0.
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"}); last stderr: 'stdio' Server stderr (last 10 lines): … 🎉 Update available: 4.1.1 … INFO Starting MCP server 'fastmcp-remote' with transport 'stdio'
What happens:
The client writes server/discover while uvx is still resolving and starting the bridge. On this machine, uvx fastmcp-remote usually takes 5–7 s to start, and up to 28 s on a cold cache.
The client times out (server/discover timed out; retrying with legacy initialize) and writes a legacy initialize (2025-11-25) to the same stdin.
When the bridge finally starts, it reads the buffered server/discover first, which commits the connection to 2026-07-28. It then rejects the queued initialize with -32022.
On stdio, a request that has been written is never lost, only delayed. So falling back to a legacy initialize on the same pipe after a discover timeout can't succeed against a modern server. Possible fixes:
Keep waiting for the discover response on stdio.
Restart the process before the legacy fallback.
Accept a late discover result instead of failing.
Side note: the server/discover timed out; retrying with legacy initialize warning doesn't include the server name. When many servers start at once, there's no way to tell which one it's about.
Possible workaround: install the bridge with uv tool install fastmcp-remote and point command at the installed binary. That cuts startup to about 1 s, but I haven't confirmed that it avoids the error in the app.
Activity
danswett commentedon Sep 21, 2026
Windows / 1.0.85 — the failure-path variant of this, and why it compounds
To be precise up front: I have not reproduced the exact case in the report (successful
server/discoverfollowed byinitializeon the same connection). What I see is the other branch your "Expected behavior" section calls out — discovery that Copilot decides is unusable or times out, followed by a legacy handshake:Both variants appear on Windows with CLI 1.0.85 across a mixed set of 15 stdio and http MCP servers. They are not rare: I counted 26 of these warnings in a single 60-second window.
Adding this mainly because of how it compounds with #4892. That issue causes the whole MCP graph to be force-reloaded twice an hour by a no-op managed-settings refresh. Because each reload re-runs discovery, and each failed discovery costs a second handshake, the observed rate lands at 6
Service initialized as clientevents per logical server per hour — 90/hour across 15 servers, 1498 over 15 idle hours. Roughly half of that volume is the retry described here.So the two issues multiply: #4892 sets the reload frequency, and this one sets the per-reload handshake cost.
One question that might matter for the fix: when the fallback fires, does the client open a fresh connection before sending legacy
initialize, or reuse the existing one? Your report shows reuse on the success path. If the failure path also reuses, then strict dual-era servers would reject the retry for the same-32022reason, and the cost of a discovery timeout would be a fully failed server rather than just a slow one.joselcaguilar commentedon Oct 19, 2026
Here's another data point for the
server/discovertimeout variant, triggered by a stdio bridge that starts slowly. Environment: GitHub Copilot app 1.1.30 (CLI runtime 1.0.99-2) on macOS 27.0.1 arm64.Config (redacted):
Error shown in the app. The bridge is fastmcp-remote 4.1.0, which bundles
mcp2.3.0.What happens:
server/discoverwhileuvxis still resolving and starting the bridge. On this machine,uvx fastmcp-remoteusually takes 5–7 s to start, and up to 28 s on a cold cache.server/discover timed out; retrying with legacy initialize) and writes a legacyinitialize(2025-11-25) to the same stdin.server/discoverfirst, which commits the connection to2026-07-28. It then rejects the queuedinitializewith-32022.On stdio, a request that has been written is never lost, only delayed. So falling back to a legacy
initializeon the same pipe after a discover timeout can't succeed against a modern server. Possible fixes:Side note: the
server/discover timed out; retrying with legacy initializewarning doesn't include the server name. When many servers start at once, there's no way to tell which one it's about.Possible workaround: install the bridge with
uv tool install fastmcp-remoteand pointcommandat the installed binary. That cuts startup to about 1 s, but I haven't confirmed that it avoids the error in the app.