Files
coder/agent/agentcontext/doc.go
T
Kyle Carberry 27ecd17991 refactor: consolidate agent MCP onto a single persistent engine (#26599)
Two MCP code paths both spawned the servers declared in a workspace's
`.mcp.json`: the persistent engine in `agent/x/agentmcp` (which owns
tool-call execution via `CallTool`) and an ephemeral one-shot runner in
`agent/agentcontext` (`mcprunner.go`) that connected, listed tools, and
immediately closed each server purely for discovery. Every declared
server was launched twice, and the discovery path duplicated the
engine's `.mcp.json` parse, transport-build, env-resolve, and connect
logic.

This makes `agent/x/agentmcp` the single persistent MCP engine. The
`agentcontext` manager now reads that engine's per-server catalog
in-process through an injected `MCPCatalog` option and surfaces each
server as a `KindMCPServer` resource. The engine wires `SetOnReload` to
the manager's `Trigger`, so a reload (startup connect or `.mcp.json`
edit) re-resolves and re-pushes the pinned resources. Tool-call
execution is unchanged: it still flows through the engine's `CallTool`
over `POST /api/v0/mcp/call-tool`.

The now-dead HTTP discovery surface is removed: the agent `GET
/api/v0/mcp/tools` route with `agentmcp.API.handleListTools`, and
`workspacesdk.AgentConn.ListMCPTools` with `ListMCPToolsResponse` (mock
regenerated). The change nets roughly `-1370` lines, mostly the deleted
duplicate runner and its tests.

<details>
<summary>Decision log</summary>

The merge of #26585 made pinned `chat_context_resources` the sole source
of workspace context, which surfaced the duplicate spawning. Two options
were considered:

- **Option A + dependency injection (chosen):** keep `agent/x/agentmcp`
as the single persistent engine; `agentcontext` consumes its catalog
in-process and stays the orchestrator/owner at the API boundary (it
still pushes `KindMCPServer` resources). This is low-risk because
`agentcontext` already exposed the `resolver.MCPResources` seam, so the
change just rebinds it from the ephemeral runner to the shared engine.
- **Option B (rejected):** reimplement persistent pooling, reconnect,
singleflight, and race handling inside `agentcontext` and delete
`agentmcp`. Too broad, and it discards the engine's tested lifecycle for
no behavioral gain.

`agentcontext`'s discovery was never what kept servers alive; its runner
closed each server immediately after listing tools. The component
holding persistent connections was always `agentmcp`, which is why
execution already lived there. Consolidating onto it removes the
duplicated stack rather than a whole package: both packages survive with
distinct roles (`agentmcp` is the engine, `agentcontext` is the
orchestrator/owner).

</details>

Coder Agents generated on behalf of @kylecarbs
2026-06-22 22:21:58 -06:00

35 lines
1.9 KiB
Go

// Package agentcontext consolidates the agent-side plumbing that
// resolves, watches, and pushes workspace context (instruction
// files, skills, and MCP configuration) to coderd.
//
// This is the agent half of the design described in
// "RFC: Workspace Context Sources for Coder Agents". It owns:
//
// - User-declared scan roots (Sources) layered on top of
// built-in defaults and the working directory.
// - A resolver that classifies files at fixed locations under
// each scan root into typed Resources (instruction files,
// skills, MCP configs, MCP servers). Discovery is shallow:
// instruction files (AGENTS.md, CLAUDE.md, .cursorrules) and
// .mcp.json are read only at a scan root's top level, skills
// only from fixed container directories (skills, .agents/skills,
// .claude/skills, .codex/skills), and the resolver never walks
// the tree downward or up to a parent directory.
// - A fixed-location fsnotify watcher that signals a re-resolve
// when any recognized file changes.
// - An HTTP API at /api/v0/context/sources for source CRUD
// and /api/v0/context/resync for synchronous push barriers.
// - A Pusher abstraction so the latest Snapshot can be shipped
// to coderd without coupling this package to any particular
// drpc client version.
//
// Live MCP server tool lists come from the shared MCP engine in
// agent/x/agentmcp, which owns the single set of MCP server connections
// used for both tool discovery and tool-call execution. This package
// reads that engine's catalog through the injected MCPCatalog option and
// surfaces the servers and their tools as KindMCPServer resources, so
// MCP servers are pushed to coderd alongside instruction files and
// skills. The engine notifies this package through the Manager's Trigger
// when its catalog changes, driving a re-resolve and re-push.
package agentcontext