🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

feat(coderd/x/chatd): serve workspace MCP tools and read_skill from pinned context - #26581

Merged
kylecarbs merged 1 commit into
mainfrom
feat/chatd-pinned-mcp-and-read-skill
Jun 22, 2026
Merged

feat(coderd/x/chatd): serve workspace MCP tools and read_skill from pinned context#26581
kylecarbs merged 1 commit into
mainfrom
feat/chatd-pinned-mcp-and-read-skill

Conversation

@kylecarbs

@kylecarbs kylecarbs commented Jun 22, 2026

Copy link
Copy Markdown
Member

This wires the last two consumer-side gaps of the agent-pushed workspace context refactor. coderd already hydrates each chat's pinned context (chat_context_resources), and resolveTurnWorkspaceContext already prefers the pin for instruction files and skill metadata. This change extends that preference to workspace MCP tools and the read_skill body.

Workspace MCP tools are now built from the chat's pinned mcp_server resources instead of a live ListMCPTools pull. resolveWorkspaceMCPTools prefers the pin and falls back to live discovery for chats whose agent has not reported context yet, gated the same way as the instruction/skills pin: the pin wins whenever the chat has any pinned rows, so a workspace with no MCP servers contributes no tools rather than resurrecting stale ones. Because the agent reports tool names unprefixed, each tool is re-prefixed to the {server}__{tool} form and the pushed JSON Schema is split into properties and required so the result matches what live discovery produced. Calls still proxy through the workspace agent connection; the snapshot carries tool definitions, not a way to execute them.

read_skill now serves a workspace skill's SKILL.md body from the pinned snapshot (SkillMeta.Meta) instead of dialing the agent, so a pinned chat keeps returning the same instructions even when the workspace is unreachable. The supporting-file list stays a best-effort live lookup, since the snapshot carries only the meta file per the agent push contract.

The legacy live paths remain as the fallback for agents that have not pushed context; RFC Release-5 cleanup of those paths is out of scope here.

Implementation plan and decisions

Background

The agentcontext refactor is mostly shipped across earlier PRs (#25983, #26526, #26533, #26577, #26570, #26573): the agent resolves instruction files, skills, and MCP servers into a snapshot, pushes it via PushContextState, and coderd hydrates each chat's pinned context (chat_context_resources). This PR closes the two remaining consumer-side gaps.

Key facts established from the code

  • Pushed MCP tool names are unprefixed (mcprunner stores tool.Name); the agent MCP proxy and CallMCPTool expect the {server}__{tool} form (agentmcp.ToolNameSep). The pinned path reconstructs the prefix for execution, matching the model-facing names the legacy path produced.
  • Legacy agentmcp sets MCPToolInfo.Schema = InputSchema.Properties and Required = InputSchema.Required separately. The pushed input_schema is the full JSON Schema object, so the pinned builder extracts properties and required to match that shape.
  • SkillMetaBody.meta is the verbatim SKILL.md. The supporting-file list is not in the snapshot, so it is fetched live on demand (best-effort).
  • Gating mirrors resolveTurnWorkspaceContext: the pin wins when the chat has any pinned rows; otherwise the live path is used.

Changes

  1. chattool/skill.go: add SkillMeta.Meta []byte; extract listSkillFiles from LoadSkillBody; in readWorkspaceSkillBody, when Meta is present, parse the body from it without dialing and list files best-effort, else use the legacy live read.
  2. context_prompt.go: populate SkillMeta.Meta in contextResourcesToPrompt; add workspaceMCPToolInfosFromResources (pinned mcp_server rows to []workspacesdk.MCPToolInfo with prefixed names and split properties/required) and splitMCPInputSchema.
  3. chatd.go: add pinnedWorkspaceMCPTools (build tools from the pin, ok-gated) and resolveWorkspaceMCPTools (pin-first, fall back to discoverWorkspaceMCPTools).
  4. generation_preparer.go: call resolveWorkspaceMCPTools instead of discoverWorkspaceMCPTools.

Tests

  • chattool/skill_test.go: read_skill serves the pinned body without dialing, lists files via LS, and still returns the body when the workspace is unreachable.
  • context_prompt_internal_test.go: SkillMeta.Meta is populated; workspaceMCPToolInfosFromResources prefixing/properties/required/skip behavior; pinnedWorkspaceMCPTools ok-gating and fallback dispatch.

Opened by Coder Agents on behalf of @kylecarbs.

…inned context

Wire the consumer side of the agent-pushed workspace context snapshot so a
chat uses its pinned context instead of live-pulling from the workspace agent.

- Build workspace MCP tools from the chat's pinned chat_context_resources
  instead of dialing the agent for a live tool list. resolveWorkspaceMCPTools
  prefers the pin and falls back to live discovery for chats whose agent has
  not reported context yet, mirroring resolveTurnWorkspaceContext for
  instructions and skills. Pushed tool names are re-prefixed to
  "<server>__<tool>" and the pushed JSON Schema is split into properties and
  required to match the shape the live path produces.
- Serve read_skill's SKILL.md body from the pinned snapshot (SkillMeta.Meta)
  so a pinned chat keeps returning the same instructions even when the
  workspace is unreachable. The supporting-file list stays a best-effort live
  lookup, since the snapshot carries only the meta file.

Tool calls still proxy through the workspace agent connection; the snapshot
carries tool definitions, not a way to execute them. The legacy live paths
remain as fallback for agents that have not pushed context.
@kylecarbs
kylecarbs marked this pull request as ready for review June 22, 2026 19:10
@kylecarbs
kylecarbs merged commit 78c5ab9 into main Jun 22, 2026
61 of 62 checks passed
@kylecarbs
kylecarbs deleted the feat/chatd-pinned-mcp-and-read-skill branch June 22, 2026 19:13
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 22, 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