Which version line?
v2 - current (@modelcontextprotocol/inspector@latest)
Which client?
Web
Inspector version
2.0.0; reproduced against the current v2 development branch.
Node version
v26.7.0
Operating system (and browser, for the web client)
macOS 27.0; reproduced at hook/test level, so no browser-specific behavior is required.
Transport
Not applicable / never connected
MCP server under inspection
No MCP server is required. The issue is in the web client's /api/servers/events subscription that keeps the saved server list in sync after mcp.json changes.
Steps to reproduce
- Start from the current v2 development branch.
- Mount
useServers with a fetch implementation whose /api/servers response reads from a test mcp.json.
- Have
/api/servers/events return a readable stream that emits a valid SSE change frame delimited with CRLF line endings: event: change\r\n\r\n.
- Update
mcp.json before releasing that frame.
- Observe the hook state after the frame is consumed.
Expected behavior
The hook should treat the CRLF-delimited SSE frame as a change notification, call the background refresh path, and update the displayed server list from mcp.json.
SSE permits CRLF line endings, and the hook is already acting as a small custom SSE parser because EventSource cannot send the x-mcp-remote-auth header.
Actual behavior
The hook only searches for \n\n as the frame separator. A CRLF-delimited frame stays buffered, isSseDataFrame() is never reached, and no background refresh is triggered. The server list stays at its previous value until the user manually refreshes or another LF-delimited event arrives.
Logs, errors, or screenshots
Focused regression before the prototype fix:
FAIL clients/web/src/test/core/react/useServers.test.tsx > useServers > parses CRLF-delimited SSE frames as change notifications
AssertionError: expected [ 'seed' ] to deeply equal [ 'aftercrlf' ]
Verification after the prototype fix:
npm run test -- src/test/core/react/useServers.test.tsx
Test Files 1 passed (1)
Tests 33 passed (33)
npm run validate:web
Test Files 263 passed (263)
Tests 3811 passed (3811)
Already prototyped a fix?
Prototype prompt:
Update the web client's useServers SSE reader so `/api/servers/events` treats both LF and CRLF blank lines as SSE frame separators. Keep comment-only priming frames ignored, keep the existing one-background-refresh-per-decode-chunk behavior, and add a hook unit test with a controlled readable stream that emits `event: change\r\n\r\n` after an external `mcp.json` write.
The prototype changes core/react/useServers.ts to find SSE frame separators with a CRLF-aware blank-line matcher and split frame lines with CRLF/LF handling. It adds a focused useServers regression test for a CRLF-delimited event: change frame.
Before you submit
Which version line?
v2 - current (
@modelcontextprotocol/inspector@latest)Which client?
Web
Inspector version
2.0.0; reproduced against the current v2 development branch.
Node version
v26.7.0
Operating system (and browser, for the web client)
macOS 27.0; reproduced at hook/test level, so no browser-specific behavior is required.
Transport
Not applicable / never connected
MCP server under inspection
No MCP server is required. The issue is in the web client's
/api/servers/eventssubscription that keeps the saved server list in sync aftermcp.jsonchanges.Steps to reproduce
useServerswith a fetch implementation whose/api/serversresponse reads from a testmcp.json./api/servers/eventsreturn a readable stream that emits a valid SSE change frame delimited with CRLF line endings:event: change\r\n\r\n.mcp.jsonbefore releasing that frame.Expected behavior
The hook should treat the CRLF-delimited SSE frame as a change notification, call the background refresh path, and update the displayed server list from
mcp.json.SSE permits CRLF line endings, and the hook is already acting as a small custom SSE parser because
EventSourcecannot send thex-mcp-remote-authheader.Actual behavior
The hook only searches for
\n\nas the frame separator. A CRLF-delimited frame stays buffered,isSseDataFrame()is never reached, and no background refresh is triggered. The server list stays at its previous value until the user manually refreshes or another LF-delimited event arrives.Logs, errors, or screenshots
Focused regression before the prototype fix:
Verification after the prototype fix:
Already prototyped a fix?
Prototype prompt:
The prototype changes
core/react/useServers.tsto find SSE frame separators with a CRLF-aware blank-line matcher and split frame lines with CRLF/LF handling. It adds a focuseduseServersregression test for a CRLF-delimitedevent: changeframe.Before you submit