4.3 KiB
coding-agent-mcp
An MCP server for coding agents. It provides workspace-subpath-scoped file editing and typed build/test tasks, including Python tests.
Security model
This is intentionally a single combined server:
coding-agent-mcp. The old split servers and the generic
run_command API were removed.
- HTTP requires an API key. Set
CODING_AGENT_MCP_API_KEYStoSUBJECT=TOKENentries separated by commas. - An SSE connection creates a server-generated session bound to that authenticated subject. MCP requests must use that live session; callers cannot choose a session ID.
- The session’s optional
workspaceSubpathis bound when SSE opens and cannot change afterward. It is the only filesystem scope beneath the configured workspace root; the server-generated session ID is not part of the directory path. - File and task paths are relative only. The client cannot select a root or use absolute paths.
- File paths are checked for traversal and symlink escapes.
- HTTP sends no permissive CORS header. Set
CODING_AGENT_MCP_CORS_ORIGINSto an explicit comma-separated origin allowlist only when browser access is required. - Remote HTTP command execution defaults to disabled.
Set
CODING_AGENT_MCP_EXECUTION_BACKEND=localonly in the hardened runner deployment below.
run_task deliberately accepts no shell command, flags,
environment variables, npm script name, or local executable. It maps a
typed request to a fixed invocation. Project tests and build scripts
still execute project code, so this validation is not a sandbox.
Tools
Workspace tools: list_files, read_file,
read_files, read_binary_file,
search_text, write_file,
write_binary_file, apply_patch,
make_directory, delete_path,
move_path, rename_path, and
file_info.
Execution tool: run_task.
Example Python request:
{
"runner": "pytest",
"task": "test",
"paths": ["tests/unit"],
"timeoutSeconds": 300
}Supported runners are pytest, npm,
pnpm, yarn, maven,
gradle, go, and cargo. Supported
tasks depend on the runner; the server rejects unsupported
combinations.
Local trusted use
Stdio is intended for a local, trusted client and enables typed task execution by default:
npm run start:coding-agent -- --root /absolute/path/to/workspaceThe runtime needs the selected tool installed. The supplied Docker image contains Python 3 and pytest.
Remote hardened deployment
- Copy
.env.exampleto.envand set a long random API token. - Create a dedicated workspace directory; do not mount a home directory, source checkout, Docker socket, or secrets.
- Make that directory writable by
CODING_AGENT_UID:CODING_AGENT_GID. - Deploy with
docker compose up --build -d.
The Compose deployment runs as a non-root UID, makes the container
filesystem read-only, provides an ephemeral /tmp, removes
Linux capabilities, applies process/memory/CPU limits, and places the
MCP service on an internal-only Docker network. The workspace mount is
the only intended writable persistent path.
This is a hardened local runner, not a VM-grade security boundary.
For untrusted agents or untrusted repositories, connect
run_task to an external ephemeral VM/container runner with
a copy-on-write workspace, no host bind mounts, no Docker socket, no
inherited secrets, resource quotas, and explicit network policy. Keep
execution disabled until such a runner is configured.
HTTP protocol
All HTTP endpoints require Authorization: Bearer TOKEN
(or x-api-key).
Streamable HTTP (recommended)
- Send an MCP
initializeJSON-RPC request toPOST /mcp. The response includesMcp-Session-Id. - Send subsequent MCP requests to
POST /mcpwith thatMcp-Session-Idheader. - Use
DELETE /mcpwithMcp-Session-Idto terminate the session. GET /mcpwithMcp-Session-Idopens an optional server-to-client SSE stream.
Legacy SSE
GET /sseopens the former MCP SSE transport. It emits anendpointevent for posting messages.- For automatic legacy-client fallback,
GET /mcpwithoutMcp-Session-Idprovides the same SSE handshake. - The pre-existing custom transport is retained:
GET /eventsreturnsx-session-id; send it onPOST /mcpasx-session-id. - Bind
x-workspace-subpathonly when opening or initializing a session; it cannot change afterward. GET /healthreports server health.
Development
npm test