13 changed files with 824 additions and 247 deletions
@ -0,0 +1,10 @@ |
|||||||
|
{ |
||||||
|
"$schema": "https://charm.land/crush.json", |
||||||
|
"mcp": { |
||||||
|
"codebase-index": { |
||||||
|
"type": "http", |
||||||
|
"url": "http://localhost:8001/supergateway/mcp", |
||||||
|
"timeout": 600000 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
# API key for the brave-search MCP server (https://brave.com/search/api/) |
||||||
|
BRAVE_API_KEY= |
||||||
|
|
||||||
|
# Optional: comma-separated list of brave search tools to expose |
||||||
|
# BRAVE_MCP_ENABLED_TOOLS= |
||||||
|
|
||||||
|
# Root directory that contains all repositories you want code-indexed. |
||||||
|
# add-project.sh sets this automatically (default: $HOME/src); projects |
||||||
|
# outside this directory need an extra volume mount (see README). |
||||||
|
# PROJECTS_ROOT=/home/you/src |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
{ |
||||||
|
"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 |
||||||
|
}, |
||||||
|
"codebase-index": { |
||||||
|
"type": "streamableHttp", |
||||||
|
"url": "http://localhost:8001/supergateway/mcp", |
||||||
|
"disabled": false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
# 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 |
||||||
|
|
||||||
|
```bash |
||||||
|
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 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/` (structural mode: BM25 + call graph, |
||||||
|
no embedding provider; ollama upgrade documented in README). |
||||||
|
|
||||||
|
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 is partly broken**: the default docker0 bridge has NO egress |
||||||
|
(DNS/TCP fail); custom compose networks work fine. That is why builds use |
||||||
|
`network: host` in the compose file — keep it. |
||||||
|
- `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. |
||||||
@ -1,36 +1,268 @@ |
|||||||
# mcp-supergateway |
# mcp-supergateway |
||||||
|
|
||||||
Dockerized [supergateway](https://www.npmjs.com/package/supergateway) image bundling several popular |
A local toolbox for AI coding assistants, running in Docker. |
||||||
MCP servers (fetch, google-maps, context7, puppeteer, excel, brave-search, ...) so each one can be |
|
||||||
exposed as an SSE endpoint via docker-compose. |
|
||||||
|
|
||||||
## Usage |
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. |
||||||
|
|
||||||
1. Copy `.env.example` (or create `.env`) and fill in the API keys the services you enable require. |
This repo runs those servers **once per machine, in Docker**, and gives each one a simple |
||||||
2. Start the stack: |
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](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch), |
||||||
|
[library docs via context7](https://github.com/upstash/context7), |
||||||
|
[web search via brave](https://github.com/brave/brave-search-mcp-server) (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](https://github.com/Helweg/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) |
||||||
|
|
||||||
```bash |
```bash |
||||||
docker compose up -d |
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: |
||||||
|
|
||||||
|
```bash |
||||||
|
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: |
||||||
|
|
||||||
|
```bash |
||||||
|
./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](#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`: |
||||||
|
|
||||||
|
```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`: |
||||||
|
|
||||||
|
```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" } |
||||||
|
} |
||||||
|
} |
||||||
``` |
``` |
||||||
|
|
||||||
3. Point any MCP-compatible client at the exposed SSE endpoints (one per service/port defined in |
crush picks up each project's `.crush.json` automatically (restart crush in that |
||||||
`docker-compose.yml`). |
directory). |
||||||
|
|
||||||
## Client configuration |
### Cline / Roo Code / Kilo Code (VS Code) |
||||||
|
|
||||||
Example of connecting an SSE-capable MCP client: |
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` | |
||||||
|
|
||||||
```json |
```json |
||||||
{ |
{ |
||||||
"mcpServers": { |
"mcpServers": { |
||||||
"fetch": { |
"fetch": { "type": "streamableHttp", "url": "http://localhost:8000/fetch/mcp", "disabled": false }, |
||||||
"type": "sse", |
"context7": { "type": "streamableHttp", "url": "http://localhost:8000/context7/mcp", "disabled": false }, |
||||||
"url": "http://localhost:8001/sse" |
"brave-search": { "type": "streamableHttp", "url": "http://localhost:8000/brave-search/mcp", "disabled": false } |
||||||
}, |
|
||||||
"brave-search": { |
|
||||||
"type": "sse", |
|
||||||
"url": "http://localhost:8010/sse" |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
``` |
||||||
|
|
||||||
|
## 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: |
||||||
|
|
||||||
|
```json |
||||||
|
{ |
||||||
|
"embeddingProvider": "custom", |
||||||
|
"customProvider": { |
||||||
|
"baseUrl": "http://ollama:11434/v1", |
||||||
|
"model": "nomic-embed-text", |
||||||
|
"dimensions": 768 |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
3. Rebuild each project's index: |
||||||
|
|
||||||
|
```bash |
||||||
|
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 |
||||||
|
|
||||||
|
```bash |
||||||
|
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: |
||||||
|
|
||||||
|
```jsonc |
||||||
|
"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](https://github.com/supercorp-ai/supergateway) v4 plus the bundled MCP |
||||||
|
servers, and [open-codebase-index](https://github.com/Helweg/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 |
||||||
|
|
||||||
|
```bash |
||||||
|
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: |
||||||
|
|
||||||
|
```yaml |
||||||
|
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 ...`** — on this host the default |
||||||
|
docker bridge has no internet access; builds already run with `network: host` in the |
||||||
|
compose file. 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`. |
||||||
|
|||||||
@ -0,0 +1,325 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# |
||||||
|
# Register (or remove) a project repository with the local MCP codebase-index |
||||||
|
# gateway managed by this repo's docker-compose stack. |
||||||
|
# |
||||||
|
# ./add-project.sh <path-to-repo> [slug] |
||||||
|
# ./add-project.sh --remove <path-or-slug> |
||||||
|
# |
||||||
|
# What "register" does: |
||||||
|
# 1. records the project in projects.env (slug=path) - the list of indexed repos |
||||||
|
# 2. regenerates supergateway.projects.jsonc - one MCP endpoint per project: |
||||||
|
# http://localhost:8001/<slug>/mcp |
||||||
|
# 3. recreates the mcp-codebase-index container with the updated config |
||||||
|
# 4. builds the initial code index (keyword + call graph, works offline) |
||||||
|
# 5. writes AI-client config snippets INTO the project repo so every tool |
||||||
|
# finds its index automatically when opened in that directory: |
||||||
|
# opencode.json (opencode project config) |
||||||
|
# .crush.json (crush project config) |
||||||
|
# .roo/mcp.json (Roo Code / Cline / Kilo Code workspace config) |
||||||
|
# and adds ".opencode/" to the project's .gitignore (index data lives there) |
||||||
|
# |
||||||
|
set -euo pipefail |
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
||||||
|
cd "$REPO_DIR" |
||||||
|
|
||||||
|
PROJECTS_ENV="$REPO_DIR/projects.env" |
||||||
|
GENERATED_CONFIG="$REPO_DIR/supergateway.projects.jsonc" |
||||||
|
GATEWAY_PORT=8001 |
||||||
|
INDEX_CONFIG=/etc/codebase-index/config.json |
||||||
|
SERVICE=mcp-codebase-index |
||||||
|
|
||||||
|
die() { echo "ERROR: $*" >&2; exit 1; } |
||||||
|
note() { echo; echo "== $*"; } |
||||||
|
|
||||||
|
http_get() { |
||||||
|
if command -v curl >/dev/null 2>&1; then |
||||||
|
curl -fsS -m 3 "$1" 2>/dev/null || true |
||||||
|
elif command -v wget >/dev/null 2>&1; then |
||||||
|
wget -qO- -T 3 "$1" 2>/dev/null || true |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
slugify() { |
||||||
|
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/^-+//; s/-+$//' |
||||||
|
} |
||||||
|
|
||||||
|
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' <<<"$1"; } |
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
# projects.env helpers |
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
|
||||||
|
env_get() { # env_get <path> -> slug (or empty) |
||||||
|
local p line key val |
||||||
|
p="$1" |
||||||
|
[[ -f "$PROJECTS_ENV" ]] || return 0 |
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do |
||||||
|
[[ -z "$line" || "$line" == \#* ]] && continue |
||||||
|
key="${line%%=*}"; val="${line#*=}" |
||||||
|
[[ "$val" == "$p" ]] && { echo "$key"; return 0; } |
||||||
|
done < "$PROJECTS_ENV" |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
env_set() { # env_set <slug> <path> (idempotent, keeps order) |
||||||
|
local slug="$1" path="$2" tmp line key val |
||||||
|
tmp="$(mktemp)" |
||||||
|
[[ -f "$PROJECTS_ENV" ]] || touch "$PROJECTS_ENV" |
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do |
||||||
|
if [[ -z "$line" || "$line" == \#* ]]; then printf '%s\n' "$line" >> "$tmp"; continue; fi |
||||||
|
key="${line%%=*}"; val="${line#*=}" |
||||||
|
# drop lines that match either the same path or the same slug |
||||||
|
[[ "$val" == "$path" || "$key" == "$slug" ]] && continue |
||||||
|
printf '%s\n' "$line" >> "$tmp" |
||||||
|
done < "$PROJECTS_ENV" |
||||||
|
printf '%s=%s\n' "$slug" "$path" >> "$tmp" |
||||||
|
mv "$tmp" "$PROJECTS_ENV" |
||||||
|
} |
||||||
|
|
||||||
|
env_del() { # env_del <slug-or-path> |
||||||
|
local target="$1" tmp line key val |
||||||
|
tmp="$(mktemp)" |
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do |
||||||
|
if [[ -z "$line" || "$line" == \#* ]]; then printf '%s\n' "$line" >> "$tmp"; continue; fi |
||||||
|
key="${line%%=*}"; val="${line#*=}" |
||||||
|
[[ "$val" == "$target" || "$key" == "$target" ]] && continue |
||||||
|
printf '%s\n' "$line" >> "$tmp" |
||||||
|
done < "$PROJECTS_ENV" |
||||||
|
mv "$tmp" "$PROJECTS_ENV" |
||||||
|
} |
||||||
|
|
||||||
|
regenerate_config() { |
||||||
|
local line slug path first=1 |
||||||
|
{ |
||||||
|
echo "// GENERATED by add-project.sh from projects.env - do not edit by hand." |
||||||
|
echo "// Each project is served at http://localhost:${GATEWAY_PORT}/<slug>/mcp" |
||||||
|
echo "// Re-run ./add-project.sh after editing projects.env." |
||||||
|
echo "{" |
||||||
|
echo " \"outputTransport\": \"streamableHttp\"," |
||||||
|
echo " \"stateful\": true," |
||||||
|
echo " \"sessionTimeout\": 3600000," |
||||||
|
echo " \"mcpServers\": {" |
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do |
||||||
|
[[ -z "$line" || "$line" == \#* ]] && continue |
||||||
|
slug="${line%%=*}"; path="${line#*=}" |
||||||
|
[[ -z "$slug" || -z "$path" ]] && continue |
||||||
|
[[ $first -eq 0 ]] && echo "," |
||||||
|
first=0 |
||||||
|
printf ' "%s": { "stdio": "open-codebase-index-mcp --config %s --project %s" }' \ |
||||||
|
"$(json_escape "$slug")" "$INDEX_CONFIG" "$(json_escape "$path")" |
||||||
|
done < "$PROJECTS_ENV" |
||||||
|
echo "" |
||||||
|
echo " }" |
||||||
|
echo "}" |
||||||
|
} > "$GENERATED_CONFIG" |
||||||
|
} |
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
# .env bootstrap |
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
|
||||||
|
ensure_env() { |
||||||
|
if [[ ! -f "$REPO_DIR/.env" ]]; then |
||||||
|
cp "$REPO_DIR/.env.example" "$REPO_DIR/.env" 2>/dev/null || touch "$REPO_DIR/.env" |
||||||
|
echo "Created .env (remember to set BRAVE_API_KEY there)." |
||||||
|
fi |
||||||
|
if ! grep -qE '^PROJECTS_ROOT=' "$REPO_DIR/.env"; then |
||||||
|
printf 'PROJECTS_ROOT=%s\n' "${PROJECTS_ROOT:-$HOME/src}" >> "$REPO_DIR/.env" |
||||||
|
echo "Set PROJECTS_ROOT=${PROJECTS_ROOT:-$HOME/src} in .env" |
||||||
|
fi |
||||||
|
PROJECTS_ROOT="$(grep -E '^PROJECTS_ROOT=' "$REPO_DIR/.env" | tail -1 | cut -d= -f2-)" |
||||||
|
[[ -d "$PROJECTS_ROOT" ]] || die "PROJECTS_ROOT=$PROJECTS_ROOT does not exist (edit .env)." |
||||||
|
} |
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
# client config snippets written into the target project |
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
|
||||||
|
write_client_config() { # write_client_config <file> <fresh-content> <jq-merge-expr> <url> |
||||||
|
local file="$1" fresh="$2" merge="$3" url="$4" |
||||||
|
mkdir -p "$(dirname "$file")" |
||||||
|
if [[ -f "$file" ]]; then |
||||||
|
if command -v jq >/dev/null 2>&1; then |
||||||
|
if jq --arg u "$url" "$merge" "$file" > "$file.tmp" 2>/dev/null; then |
||||||
|
mv "$file.tmp" "$file" |
||||||
|
echo " updated $file" |
||||||
|
else |
||||||
|
rm -f "$file.tmp" |
||||||
|
echo " NOTE: could not merge into $file (invalid JSON?) - add manually:" |
||||||
|
echo " codebase-index -> $url" |
||||||
|
fi |
||||||
|
else |
||||||
|
echo " NOTE: $file exists and jq is not installed - merge manually:" |
||||||
|
echo " codebase-index -> $url" |
||||||
|
fi |
||||||
|
else |
||||||
|
printf '%s\n' "$fresh" > "$file" |
||||||
|
echo " created $file" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
write_project_configs() { # write_project_configs <project-dir> <slug> |
||||||
|
local dir="$1" slug="$2" |
||||||
|
local url="http://localhost:${GATEWAY_PORT}/${slug}/mcp" |
||||||
|
|
||||||
|
write_client_config "$dir/opencode.json" \ |
||||||
|
"{ |
||||||
|
\"\$schema\": \"https://opencode.ai/config.json\", |
||||||
|
\"mcp\": { |
||||||
|
\"codebase-index\": { |
||||||
|
\"type\": \"remote\", |
||||||
|
\"url\": \"$url\", |
||||||
|
\"enabled\": true, |
||||||
|
\"timeout\": 600000 |
||||||
|
} |
||||||
|
} |
||||||
|
}" \ |
||||||
|
'.mcp = ((.mcp // {}) | ."codebase-index" = {type:"remote", url:$u, enabled:true, timeout:600000})' \ |
||||||
|
"$url" |
||||||
|
|
||||||
|
write_client_config "$dir/.crush.json" \ |
||||||
|
"{ |
||||||
|
\"\$schema\": \"https://charm.land/crush.json\", |
||||||
|
\"mcp\": { |
||||||
|
\"codebase-index\": { |
||||||
|
\"type\": \"http\", |
||||||
|
\"url\": \"$url\", |
||||||
|
\"timeout\": 600000 |
||||||
|
} |
||||||
|
} |
||||||
|
}" \ |
||||||
|
'.mcp = ((.mcp // {}) | ."codebase-index" = {type:"http", url:$u, timeout:600000})' \ |
||||||
|
"$url" |
||||||
|
|
||||||
|
write_client_config "$dir/.roo/mcp.json" \ |
||||||
|
"{ |
||||||
|
\"mcpServers\": { |
||||||
|
\"codebase-index\": { |
||||||
|
\"type\": \"streamableHttp\", |
||||||
|
\"url\": \"$url\", |
||||||
|
\"disabled\": false |
||||||
|
} |
||||||
|
} |
||||||
|
}" \ |
||||||
|
'.mcpServers = ((.mcpServers // {}) | ."codebase-index" = {type:"streamableHttp", url:$u, disabled:false})' \ |
||||||
|
"$url" |
||||||
|
|
||||||
|
if [[ -f "$dir/.gitignore" ]] && ! grep -qE '^\.opencode/?$' "$dir/.gitignore"; then |
||||||
|
printf '\n# codebase index data (dockerized open-codebase-index)\n.opencode/\n' >> "$dir/.gitignore" |
||||||
|
echo " updated .gitignore (.opencode/)" |
||||||
|
elif [[ ! -f "$dir/.gitignore" ]]; then |
||||||
|
printf '.opencode/\n' > "$dir/.gitignore" |
||||||
|
echo " created .gitignore (.opencode/)" |
||||||
|
fi |
||||||
|
} |
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
# commands |
||||||
|
# --------------------------------------------------------------------------- |
||||||
|
|
||||||
|
cmd_remove() { |
||||||
|
local target="${1:-}" |
||||||
|
[[ -n "$target" ]] || die "usage: $0 --remove <path-or-slug>" |
||||||
|
if [[ -d "$target" ]]; then target="$(realpath -e "$target")"; fi |
||||||
|
[[ -f "$PROJECTS_ENV" ]] || die "no projects registered yet" |
||||||
|
env_del "$target" |
||||||
|
regenerate_config |
||||||
|
note "Recreating the index gateway" |
||||||
|
docker compose up -d --build >/dev/null |
||||||
|
echo "Removed '$target' from the index gateway." |
||||||
|
echo "Left in place (safe to delete by hand): client config snippets in the" |
||||||
|
echo "project (opencode.json / .crush.json / .roo/mcp.json) and its .opencode/ index data." |
||||||
|
} |
||||||
|
|
||||||
|
cmd_add() { |
||||||
|
local target="${1:-}" slug="${2:-}" |
||||||
|
[[ -n "$target" ]] || die "usage: $0 <path-to-repo> [slug]" |
||||||
|
target="$(realpath -e "$target")" || die "path not found: $target" |
||||||
|
[[ -d "$target/.git" ]] || die "not a git repository: $target (the index is branch-aware and needs git)" |
||||||
|
|
||||||
|
ensure_env |
||||||
|
|
||||||
|
[[ "$target" == "$PROJECTS_ROOT" || "$target" == "$PROJECTS_ROOT"/* ]] || { |
||||||
|
die "$target is not under PROJECTS_ROOT=$PROJECTS_ROOT. |
||||||
|
|
||||||
|
Either move the project under that directory, or expose its parent too: |
||||||
|
create a docker-compose.override.yml next to this compose file containing |
||||||
|
|
||||||
|
services: |
||||||
|
mcp-codebase-index: |
||||||
|
volumes: |
||||||
|
- /extra/root:/extra/root |
||||||
|
|
||||||
|
then add 'PROJECTS_ROOT' style entries by hand in projects.env and re-run this script." |
||||||
|
} |
||||||
|
|
||||||
|
# slug: explicit, or from directory name, deduped against existing entries |
||||||
|
if [[ -z "$slug" ]]; then |
||||||
|
slug="$(slugify "$(basename "$target")")" |
||||||
|
[[ -n "$slug" ]] || slug="project" |
||||||
|
if [[ -n "$(env_get_other_slug "$slug" "$target")" ]]; then |
||||||
|
slug="$(slugify "$(basename "$(dirname "$target")")")-$slug" |
||||||
|
fi |
||||||
|
else |
||||||
|
slug="$(slugify "$slug")" |
||||||
|
[[ -n "$slug" ]] || die "invalid slug" |
||||||
|
fi |
||||||
|
|
||||||
|
local existing; existing="$(env_get "$target")" |
||||||
|
if [[ -n "$existing" && "$existing" != "$slug" ]]; then |
||||||
|
echo "Project already registered as '$existing' - renaming to '$slug'." |
||||||
|
elif [[ -n "$existing" ]]; then |
||||||
|
echo "Project already registered as '$existing' - refreshing." |
||||||
|
fi |
||||||
|
|
||||||
|
env_set "$slug" "$target" |
||||||
|
regenerate_config |
||||||
|
|
||||||
|
note "Starting the stack (first build can take a few minutes)" |
||||||
|
local log; log="$(mktemp)" |
||||||
|
if ! docker compose up -d --build >"$log" 2>&1; then |
||||||
|
tail -n 40 "$log" |
||||||
|
die "docker compose up failed" |
||||||
|
fi |
||||||
|
rm -f "$log" |
||||||
|
|
||||||
|
echo "Waiting for the index gateway..." |
||||||
|
local i ok="" |
||||||
|
for i in $(seq 1 30); do |
||||||
|
[[ "$(http_get "http://localhost:${GATEWAY_PORT}/healthz")" == "ok" ]] && { ok=1; break; } |
||||||
|
sleep 1 |
||||||
|
done |
||||||
|
[[ -n "$ok" ]] || die "index gateway did not become healthy (see: docker compose logs $SERVICE)" |
||||||
|
|
||||||
|
note "Building the code index for $target (keyword + call graph, offline)" |
||||||
|
docker compose exec -T "$SERVICE" ocbi index --project "$target" --config "$INDEX_CONFIG" |
||||||
|
|
||||||
|
note "Writing AI-client config snippets into $target" |
||||||
|
write_project_configs "$target" "$slug" |
||||||
|
|
||||||
|
note "Done" |
||||||
|
echo " MCP endpoint : http://localhost:${GATEWAY_PORT}/${slug}/mcp" |
||||||
|
echo |
||||||
|
echo "Open $target with your AI tool and it picks the config up automatically:" |
||||||
|
echo " opencode / crush : (re)start in that directory, or run 'opencode reload'" |
||||||
|
echo " VS Code (Cline/Roo/Kilo): reopen the workspace" |
||||||
|
} |
||||||
|
|
||||||
|
env_get_other_slug() { # env_get_other_slug <slug> <path> -> prints slug if taken by another path |
||||||
|
local slug="$1" path="$2" line key val |
||||||
|
[[ -f "$PROJECTS_ENV" ]] || return 0 |
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do |
||||||
|
[[ -z "$line" || "$line" == \#* ]] && continue |
||||||
|
key="${line%%=*}"; val="${line#*=}" |
||||||
|
[[ "$key" == "$slug" && "$val" != "$path" ]] && { echo "$key"; return 0; } |
||||||
|
done < "$PROJECTS_ENV" |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
case "${1:-}" in |
||||||
|
--remove|-r) shift; cmd_remove "$@" ;; |
||||||
|
-h|--help) sed -n '2,20p' "$0" ;; |
||||||
|
*) cmd_add "$@" ;; |
||||||
|
esac |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"scope": "project", |
||||||
|
"indexing": { |
||||||
|
"mode": "structural", |
||||||
|
"autoIndex": false, |
||||||
|
"watchFiles": true |
||||||
|
}, |
||||||
|
"search": { |
||||||
|
"maxResults": 20 |
||||||
|
} |
||||||
|
} |
||||||
@ -1,107 +1,75 @@ |
|||||||
version: '3.8' |
name: mcp-supergateway |
||||||
|
|
||||||
# NOTE: remember to fill your .env |
# NOTE: copy this file to .env and fill in the keys for the servers you enable. |
||||||
|
|
||||||
services: |
services: |
||||||
|
|
||||||
mcp-fetch: |
# Multi-server MCP gateway (supergateway --config). |
||||||
image: chodak166/mcp-supergateway |
# One port, one Streamable HTTP endpoint per server: http://localhost:8000/<name>/mcp |
||||||
container_name: mcp-fetch |
# Servers are defined in supergateway.config.jsonc. |
||||||
|
mcp: |
||||||
|
build: |
||||||
|
context: . |
||||||
|
network: host |
||||||
|
image: chodak166/mcp-supergateway:latest |
||||||
|
container_name: mcp-gateway |
||||||
ports: |
ports: |
||||||
- "8001:8000" |
- "8000:8000" |
||||||
command: --stdio "mcp-server-fetch --ignore-robots-txt" |
|
||||||
restart: unless-stopped |
|
||||||
|
|
||||||
# mcp-google-search: |
|
||||||
# image: chodak166/mcp-supergateway |
|
||||||
# ports: |
|
||||||
# - "8002:8000" |
|
||||||
# env_file: |
|
||||||
# - .env |
|
||||||
# command: --stdio "node /opt/google-search-mcp-server/dist/index.js" |
|
||||||
# restart: unless-stopped |
|
||||||
|
|
||||||
mcp-google-maps: |
|
||||||
image: chodak166/mcp-supergateway |
|
||||||
ports: |
|
||||||
- "8003:8000" |
|
||||||
env_file: |
env_file: |
||||||
- .env |
- .env |
||||||
command: --stdio "npx -y @modelcontextprotocol/server-google-maps" |
volumes: |
||||||
restart: unless-stopped |
- ./supergateway.config.jsonc:/etc/supergateway/servers.jsonc:ro |
||||||
|
command: |
||||||
mcp-context7: |
- --config |
||||||
image: chodak166/mcp-supergateway |
- /etc/supergateway/servers.jsonc |
||||||
ports: |
- --healthEndpoint |
||||||
- "8004:8000" |
- /healthz |
||||||
env_file: |
|
||||||
- .env |
|
||||||
command: --stdio "npx -y @upstash/context7-mcp@latest" |
|
||||||
restart: unless-stopped |
restart: unless-stopped |
||||||
|
|
||||||
# mcp-commander: |
# open-codebase-index (https://github.com/Helweg/open-codebase-index) |
||||||
# image: chodak166/mcp-supergateway |
# Serves ONE endpoint per registered project: http://localhost:8001/<slug>/mcp |
||||||
# ports: |
# Projects are registered with ./add-project.sh (list kept in projects.env, |
||||||
# - "8005:8000" |
# gateway config generated into supergateway.projects.jsonc). All projects must |
||||||
# volumes: |
# live under PROJECTS_ROOT (set in .env by add-project.sh), which is mounted at |
||||||
# - ./volumes/mcp/workspace:/app |
# its own host path so tool results return paths valid on the host. |
||||||
# command: --stdio "npx -y @wonderwhy-er/desktop-commander@latest" |
# Each project's index data lives in <project>/.opencode/index/. |
||||||
# restart: unless-stopped |
# The index server process is started per client session; nothing idles. |
||||||
|
mcp-codebase-index: |
||||||
mcp-puppeteer: |
build: |
||||||
image: chodak166/mcp-supergateway |
context: . |
||||||
|
network: host |
||||||
|
image: chodak166/mcp-supergateway:latest |
||||||
|
container_name: mcp-codebase-index |
||||||
|
# Run as the image's `node` user (uid 1000) so index data written into the |
||||||
|
# mounted repos is owned by the host user. |
||||||
|
user: node |
||||||
ports: |
ports: |
||||||
- "8006:8000" |
- "8001:8000" |
||||||
command: --stdio "xvfb-run --server-args='-screen 0 1920x1080x24' -a npx -y @modelcontextprotocol/server-puppeteer" |
volumes: |
||||||
|
- ${PROJECTS_ROOT:?run ./add-project.sh first}:${PROJECTS_ROOT:?run ./add-project.sh first} |
||||||
|
- ./codebase-index.config.json:/etc/codebase-index/config.json:ro |
||||||
|
- ./supergateway.projects.jsonc:/etc/supergateway/projects.jsonc:ro |
||||||
|
command: |
||||||
|
- --config |
||||||
|
- /etc/supergateway/projects.jsonc |
||||||
|
- --healthEndpoint |
||||||
|
- /healthz |
||||||
restart: unless-stopped |
restart: unless-stopped |
||||||
env_file: |
|
||||||
- .env |
|
||||||
|
|
||||||
# mcp-telegram: |
# Optional: local embeddings for semantic (hybrid) codebase indexing. |
||||||
# image: chodak166/mcp-supergateway |
# Start with: docker compose --profile embeddings up -d |
||||||
|
# Then switch indexing.mode to "hybrid" in codebase-index.config.json and set |
||||||
|
# embeddingProvider "custom" with baseUrl http://ollama:11434/v1, |
||||||
|
# model nomic-embed-text, dimensions 768, and run: |
||||||
|
# docker compose exec mcp-codebase-index ocbi index --project $PWD --config /etc/codebase-index/config.json --force |
||||||
|
# ollama: |
||||||
|
# image: ollama/ollama:latest |
||||||
|
# profiles: ["embeddings"] |
||||||
# ports: |
# ports: |
||||||
# - "8007:8000" |
# - "11434:11434" |
||||||
# env_file: |
|
||||||
# - .env |
|
||||||
# working_dir: /app |
|
||||||
# volumes: |
# volumes: |
||||||
# - ./:/app |
# - ollama:/root/.ollama |
||||||
# command: --stdio "npx -y mcptelegram" |
|
||||||
# restart: unless-stopped |
# restart: unless-stopped |
||||||
|
|
||||||
# mcp-filesystem: |
|
||||||
# image: chodak166/mcp-supergateway |
|
||||||
# ports: |
|
||||||
# - "8008:8000" |
|
||||||
# env_file: |
|
||||||
# - .env |
|
||||||
# working_dir: /app |
|
||||||
# volumes: |
# volumes: |
||||||
# - ./:/app |
# ollama: |
||||||
# command: --stdio "npx -y @modelcontextprotocol/server-filesystem /app" |
|
||||||
# restart: unless-stopped |
|
||||||
|
|
||||||
mcp-excel: |
|
||||||
image: chodak166/mcp-supergateway |
|
||||||
ports: |
|
||||||
- "8009:8000" |
|
||||||
volumes: |
|
||||||
- ~/src/mcp-excel:/app |
|
||||||
command: --stdio "npx -y @negokaz/excel-mcp-server" |
|
||||||
restart: unless-stopped |
|
||||||
# |
|
||||||
# mcp-inspector: |
|
||||||
# image: chodak166/mcp-supergateway |
|
||||||
# container_name: mcp-inspector |
|
||||||
# network_mode: host |
|
||||||
# command: --stdio "npx -y @modelcontextprotocol/inspector" |
|
||||||
# restart: unless-stopped |
|
||||||
|
|
||||||
mcp-brave-search: |
|
||||||
image: chodak166/mcp-supergateway |
|
||||||
ports: |
|
||||||
- "8010:8000" |
|
||||||
env_file: |
|
||||||
- .env |
|
||||||
command: --stdio "npx -y @brave/brave-search-mcp-server" |
|
||||||
restart: unless-stopped |
|
||||||
|
|||||||
@ -1,71 +0,0 @@ |
|||||||
{ |
|
||||||
"mcpServers": { |
|
||||||
"fetch": { |
|
||||||
"type": "sse", |
|
||||||
"url": "http://localhost:8001/sse", |
|
||||||
"disabled": false, |
|
||||||
"alwaysAllow": [ |
|
||||||
"fetch" |
|
||||||
] |
|
||||||
}, |
|
||||||
"google-search": { |
|
||||||
"url": "http://localhost:8002/sse", |
|
||||||
"disabled": true, |
|
||||||
"alwaysAllow": [ |
|
||||||
"google_search" |
|
||||||
] |
|
||||||
}, |
|
||||||
"telegram": { |
|
||||||
"url": "http://localhost:8003/sse", |
|
||||||
"disabled": true, |
|
||||||
"alwaysAllow": [] |
|
||||||
}, |
|
||||||
"context7": { |
|
||||||
"url": "http://localhost:8004/sse", |
|
||||||
"disabled": false, |
|
||||||
"alwaysAllow": [] |
|
||||||
}, |
|
||||||
"excel": { |
|
||||||
"url": "http://localhost:8009/sse", |
|
||||||
"disabled": true, |
|
||||||
"alwaysAllow": [] |
|
||||||
}, |
|
||||||
"brave-search": { |
|
||||||
"url": "http://localhost:8010/sse", |
|
||||||
"disabled": false, |
|
||||||
"alwaysAllow": [ |
|
||||||
"brave_web_search" |
|
||||||
] |
|
||||||
}, |
|
||||||
"blender-mcp": { |
|
||||||
"disabled": true, |
|
||||||
"command": "uvx", |
|
||||||
"args": [ |
|
||||||
"/home/chodak/src/git/blender-mcp" |
|
||||||
], |
|
||||||
"alwaysAllow": [ |
|
||||||
"get_scene_info", |
|
||||||
"get_object_info", |
|
||||||
"execute_blender_code" |
|
||||||
] |
|
||||||
}, |
|
||||||
"gimp": { |
|
||||||
"command": "uv", |
|
||||||
"args": [ |
|
||||||
"run", |
|
||||||
"--directory", |
|
||||||
"/home/chodak/src/git/gimp-mcp", |
|
||||||
"gimp_mcp_server.py" |
|
||||||
], |
|
||||||
"alwaysAllow": [ |
|
||||||
"get_gimp_info" |
|
||||||
], |
|
||||||
"disabled": true |
|
||||||
}, |
|
||||||
"cloudflare-docs": { |
|
||||||
"type": "sse", |
|
||||||
"url": "https://docs.mcp.cloudflare.com/sse", |
|
||||||
"disabled": true |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"$schema": "https://opencode.ai/config.json", |
||||||
|
"mcp": { |
||||||
|
"codebase-index": { |
||||||
|
"type": "remote", |
||||||
|
"url": "http://localhost:8001/supergateway/mcp", |
||||||
|
"enabled": true, |
||||||
|
"timeout": 600000 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
// Supergateway multi-server configuration. |
||||||
|
// |
||||||
|
// Every server below is served over Streamable HTTP on the gateway port: |
||||||
|
// http://localhost:8000/<name>/mcp |
||||||
|
// |
||||||
|
// Restart the gateway after changes: docker compose restart mcp |
||||||
|
// Env vars (${VAR}) are read from the container environment (see .env / env_file). |
||||||
|
{ |
||||||
|
"outputTransport": "streamableHttp", |
||||||
|
"stateful": true, |
||||||
|
"sessionTimeout": 3600000, |
||||||
|
"mcpServers": { |
||||||
|
"fetch": { |
||||||
|
"stdio": "mcp-server-fetch --ignore-robots-txt" |
||||||
|
}, |
||||||
|
"context7": { |
||||||
|
"stdio": "context7-mcp" |
||||||
|
}, |
||||||
|
"brave-search": { |
||||||
|
"stdio": "brave-search-mcp-server", |
||||||
|
"env": { |
||||||
|
"BRAVE_API_KEY": "${BRAVE_API_KEY:-}" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Examples (uncomment and adjust): |
||||||
|
// |
||||||
|
// "memory": { |
||||||
|
// "stdio": "npx -y @modelcontextprotocol/server-memory" |
||||||
|
// }, |
||||||
|
// "filesystem": { |
||||||
|
// "stdio": "npx -y @modelcontextprotocol/server-filesystem /absolute/path" |
||||||
|
// }, |
||||||
|
// "everything": { |
||||||
|
// "stdio": "npx -y @modelcontextprotocol/server-everything" |
||||||
|
// } |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue