Skip to content

docs: rework channels proposal around local mcp bridge#706

Merged
icholy merged 2 commits into
masterfrom
docs/channels-proposal-local-bridge
May 30, 2026
Merged

docs: rework channels proposal around local mcp bridge#706
icholy merged 2 commits into
masterfrom
docs/channels-proposal-local-bridge

Conversation

@icholy-bot
Copy link
Copy Markdown
Collaborator

Summary

  • Substantially rewrites proposals/draft/claude-code-channels.md to reflect the new design direction: channels are about notifying a local user-driven Claude Code session that orchestrates xagent through the user-facing MCP server, not pushing into in-container agents.
  • Introduces a local stdio xagent mcp bridge that re-exposes the user-facing tools (via a shared mcpserver.AddTools refactor) and translates the existing apiservernotifyserver SSE notification stream into notifications/claude/channel events.
  • Drops the previously-proposed task_events table and PollEvents RPC — the existing pubsub/SSE pipeline already carries every change needed.
  • Refreshes the Background section to match the current Claude Code Channels research-preview docs (capability shape, meta identifier rule, fire-and-forget delivery, allowlist, auth/platform constraints).
  • Re-weighs Go vs TypeScript/Bun for the bridge now that the original "no Node in containers" objection no longer applies (the bridge runs locally, and Bun is already a channels prerequisite).
  • Notes the in-container "push to agents" framing as out-of-scope future work.

This is a docs-only change. No Go code is modified.

Related to #466

Test plan

  • Read the rewritten proposal end-to-end and confirm the structure matches the proposal skill (.claude/skills/proposal/SKILL.md).
  • Confirm the central transport constraint (channels are stdio-only) is stated clearly enough to justify the bridge.
  • Confirm the design references real types/files: mcpserver.go, apiserver.go's s.publish, notifyserver, model.Notification, internal/x/sse, xagentclient.
  • Verify Open Questions reflect genuinely open decisions (Go vs TS/Bun, filter scope, bundled vs split bridge).

Reframe the Claude Code channels proposal: the primary use case is
notifying a local user-driven Claude Code session that orchestrates
xagent tasks through the user-facing MCP server, not pushing into
in-container agents.

Replace the new task_events table and PollEvents RPC with reuse of
the existing apiserver -> notifyserver SSE pipeline. Introduce a
local stdio "xagent mcp" bridge that proxies the user-facing tools
and translates model.Notification events into
notifications/claude/channel. Update channel docs facts to match
the current research preview, and re-weigh Go vs TS/Bun for the
bridge now that the in-container Node objection no longer applies.
@icholy-bot icholy-bot requested a review from icholy as a code owner May 30, 2026 13:12
@icholy
Copy link
Copy Markdown
Owner

icholy commented May 30, 2026

@icholy-bot Follow-up findings from investigating the Go SDK gap directly against the vendored source — a few things in the proposal are now stale and should be updated:

1. SDK version is wrong. The proposal says "Go SDK v1.2.0". The repo is pinned at v1.4.1, latest is v1.6.1, and the gap persists in all of them (still only NotifyProgress/Log, no public generic notify). Update the version reference.

2. The "Go MCP SDK Gap" section should be reframed from open → mostly resolved.

  • Advertising the capability needs no patch. ServerOptions.Capabilities.Experimental map[string]any is public (protocol.go:1557, consumed at server.go:563). Declaring experimental["claude/channel"] = {} works on stock SDK. This should be separated out of "the gap" entirely.
  • Sending the notification → use the transport-wrapper (option 2), it's the chosen path. It's 100% public API: mcp.Transport/mcp.Connection are exported, and a &jsonrpc.Request{Method: "notifications/claude/channel", Params: raw} with no ID serializes as a valid notification. ~30 lines of wrapper in our repo, no fork, no vendor patch. The wrapper just needs to mutex-guard Write so injected frames don't interleave with the SDK's.

3. Option 1 (upstream ServerSession.Notify) is a dead end short-term — drop the "strongly preferred." It's literally open PR modelcontextprotocol/go-sdk#898 (cites notifications/claude/channel as motivation), and maintainer @jba rejected the send-only approach: "A send-only solution isn't sufficient. There must be a story on the receive side… let's not write more code until we understand the solution." Tracked under #745; competing PRs #844 and #956. Net: don't block on upstream; ship the transport wrapper with a TODO linking #745 so we can delete it once upstream lands a combined send+receive design.

4. The Go-vs-Bun open question now resolves toward Go. The only thing that made Bun attractive was sidestepping the SDK gap — the transport wrapper eliminates that, so Go (reusing xagentclient, internal/x/sse, model.Notification, single binary) wins. Worth closing that open question rather than leaving it open.

The receive-side concern @jba raised only matters to us if/when we add channel permission relay (Claude Code → bridge); for the v1 one-way "task updated" push, send-only via the transport wrapper is sufficient.

Fold in review findings from PR #706:

- Correct vendored Go MCP SDK version: v1.4.1 (v1.6.1 latest); gap
  persists in all of them.
- Split the prior "SDK gap" section into two: declaring the
  claude/channel capability is already supported by the public
  ServerOptions.Capabilities.Experimental and needs no patch;
  sending notifications/claude/channel is handled by a ~30-line
  transport wrapper over the public mcp.Transport, mcp.Connection,
  and jsonrpc.Request APIs.
- Drop upstream ServerSession.Notify as the preferred path: the
  send-only design was rejected by maintainer @jba on go-sdk #898;
  combined send+receive design is tracked in go-sdk #745.
- Drop the temporary-fork option entirely.
- Resolve the Go-vs-TS/Bun open question toward Go now that the
  transport wrapper eliminates Bun's only structural advantage.
- Update the xagent mcp skeleton to thread the wrapped transport
  to the SSE->channel goroutine.
@icholy-bot
Copy link
Copy Markdown
Collaborator Author

Thanks — all four points folded in (commit 23b8ea2). Summary of the changes:

  1. SDK version — fixed: now says vendored v1.4.1 / latest v1.6.1, gap persists across both.
  2. "SDK Gap" reframed — split into two subsections:
    • Advertising claude/channel: already public API (ServerOptions.Capabilities.Experimental at protocol.go L1547 in v1.4.1). No patch needed.
    • Sending the notification: chosen path is a ~30-line transport wrapper over public mcp.Transport, mcp.Connection, and jsonrpc.Request (no ID = notification, per Request.IsCall() at messages.go:110). Mutex-guarded Write. The xagent mcp skeleton now constructs channelTransport{inner: &mcp.StdioTransport{}} and passes the wrapper to both server.Connect and the SSE→channel goroutine.
  3. Upstream ServerSession.Notify — demoted from "strongly preferred" to a "why not": linked to go-sdk PR #898, @jba's rejection comment, the unified-design tracking issue #745, and competing PRs #844 / #956. Wrapper ships with a TODO pointing at proposal: assignment-triggered routing rules #745. Temporary fork dropped entirely.
  4. Go vs TS/Bun — moved from Open Questions into Trade-offs and resolved toward Go. Open Question Use GetTaskDetails in task list command #4 (permission relay) also rewritten to note it's the case that would need the receive-side story proposal: assignment-triggered routing rules #745 is blocking on, so it's bounded by that upstream design.

The "Future work: pushing into in-container agents" section now says the transport wrapper is reusable as-is for the in-container agent server. (task 668)

@icholy icholy merged commit bed15d1 into master May 30, 2026
1 check passed
@github-actions github-actions Bot mentioned this pull request May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants