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.
 
 

12 KiB

mcp-supergateway

A local toolbox for AI coding assistants, running in Docker.

AI coding tools — opencode, crush, VS Code's Cline, Roo Code, Kilo Code — can all use extra abilities (fetch a web page, search the web, read library docs, search a codebase) through a standard plug system called MCP. Every ability is a small server program that normally has to be installed and run separately for each tool.

This repo runs those servers once per machine, in Docker, and gives each one a simple local web address. Every AI tool on your computer then shares the same services — no Node.js, no Python, nothing to install on the host.

The idea in one picture

 your AI tools                          this docker-compose stack
 ┌─────────────┐
 │  opencode   │───┐
 │  crush      │   │    http://localhost:8000/fetch/mcp         ┌────────────────────┐
 │  Cline      │   ├───►http://localhost:8000/context7/mcp  ──► │  mcp-gateway       │
 │  Roo / Kilo │   │    http://localhost:8000/brave-search/mcp  │  (shared tools)    │
 └─────────────┘   │                                            └────────────────────┘
                   │    http://localhost:8001/supergateway/mcp
                   └───►http://localhost:8001/yazi/mcp        ──► ┌────────────────────┐
                        http://localhost:8001/<project>/mcp       │  mcp-codebase-index│
                                                                  │  (one endpoint per │
                                                                  │   code project)    │
                                                                  └────────────────────┘

Two containers do all the work:

  • mcp-gateway (port 8000) — always-useful helpers, shared by every tool: web fetch, library docs via context7, web search via brave (needs a free API key).
  • mcp-codebase-index (port 8001) — a private search index for each of your code projects, built with open-codebase-index. It lets the AI find things in a large codebase quickly (keyword search, "where is this defined", "who calls this") instead of reading files one by one. Every project gets its own address: http://localhost:8001/<project>/mcp.

Quick start (once per machine)

git clone <this repo> && cd supergateway
cp .env.example .env      # put your BRAVE_API_KEY in it (https://brave.com/search/api/)
./add-project.sh .        # registers this repo as the first indexed project and starts everything

./add-project.sh . builds the Docker image, starts both containers, indexes this repository, and writes a few small config files into it (see below). Check that it worked:

docker compose ps                       # both containers should be "Up"
curl http://localhost:8000/healthz      # -> ok
curl http://localhost:8001/healthz      # -> ok

Indexing your own projects — the one command you'll actually use

From this repo, run:

./add-project.sh ~/src/git/my-project

That single command:

  1. remembers the project in projects.env (the list of indexed repositories),
  2. gives it its own address: http://localhost:8001/my-project/mcp,
  3. builds its search index (stored inside the project at .opencode/index/ — disposable, rebuilt anytime, gitignored),
  4. writes three tiny config files into the project, each pointing at that address:
    • opencode.json — opencode reads this automatically when started in that directory
    • .crush.json — crush reads this automatically when started in that directory
    • .roo/mcp.json — Roo Code / Cline / Kilo Code workspace config (commit them — teammates who run this stack get the same behavior for free),
  5. adds .opencode/ to the project's .gitignore.

Why this is nice: you never re-configure your tools when switching projects. Open a project → the AI tool automatically finds that project's index. Work on three projects at the same time — each has its own address and its own index, nothing interferes.

Rules of the game:

  • the project must be a git repository (the index is branch-aware and needs git),
  • it must live under PROJECTS_ROOT (default ~/src, set in .env — the script configures this for you). Projects elsewhere need one extra volume mount, see Troubleshooting.

To stop indexing a project: ./add-project.sh --remove ~/src/git/my-project (index data and the small config files are left in the project; delete them if you want).

For "how does repo X use repo Y" questions you can also attach neighboring repositories to the current project as knowledge bases (the add_knowledge_base tool) — they get searched alongside the project's own code.

Pointing your tools at the stack (once per tool)

The shared tools (port 8000) are configured once, globally. Per-project indexes (port 8001) need no global configuration at all — each project carries its own config files, written by add-project.sh.

opencode

~/.config/opencode/opencode.jsonc:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "fetch": { "type": "remote", "url": "http://localhost:8000/fetch/mcp", "enabled": true },
    "context7": { "type": "remote", "url": "http://localhost:8000/context7/mcp", "enabled": true },
    "brave-search": { "type": "remote", "url": "http://localhost:8000/brave-search/mcp", "enabled": true }
  }
}

Verify from any indexed project directory: opencode mcp list → four servers connected (three above + codebase-index from the project's own opencode.json). If opencode was already running there, run opencode reload first and give it a few seconds.

crush

~/.config/crush/crush.json:

{
  "$schema": "https://charm.land/crush.json",
  "mcp": {
    "fetch": { "type": "http", "url": "http://localhost:8000/fetch/mcp" },
    "context7": { "type": "http", "url": "http://localhost:8000/context7/mcp" },
    "brave-search": { "type": "http", "url": "http://localhost:8000/brave-search/mcp" }
  }
}

crush picks up each project's .crush.json automatically (restart crush in that directory).

Cline / Roo Code / Kilo Code (VS Code)

Each indexed project already contains a workspace .roo/mcp.json (written by add-project.sh), so opening the project in Roo Code just works. To also get the shared tools everywhere, add them once to your plugin's global settings file:

Plugin Global config file (Linux)
Cline ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
Roo Code ~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json
Kilo Code ~/.config/Code/User/globalStorage/kilocode.kilo-code/settings/mcp_settings.json
{
  "mcpServers": {
    "fetch": { "type": "streamableHttp", "url": "http://localhost:8000/fetch/mcp", "disabled": false },
    "context7": { "type": "streamableHttp", "url": "http://localhost:8000/context7/mcp", "disabled": false },
    "brave-search": { "type": "streamableHttp", "url": "http://localhost:8000/brave-search/mcp", "disabled": false }
  }
}

What the code index actually searches

By default the index runs in structural mode: keyword (BM25) search, symbol definitions, call graphs, branch awareness — entirely offline, no AI provider needed. This is usually plenty and it works out of the box.

To add semantic search ("find code by meaning"), plug in an embedding provider:

  1. Start local Ollama embeddings: docker compose --profile embeddings up -d ollama, then docker compose exec ollama ollama pull nomic-embed-text.

  2. In codebase-index.config.json switch "mode": "structural" to "hybrid" and add:

    {
      "embeddingProvider": "custom",
      "customProvider": {
        "baseUrl": "http://ollama:11434/v1",
        "model": "nomic-embed-text",
        "dimensions": 768
      }
    }
    
  3. Rebuild each project's index:

    docker compose exec mcp-codebase-index ocbi index --project ~/src/git/my-project --config /etc/codebase-index/config.json --force
    

(Or ask the AI to run the index_codebase / index_status tools — rebuilding and refreshing indexes is something the assistants can do themselves through MCP.)

Everyday commands

docker compose ps                                      # status
docker compose logs -f mcp                             # shared-tools gateway logs
docker compose logs -f mcp-codebase-index              # index gateway logs (per-project lines prefixed)
docker compose restart mcp mcp-codebase-index          # after editing supergateway.config.jsonc / codebase-index.config.json
docker compose down                                    # stop everything (index data survives, it lives in the projects)

Adding or removing shared tools (port 8000)

Edit supergateway.config.jsonc — each entry becomes http://localhost:8000/<name>/mcp. Any stdio MCP server works:

"memory": {
  "stdio": "npx -y @modelcontextprotocol/server-memory"
}

Then docker compose restart mcp. Servers started via npx need outbound network from the container on first use.

How it works under the hood (curious readers)

  • One image (built from Dockerfile, node:24-slim) runs both services: supergateway v4 plus the bundled MCP servers, and open-codebase-index.
  • Both gateways speak Streamable HTTP (the current MCP transport) with sessions, so any modern client can connect.
  • The index gateway mounts your PROJECTS_ROOT into the container at the same path it has on the host — so every file path the index reports is a real path you (and your AI tool) can open.
  • Each project's index server process is started per client session and dies when the client disconnects; the index data on disk persists, so reconnects are incremental. Registering 20 projects does not mean 20 idle processes.
  • Index data is stored per project in .opencode/index/ — the same layout the native open-codebase-index uses — and is safe to delete at any time (it gets rebuilt).

Troubleshooting

curl http://localhost:8000/healthz   # -> ok   (shared tools gateway)
curl http://localhost:8001/healthz   # -> ok   (index gateway)
docker compose ps                    # both services "Up"
  • opencode mcp list says "No MCP servers configured" right after opencode reload — the background service reconnects asynchronously; wait 2–3 seconds and run it again.

  • Project lives outside PROJECTS_ROOT — create a docker-compose.override.yml next to docker-compose.yml in this repo, mounting the extra root at its own path:

    services:
      mcp-codebase-index:
        volumes:
          - /opt/code:/opt/code
    

    then run docker compose up -d mcp-codebase-index and register the project with ./add-project.sh /opt/code/whatever.

  • Docker build fails with Temporary failure resolving ... — the default docker bridge has no internet access on that host. Add BUILD_NETWORK=host to .env and rebuild. Note that recent docker compose versions delegate builds to buildx bake, which refuses network: host builds with "Pass --allow=network.host..." unless the host really needs it — on machines with working bridge networking leave BUILD_NETWORK unset (or set it to default). If it still fails, check your firewall.

  • brave-search tools fail — missing/invalid BRAVE_API_KEY in .env.

  • Index seems stale — re-run the project's index: ./add-project.sh ~/src/git/my-project (safe to repeat), or ask the AI to run index_codebase.

  • Index data owned by root / permission errors — the index container runs as uid 1000. If your user has a different uid, set user: "<uid>:<gid>" on the mcp-codebase-index service in docker-compose.yml.