feat(agent/x/agentmcp): migrate workspace agent MCP client to official Go SDK by ibetitsmike · Pull Request #28059 · coder/coder · GitHub
Skip to content

feat(agent/x/agentmcp): migrate workspace agent MCP client to official Go SDK - #28059

Merged
ibetitsmike merged 1 commit into
mainfrom
mike/mcp-go-sdk/agent-client
Aug 13, 2026
Merged

feat(agent/x/agentmcp): migrate workspace agent MCP client to official Go SDK#28059
ibetitsmike merged 1 commit into
mainfrom
mike/mcp-go-sdk/agent-client

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Stack Context

PR 4 of 6 in a stack that migrates every Coder MCP surface from the archived github.com/mark3labs/mcp-go library to the official github.com/modelcontextprotocol/go-sdk v1.7.0.

Stack: #28056 -> #28057 -> #28058 -> #28059 -> #28060 -> #28061

Why

The workspace agent MCP manager now stores *mcp.ClientSession per configured server.

  • stdio servers use mcp.CommandTransport with an exec.Cmd built from Coder's agentexec.Execer, preserving environment enrichment; the command uses the manager's parent context so a stdio subprocess outlives the connect handshake and stops when the session closes.
  • HTTP and SSE servers use header-injecting HTTP clients.
  • Binary tool content is re-encoded to base64 for the agent API because the official SDK decodes it into raw bytes.
  • The reload test now triggers config diffs via an environment variable because the official SDK drops connections on non-protocol stdout output (flags like -test.v made the fake server chatty).

Mux created this PR on Mike's behalf.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df5eb4d84a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +29 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve redirect stripping for sensitive MCP headers

When an HTTP or SSE MCP endpoint redirects to an unrelated host, net/http.Client deliberately removes sensitive headers such as Authorization and Cookie, but the redirected request passes through this round tripper again and these lines restore them. A configured bearer token can therefore be sent to a cross-origin redirect target. Inject these headers only on the initial request or restrict reinjection to the original host.

Useful? React with 👍 / 👎.

@ibetitsmike
ibetitsmike force-pushed the mike/mcp-go-sdk/agent-client branch from df5eb4d to 4c14a18 Compare August 13, 2026 09:50
ibetitsmike added a commit that referenced this pull request Aug 13, 2026
## Stack Context

PR 2 of 6 in a stack that migrates every Coder MCP surface from the
archived `github.com/mark3labs/mcp-go` library to the official
`github.com/modelcontextprotocol/go-sdk` v1.7.0.

Stack: #28056 -> #28057 -> #28058 -> #28059 -> #28060 -> #28061

## Why

`coder exp mcp server` (stdio) now uses the official SDK server with
`mcp.IOTransport` over the invocation's stdin/stdout, and reuses the
shared `coderd/mcp.RegisterSDKTool` helper from PR #28056 so both
servers register tools identically.

- A `nopWriteCloser` prevents the SDK from closing the invocation's
stdout.
- Tests send spec-compliant initialize params and
`notifications/initialized` before `tools/list` because the official SDK
enforces the protocol lifecycle.

> Mux created this PR on Mike's behalf.
@ibetitsmike
ibetitsmike force-pushed the mike/mcp-go-sdk/agent-client branch from 4c14a18 to 051463b Compare August 13, 2026 10:02
Base automatically changed from mike/mcp-go-sdk/chatd-client to main August 13, 2026 10:11
…l Go SDK

Replace the mark3labs client with the official SDK client for
.mcp.json-configured servers. Stdio servers run via CommandTransport
with the same execer-built command and enriched environment; the
subprocess still outlives the connect handshake because the command
context is the manager's, not the bounded connect context. HTTP and
SSE headers move to an http.RoundTripper on the transport's client.

Config parsing, transport inference, tool-name prefixing, catalog
snapshots, and the agent call-tool API keep their external shapes.
The SDK re-encodes binary content as base64 for the agent API and,
unlike mark3labs, closes stdio connections on non-protocol stdout
output, which is what the spec requires of servers.
ibetitsmike added a commit that referenced this pull request Aug 13, 2026
…al Go SDK (#28058)

## Stack Context

PR 3 of 6 in a stack that migrates every Coder MCP surface from the
archived `github.com/mark3labs/mcp-go` library to the official
`github.com/modelcontextprotocol/go-sdk` v1.7.0.

Stack: #28056 -> #28057 -> #28058 -> #28059 -> #28060 -> #28061

## Why

The chatd external MCP client (admin-configured MCP servers used by
Agent chat) now holds `*mcp.ClientSession` connections created via
`mcp.NewClient` and `Client.Connect`, with `StreamableClientTransport`
or `SSEClientTransport` per server config.

- Auth and identity headers are injected through a custom
`http.RoundTripper` because the official SDK has no per-header transport
options.
- Tool input schemas are extracted from the SDK's `map[string]any`
decoding.
- Content conversion handles the official pointer content types; the SDK
decodes blob resources into raw bytes, so binary content is handled
without an extra base64 round trip.
- Test fixtures are official stateless Streamable HTTP servers.

> Mux created this PR on Mike's behalf.
@ibetitsmike
ibetitsmike force-pushed the mike/mcp-go-sdk/agent-client branch from 051463b to 4341c1b Compare August 13, 2026 10:11
pull Bot pushed a commit to TKaxv-7S/coder that referenced this pull request Aug 13, 2026
## Stack Context

PR 1 of 6 in a stack that migrates every Coder MCP surface from the
archived `github.com/mark3labs/mcp-go` library to the official
`github.com/modelcontextprotocol/go-sdk` v1.7.0, adding MCP 2026-07-28
support while keeping compatibility with clients speaking 2024-11-05
through 2025-06-18.

Stack: coder#28056 -> coder#28057 -> coder#28058 -> coder#28059 -> coder#28060 -> coder#28061

## Why

The coderd Streamable HTTP MCP server (`/api/experimental/mcp/http`) is
the foundation layer: it introduces the official SDK dependency and the
shared `RegisterSDKTool` helper the CLI server reuses.

- The server runs the SDK handler in stateless mode with `JSONResponse:
true`, preserving the previous `application/json` POST wire format. GET
and DELETE return 405, and no `Mcp-Session-Id` is issued, both permitted
by the Streamable HTTP spec.
- `DisableLocalhostProtection` is set because coderd commonly listens on
loopback behind a reverse proxy with a public Host header; the
endpoint's bearer authentication is the relevant access control.
- Tool registration builds raw JSON object schemas and omits empty
`required`, keeping `tools/list` output byte-identical to the previous
server (verified with a golden comparison).
- SDK logs are adapted to `cdr.dev/slog/v3`; only warnings and errors
are forwarded because the SDK logs several INFO lines per stateless
request.
- Tests cover the modern 2026-07-28 flow, legacy 2025-06-18 initialize,
unsupported protocol version rejection (`-32022`), and non-POST method
behavior.

## Known behavior deltas vs the old endpoint

Both deltas come from the SDK enforcing the Streamable HTTP spec where
mark3labs was lenient, on an experimental endpoint:

- POST requests whose `Accept` header lists `application/json` without
`text/event-stream` are now rejected with 400 (the spec requires clients
to list both; a missing `Accept` header is still tolerated). mark3labs
did not validate `Accept` at all.
- The old server generated an unvalidated `Mcp-Session-Id` response
header; the stateless SDK handler issues none. Clients that merely echo
the header back are unaffected.

## Validation

Beyond unit/integration tests, a remote dogfood UAT ran protocol
conformance against a live dev server built from the stack tip: version
negotiation matrix (2024-11-05 through bogus/omitted values), auth,
session/method semantics, tool schema sanity, tools/call happy and error
paths (unknown tool, schema-violating args, malformed JSON, jsonrpc
"1.0"), and a concurrency smoke test. No 500s or connection drops; error
shapes are clean JSON-RPC/HTTP errors.

> Mux created this PR on Mike's behalf.
@ibetitsmike
ibetitsmike merged commit 7720e28 into main Aug 13, 2026
44 of 46 checks passed
@ibetitsmike
ibetitsmike deleted the mike/mcp-go-sdk/agent-client branch August 13, 2026 10:29
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants