coder: let the omp harness drive workspaces over Coders MCP server

Coder ships `coder exp mcp server` and omp is an MCP client, so the two compose
with no custom code. The agent stays on the host where its credentials already
live and reaches into the workspace, rather than shipping secrets into a
container.

- scripts/coder-mcp.sh wraps the server, passing a dedicated `omp-mcp` token via
  `docker exec --env-file` (mode 600 temp file, shredded by an EXIT trap) so the
  token never appears in argv or ps
- allow-list exposes 26 of 32 tools; template mutation is excluded because
  pushing a template is the one real path from a Coder principal to the host
  docker socket
- scripts/coder-token-rotate.sh handles the 168h token lifetime cap: mint,
  verify against the API, then revoke the predecessors
- .omp/mcp.json registers it project-scoped so 26 tools do not load into every
  unrelated omp session

The docker exec must stay in the foreground: backgrounding it makes bash
redirect stdin from /dev/null with job control disabled, and the MCP transport
dies on EOF with "MCP tool load failed ... Transport closed".

Verified: fresh omp session in this directory answered from the tools -
coder_get_authenticated_user returned loca, workspace ws1 running.
This commit is contained in:
Antigravity
2026-08-20 17:46:51 +02:00
parent 0e54b86dac
commit 3478e7b913
8 changed files with 185 additions and 2 deletions

View File

@@ -14,7 +14,12 @@ reviewed: 2026-08-19
| `/home/loca/dev/coder/` | stack root; compose project name `coder` derives from this directory name | `loca`; run every compose command from here |
| `/home/loca/dev/coder/docker-compose.yml` | the whole deployment definition: images, pins, ports, env, volumes, memory ceilings | `loca`; edit here, never with `docker run` flags |
| `/home/loca/dev/coder/.env` | supplies `CODER_PG_PASSWORD` to compose interpolation | `loca`, mode 600, git-ignored; contents are never read into or quoted by any document |
| `/home/loca/dev/coder/.gitignore` | ignores `.env`, `q5vault/.obsidian/`, and terraform working state under `templates/` | `loca`; keeps the secret, editor state and tfstate out of version control while the provider lockfile stays committed |
| `/home/loca/dev/coder/.mcp-token` | dedicated Coder token named `omp-mcp`, consumed by `scripts/coder-mcp.sh` so the omp harness can call Coder's MCP tools | `loca`, mode 600, git-ignored; 168h maximum lifetime, rotate with `scripts/coder-token-rotate.sh` |
| `/home/loca/dev/coder/.omp/mcp.json` | project-scoped MCP registration; mounts the `coder` server only when omp runs in this directory | `loca`; holds no secret, the token is read by the wrapper |
| `/home/loca/dev/coder/scripts/coder-mcp.sh` | wraps `coder exp mcp server` with `docker exec --env-file` credential passing and a 26-tool allow-list that excludes template mutation | `loca`, mode 755; must run the docker exec in the foreground or the MCP transport dies on EOF |
| `/home/loca/dev/coder/scripts/coder-token-rotate.sh` | mints a replacement `omp-mcp` token, verifies it against the API, then revokes the previous ones | `loca`, mode 755; run weekly |
| `/home/loca/dev/coder/scripts/backup-stacks.sh` | nightly backup driver for both stacks, invoked by `stacks-backup.service` | `loca`, mode 755; runs as root from the timer, so no `sudo` inside |
| `/home/loca/dev/coder/.gitignore` | ignores `.env`, `.admin-credentials`, `.mcp-token`, `q5vault/.obsidian/`, and terraform working state under `templates/` | `loca`; keeps secrets, editor state and tfstate out of version control while the provider lockfile stays committed |
| `/home/loca/dev/coder/config/runtime-version.txt` | plain-text pin, currently `v2.35.3`; the human-readable twin of the image tag | `loca`; changes in the same commit as the tag |
| `/home/loca/dev/coder/deploy/code.nginx.conf` | source of truth for the four nginx server blocks | `loca`; the installed site file is a copy, so edit here first |
| `/home/loca/dev/coder/templates/docker/main.tf` | pre-validated docker workspace template; one `coder_app` at `subdomain = false`, persistent `/home/coder` volume, no docker socket in the workspace | `loca`; pushed by the operator with `coder templates push` |