Removes kilo, kimi, kimi-code, copilot, windsurf, augment, trae, qwen, hermes, cline, codebuddy and pi end to end: capability descriptors, installer branches and converters (bin/install.js 14.9k -> 11.2k lines), TypeScript converters, hook surfaces and runtime homes, review lanes qwen/kimi-code, the two pi migrations, Kimi payload normalization in the hook guards, dead hostBehaviors vocabulary, launcher home probes, fixtures, runtime-specific tests and the prose that presented them as supported. Installer output for the six kept runtimes is byte-identical to before the prune. The Kimi tool-vocabulary tests in workflow-guard, read-guard and read-injection-scanner are left in place pending a decision.
7.1 KiB
How to connect a host to the MSD companion MCP server
This guide shows you how to make a MCP-capable host (Claude Code, Codex,
OpenCode, VS Code, Antigravity CLI, Cursor) drive
MSD — run MSD
commands and read/write .planning/ state — through the companion MCP server,
with no bespoke plugin.
Once connected, three tools appear in the host alongside its others:
msd_invoke_command, msd_read_state, msd_write_state. The server also
serves a read-only catalog of MSD's own content — workflows and
references as MCP resources, and the /msd-* commands as MCP prompts — so a
host can browse and pull that content directly instead of shelling out to the
CLI. (For the tool contracts, see the reference section below; for why this
server exists and its trust model, see
ADR-1239 and the
capability trust model.)
1. Add the server to your host's MCP config
The entry shape is the same everywhere; only the config file and key differ by host.
{
"msd": {
"command": "npx",
"args": ["-y", "@golem15/msd-core", "msd-mcp-server"],
"cwd": "/abs/path/to/your/project"
}
}
- Claude Code / Codex / Cursor — under the host's
mcpServersobject (project or user config). - VS Code — in the workspace MCP servers list.
- Antigravity — under the
mcpServersblock of its standalonemcp_config.jsonprofile (not embedded insettings.json) — global at~/.gemini/antigravity/mcp_config.json(or the siblingantigravity-ide/antigravity-clidir MSD resolved into), project-local at.agents/mcp_config.json. MSD's installer configures this entry automatically (--antigravityinstalls). - OpenCode — under the
mcpkey (notmcpServers), in~/.config/opencode/opencode.jsonc(global) or./opencode.json(project). The entry shape also differs — see below.
Set cwd to the project whose .planning/ you want MSD to manage — the server
resolves state paths against it.
OpenCode entry shape
OpenCode uses a
type/command/timeout entry under the mcp key instead of the generic
command/args/cwd form above:
{
"mcp": {
"msd": {
"type": "local",
"command": ["npx", "-y", "@golem15/msd-core", "msd-mcp-server"],
"timeout": 10000
}
}
}
2. Restart the host
On startup the host performs the MCP initialize handshake. The response
advertises tools, resources, and prompts capabilities, so the three MSD
tools become callable and the host can also list the served catalog
(resources and prompts) described below. The server never advertises
resources.subscribe or listChanged — the catalog is fixed for the life of
the server process, so there is nothing to subscribe to.
3. Verify
Ask the host to read an existing planning file:
{ "name": "msd_read_state", "arguments": { "path": "/abs/path/to/your/project/.planning/STATE.md" } }
It returns the file's contents. msd_invoke_command takes
{family, subcommand, args} and returns the command-routing hub's structured
result (the same shape msd-tools produces).
4. Browse the catalog (resources and prompts)
The server also exposes MSD's own content tree as MCP resources and the
commands/msd/*.md command set as MCP prompts. This is additive: the
file-copy install (the default for every runtime) is unchanged, and the
catalog only adds a way for an MCP-capable host to read the same content
directly over the protocol.
List and read a resource
List available resources (paginated — ask the host to follow nextCursor
until it is absent):
{ "name": "resources/list", "arguments": { "cursor": null } }
Each entry has a msd://<segment>/<relpath> URI, where <segment> is
workflows, references, or commands, and <relpath> is the file's path
within that segment (for example, msd://workflows/plan-phase.md,
msd://references/untrusted-input-boundary.md, or
msd://commands/plan-phase.md). Commands appear in both surfaces: read one as
a resource to get its raw markdown, or get it as a prompt to have the host
treat it as an invocable message. Read one by URI:
{ "name": "resources/read", "arguments": { "uri": "msd://workflows/plan-phase.md" } }
An unknown or unrecognized URI (including any path-traversal or absolute-path attempt) returns a JSON-RPC error rather than an empty or partial result.
List and get a prompt
{ "name": "prompts/list", "arguments": {} }
Each entry is keyed by its bare command name — plan-phase, not a path. Get
one:
{ "name": "prompts/get", "arguments": { "name": "plan-phase" } }
An unknown prompt name returns a JSON-RPC error. prompts/get accepts an
arguments object but ignores it — no shipped command template takes
injected arguments today.
Composed vs. verbatim content
Workflow resources (msd://workflows/…) are served composed — with
<!-- msd:section --> markers stripped — exactly as the installed file tree
gets them, while reference and command content is served verbatim, because
some reference and command docs use that marker syntax as a documented example
rather than a real marker.
If something does not work
command not found: msd-mcp-server— invoke vianpxas shown above, or install the package globally first (npm i -g @golem15/msd-core).msd_read_statefails with ENOENT — the path is resolved literally; pass an absolute path under the project's.planning/.- The host lists no MSD tools — confirm the server starts in isolation:
npx @golem15/msd-core msd-mcp-serverthen send aninitializerequest on stdin; it writes aprotocolVersionresponse and exits on EOF. - You manage multiple projects — register one
msdentry per project with a distinct name andcwd; the server is stateless across projects.
Reference — the three tools
| Tool | Arguments | Returns |
|---|---|---|
msd_invoke_command |
{family: string, subcommand: string, args?: unknown[]} |
the command-routing hub result ({ok, …}) as JSON text |
msd_read_state |
{path: string} |
the file contents as text |
msd_write_state |
{path: string, content: string} |
{ok: true, path} as JSON text |
Errors from a tool are returned as MCP tool errors (isError: true), not as
JSON-RPC protocol errors — the host surfaces them in its normal tool-failure UX.
Reference — the served catalog
| Method | Arguments | Returns |
|---|---|---|
resources/list |
{cursor?: string} |
{resources: [{uri, name, title, description, mimeType}], nextCursor?: string} |
resources/read |
{uri: string} |
{contents: [{uri, mimeType, text}]} |
prompts/list |
{} |
{prompts: [{name, title, description}]} |
prompts/get |
{name: string, arguments?: object} |
{description, messages: [{role: "user", content: {type: "text", text}}]} |
Errors from the catalog (unknown URI, unknown prompt name, malformed cursor, a refused path-traversal attempt) are returned as JSON-RPC protocol errors, not MCP tool errors — unlike the three tools above.