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
## Overview
Split from #26466, scoped to **agent-only** changes. This PR exposes the
agent's context sources and snapshots over the existing agent socket.
There
are no changes outside `agent/`.
## What's included
- **agentsocket**: context source CRUD (`ContextSources`,
`GetContextSource`,
`AddContextSource`, `RemoveContextSource`) plus `GetContextSnapshot` and
`ResyncContext` RPCs, with matching client methods and proto. The server
receives the context `Manager` via `WithContextManager` and returns a
clean
error when it is absent.
- **agentcontext**: the resync JSON response now carries the
per-resource
`Name`, keeping the HTTP resync payload in sync with the drpc
`PushContextState` path in `agentsocket`.
- **agent**: passes the context `Manager` to the socket server via
`WithContextManager`.
## What's intentionally NOT here
- No MCP wiring. There are no MCP additions in `agent.go` or
`agentcontext`.
MCP ownership will land later in `agentcontext`; this PR does not build
on
`agent/x/agentmcp`.
- No changes to `agent/x/agentmcp` or the `agentcontext` resolver. The
socket
serves whatever context resources the `Manager` already resolves.
<details>
<summary>Context for reviewers</summary>
This is one of several PRs split out of #26466. Earlier revisions also
wired
live MCP servers through the socket; that scope was removed so this PR
stays
purely socket + context plumbing inside `agent/`. The agentcontext
resolver,
`agent/x/agentmcp`, and `agent.go` MCP startup behavior are unchanged
from
`main`.
</details>
---
_Created by Coder Agents on behalf of @kylecarbs._
Add a new subcommand to list all registered sync units and their current
statuses. This provides a quick overview of the dependency coordination
state in a workspace without needing to query each unit individually.
The command supports both table (default) and JSON output formats.
```
$ coder exp sync list
UNIT STATUS READY
unit-a started true
unit-b completed true
unit-c pending false
$ coder exp sync list --output json
[
{
"unit_name": "my-unit",
"status": "started",
"is_ready": true
}
]
```
When no units are registered, the command prints `No units registered`.
<details><summary>Changes across layers</summary>
- `agent/unit`: add `Manager.ListUnits()` method
- `agent/agentsocket/proto`: add `SyncList` RPC, bump API to v1.2
- `agent/agentsocket`: add service and client implementations
- `cli`: add `sync_list.go` command, register in `sync.go`
- Tests: three golden-file test cases (empty list, multiple units, JSON)
</details>
> Generated by Coder Agents on behalf of @SasSwart
---------
Co-authored-by: Cian Johnston <cian@coder.com>
relates to #21335
Adds UpdateAppStatus on the agentsocket, wired up to forward to Coderd over the dRPC connection the agent maintains.
Disclosure: I used AI to generate significant portions of this PR, but hand-reviewed and tweaked the code. I consider it approximately indistinguishable from what I would have done by hand.
relates to: https://github.com/coder/internal/issues/1094
This is number 2 of 5 pull requests in an effort to add agent script
ordering. It adds a drpc API that is exposed via a local socket. This
API serves access to a lightweight DAG based dependency manager that was
inspired by systemd.
In follow-up PRs:
* This unit manager will be plumbed into the workspace agent struct.
* CLI commands will use this agentsocket api to express dependencies
between coder scripts
I used an LLM to produce some of these changes, but I have conducted
thorough self review and consider this contribution to be ready for an
external reviewer.