mcp: simplify and fix the streamable client transport

Make several cleanups of the streamable client transport, encountered
during work on JSON support for the streamable server:

- The 'Close' condition is differentiated from asynchronous failures. A
  failure should unblock Read with an error, at which point the JSON-RPC
  connection will be broken and closed.
- Fields are reordered in streamableClientConn to make guards more
  apparent.
- The handling of sessionID is simplified: we simply set the session ID
  whenever we receive response headers. No need to have special handling
  for the first request, as the serializeation of session initialization
  is implemented in Client.Connect.
- Since the above bullet makes Write a trivial wrapper around
  postMessage, the two methods are merged.
- A bug is fixed where JSON responses were handled synchronously in
  Write. This lead to deadlock when a hanging client->server request is
  waiting on a server->client request. Now JSON is handled symmetrically
  to SSE: the Write returns once response headers are received.
  asynchronous to Write.
- The httpConnection interface is renamed to clientConnection, and
  receive the entire InitializeResult.
- streamableClientConn receivers are renamed to be consistently 'c'.
This commit is contained in:
Rob Findley 2025-08-08 15:13:31 +00:00 • committed by Robert Findley
commit 6ea7a6c653

View file

@ -79,7 +79,7 @@ func TestStreamableTransports(t *testing.T) {
if sid == "" {
t.Error("empty session ID")
}
if g, w := session.mcpConn.(*streamableClientConn).protocolVersion, latestProtocolVersion; g != w {
if g, w := session.mcpConn.(*streamableClientConn).initializedResult.ProtocolVersion, latestProtocolVersion; g != w {
t.Fatalf("got protocol version %q, want %q", g, w)
}
// 4. The client calls the "greet" tool.