fix(native-server): replace getMcpServer() singleton with factory to allow simultaneous Chrome extension + external MCP client connections#301
Open
PyEL666 wants to merge 1 commit intohangwin:masterfrom
Conversation
…ction Previously getMcpServer() cached and reused a single Server instance. The @modelcontextprotocol/sdk Protocol.connect() method throws "Already connected to a transport" when called on an already-connected Server, so only one transport could be active at a time. This caused a race condition: whichever caller (Chrome extension via /sse or an external MCP client via /mcp) connected first would lock out the other, making it impossible to use both the Chrome extension UI and external tools like mcporter or Claude Desktop simultaneously. Fix: convert getMcpServer() from a cached singleton to a pure factory function that creates a fresh Server instance per call. Tool handlers registered by setupTools() delegate all Chrome API calls through the shared nativeMessagingHostInstance module singleton, so each independent Server instance still reaches the Chrome extension correctly. Also removes the now-unused `export let mcpServer` variable.
4 tasks
|
It works |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
It is currently impossible to use the Chrome extension UI and an external MCP client (e.g. mcporter, Claude Desktop) at the same time.
When the Chrome extension connects to
/sse, the bridge calls:When an external MCP client subsequently connects to
/mcp, the bridge calls:The
@modelcontextprotocol/sdkProtocol.connect()has a hard guard:Because
getMcpServer()returns the same cached instance every time, whichever transport connected first permanently locks out all subsequent connections. The external client receivesFailed to connect to MCP server.This produces an intermittent first-success / always-fail-after pattern:
Root Cause
File:
app/native-server/src/mcp/mcp-server.tsserver/index.tscallsgetMcpServer().connect(transport)in both the/sseroute and the/mcproute. Since they receive the sameServerobject, the secondconnect()always throws.Fix
Convert
getMcpServer()from a singleton accessor to a factory function that creates a freshServerinstance on every call.Why this is safe
setupTools()registers handlers that forward every Chrome API call throughnativeMessagingHostInstance— a separate module-level singleton innative-messaging-host.ts. Each independentServerobject shares the same underlying Native Messaging channel to the Chrome extension, so all tool calls still reach Chrome correctly.Changed Files
app/native-server/src/mcp/mcp-server.tsmcpServervariable; makegetMcpServer()a pure factoryTesting
/sse)/mcpRelated
A secondary issue (bridge process exits when Chrome extension disconnects via Native Messaging stdin EOF) is not addressed in this PR. Fixing that requires careful design to avoid port-conflict problems when Chrome respawns the bridge. It can be tracked separately.
Discovered while configuring mcporter on Windows with the Chrome MCP extension.