dev-mcps/coding-agent-mcp
Lucio Lelii 0e6b400441 Bring the three MCP servers together as one deployable stack
They were three folders on one laptop: a coding agent with a git history of its
own, and two servers - a development server and a browser - with none at all.
What makes them a stack is what sits between them, and that lived nowhere: the
compose file, the gateway, the egress proxy and the networks that keep the worker
off the internet. So the whole thing is one repository, and the coding agent's
separate history is folded into it rather than kept alongside.

What is deliberately absent: .env, node_modules, and the live service
definitions. The .example files next to them say what belongs there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 11:45:55 +02:00
..
deploy Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
examples Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
src Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
test Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
.env.example Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
Dockerfile Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
README.md Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
docker-compose.yml Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00
package.json Bring the three MCP servers together as one deployable stack 2026-09-22 11:45:55 +02:00

README.md

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_KEYS to SUBJECT=TOKEN entries 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 sessions optional workspaceSubpath is 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_ORIGINS to 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=local only 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/workspace

The runtime needs the selected tool installed. The supplied Docker image contains Python 3 and pytest.

Remote hardened deployment

  1. Copy .env.example to .env and set a long random API token.
  2. Create a dedicated workspace directory; do not mount a home directory, source checkout, Docker socket, or secrets.
  3. Make that directory writable by CODING_AGENT_UID:CODING_AGENT_GID.
  4. 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).

  • Send an MCP initialize JSON-RPC request to POST /mcp. The response includes Mcp-Session-Id.
  • Send subsequent MCP requests to POST /mcp with that Mcp-Session-Id header.
  • Use DELETE /mcp with Mcp-Session-Id to terminate the session.
  • GET /mcp with Mcp-Session-Id opens an optional server-to-client SSE stream.

Legacy SSE

  • GET /sse opens the former MCP SSE transport. It emits an endpoint event for posting messages.
  • For automatic legacy-client fallback, GET /mcp without Mcp-Session-Id provides the same SSE handshake.
  • The pre-existing custom transport is retained: GET /events returns x-session-id; send it on POST /mcp as x-session-id.
  • Bind x-workspace-subpath only when opening or initializing a session; it cannot change afterward.
  • GET /health reports server health.

Development

npm test