You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

3.7 KiB

AGENTS.md

This repo is not an application. It is a local MCP server stack: a docker-compose file that runs AI-coding-tool helpers in Docker so opencode, crush, and VS Code plugins (Cline/Roo/Kilo) can all share the same local services over Streamable HTTP. There is no app source, no test suite, no linter — verification is manual (health endpoints, MCP handshakes, opencode mcp list).

Commands

cp .env.example .env        # once; add BRAVE_API_KEY
./add-project.sh <repo>     # register a project for code indexing (idempotent; starts stack)
./add-project.sh --remove <repo-or-slug>
docker compose up -d --build
docker compose --profile embeddings up -d   # same + ollama embeddings container
docker compose ps / logs -f mcp / logs -f mcp-codebase-index
opencode reload && sleep 3 && opencode mcp list   # acceptance check

Architecture

Two services, one image (Dockerfile, node:24-slim: supergateway@4 + open-codebase-index + context7/brave/mcp-server-fetch preinstalled, glibc because the index ships NAPI binaries — do not switch the base to alpine):

  • mcp-gateway (:8000) — supergateway --config supergateway.config.jsonc; one endpoint per shared tool: /fetch/mcp, /context7/mcp, /brave-search/mcp (edit the jsonc to add servers, then docker compose restart mcp).
  • mcp-codebase-index (:8001) — supergateway --config supergateway.projects.jsonc (GENERATED by add-project.sh from projects.env; do not hand-edit, re-run the script). One endpoint per registered project: /<slug>/mcp. Mounts PROJECTS_ROOT (default ~/src, kept in .env) at the identical container path so index results return valid host paths. Runs as user: node (uid 1000) so index data is host-user owned. Index data lives in each project at .opencode/index/ (hybrid mode: BM25 + call graph + ollama nomic-embed-text embeddings; the ollama container ships dormant behind the embeddings profile and indexing degrades to keyword-only while it is off).

Per-project client configs (written into each project by add-project.sh): opencode.json, .crush.json, .roo/mcp.json, each pointing at http://localhost:8001/<slug>/mcp. Global client configs only carry the shared tools (fetch/context7/brave-search).

Gotchas

  • Host docker networking: the Arch host's default docker0 bridge has NO egress (DNS/TCP fail), so there BUILD_NETWORK=host is set in .env. On hosts with a working bridge leave it unset — newer compose delegates builds to buildx bake, which rejects network: host ("Pass --allow=network.host...") and compose cannot grant the entitlement.
  • The ollama container is profile-gated: plain docker compose up -d / down ignore it. INDEXING WARNING: N chunks failed to embed in index output means ollama was down or a batch exceeded the 30s embedding timeout — search falls back to keyword ranking until a re-index succeeds. Batches are pre-tuned small (OLLAMA_MAX_BATCH_TOKENS / OLLAMA_MAX_BATCH_ITEMS env on mcp-codebase-index) for CPU-only ollama.
  • opencode mcp list can print "No MCP servers configured" for a few seconds after opencode reload (daemon reconnects asynchronously). Retry before assuming breakage.
  • After changing client configs, crush/opencode sessions must be restarted/reloaded; VS Code plugins need the workspace reopened.
  • supergateway.projects.jsonc, projects.env, .env are gitignored and machine-specific. docker-compose.override.yml (if present) is the documented way to mount extra project roots.
  • supergateway runs stateful Streamable HTTP; each client session spawns its own stdio server process (nothing idles; index data persists on disk between sessions).
  • Add brief imperative commit messages; keep disabled blocks commented rather than deleted.