Tracking issue for replacing github.com/mark3labs/mcp-go with the official Go MCP SDK. Several MCP improvements are blocked on it, so it is filed on its own rather than as a note inside each.
Why
The current library owns resources the gateway needs to manage, and exposes no seam to reach them.
It owns the subprocess. client/transport/stdio.go builds the child with cmd.StdoutPipe(), keeps cmd unexported with no accessor, and calls cmd.Wait() itself from Close(). A second Wait errors, so the gateway cannot own the Start → Wait → decide loop that real supervision requires. A Signal(0) liveness probe is not a substitute: a dead-but-unreaped child is a zombie and still accepts it.
It owns the read path. The stdio transport reads with bufio.Reader.ReadString('\n'), which grows without limit. The gateway cannot cap it, because the library calls cmd.StdoutPipe() itself — pre-setting cmd.Stdout makes that call fail.
It has an unfixed data race. Client.initialized is a plain bool written by Initialize and read without synchronization by sendRequest, still present in the latest release. Reported upstream as mark3labs/mcp-go#935. The gateway currently orders its own calls to avoid it, which is a constraint on internal code that exists only because of the dependency.
What this unblocks
Release shape
Minor, not a patch. The migration swaps a go.mod dependency that consumers of the importable gateway (#206) can see, and the transport's observable behaviour may shift in ways a patch should not carry.
Notes
Worth confirming before starting: whether the official SDK exposes the process handle, whether it bounds its own reads or allows a limit to be supplied, and how its client type handles concurrent use.
Tracking issue for replacing
github.com/mark3labs/mcp-gowith the official Go MCP SDK. Several MCP improvements are blocked on it, so it is filed on its own rather than as a note inside each.Why
The current library owns resources the gateway needs to manage, and exposes no seam to reach them.
It owns the subprocess.
client/transport/stdio.gobuilds the child withcmd.StdoutPipe(), keepscmdunexported with no accessor, and callscmd.Wait()itself fromClose(). A secondWaiterrors, so the gateway cannot own theStart→Wait→ decide loop that real supervision requires. ASignal(0)liveness probe is not a substitute: a dead-but-unreaped child is a zombie and still accepts it.It owns the read path. The stdio transport reads with
bufio.Reader.ReadString('\n'), which grows without limit. The gateway cannot cap it, because the library callscmd.StdoutPipe()itself — pre-settingcmd.Stdoutmakes that call fail.It has an unfixed data race.
Client.initializedis a plainboolwritten byInitializeand read without synchronization bysendRequest, still present in the latest release. Reported upstream as mark3labs/mcp-go#935. The gateway currently orders its own calls to avoid it, which is a constraint on internal code that exists only because of the dependency.What this unblocks
Release shape
Minor, not a patch. The migration swaps a
go.moddependency that consumers of the importable gateway (#206) can see, and the transport's observable behaviour may shift in ways a patch should not carry.Notes
Worth confirming before starting: whether the official SDK exposes the process handle, whether it bounds its own reads or allows a limit to be supplied, and how its client type handles concurrent use.