Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.6 KiB
MCP servers
The image ships three MCP servers for Claude Code, all speaking stdio:
| Server | Name in /mcp |
What it gives Claude | Source |
|---|---|---|---|
| Gitea | gitea |
Repos, issues, PRs, releases on your Gitea instance | gitea/gitea-mcp (official, latest release binary) |
| n8n | n8n |
n8n node documentation, plus workflow creation/management when the API env vars are set | czlonkowski/n8n-mcp (npm) |
| InvokeAI | invokeai |
Text-to-image, img2img, and upscaling against your InvokeAI instance | coinstax/invokeai-mcp-server (PyPI) |
How install and registration are split
The Dockerfile only installs the servers (/usr/local/bin/n8n-mcp,
/usr/local/bin/gitea-mcp, and a uv tool venv for InvokeAI).
Registration happens in files/entrypoint.sh on every container start,
via claude mcp add --scope user.
It has to work that way: user-scope MCP config lives in ~/.claude.json,
which claudaris start bind-mounts from the host — so
anything registered at build time would be shadowed by the mounted file. The
runtime registration writes into the mounted file instead, which also means
it persists across rebuilds like the login does.
Registration is guarded per server: a server that's already present is left
alone, so hand edits to its config survive restarts. The flip side is that a
server deleted with claude mcp remove comes back on the next container
start — to change one permanently, edit its entry rather than removing it.
Pointing the servers at your instances
The servers read their URLs and tokens from the environment Claude Code runs
in (Claude Code passes its environment through to stdio MCP servers). Set
them in your host-persisted aliases file, $DATA_DIR/home/bash_aliases,
where a commented template already exists at the bottom:
export GITEA_HOST='https://gitea.example.com'
export GITEA_ACCESS_TOKEN='...'
export N8N_API_URL='https://n8n.example.com' # optional: enables workflow management tools
export N8N_API_KEY='...'
export INVOKEAI_BASE_URL='http://invokeai.example.com:9090'
Then start a new shell (or source ~/.bashrc) and launch claude. Because
the file lives on the host, tokens never end up in the image or the repo. If
your bash_aliases was seeded before the MCP servers existed, copy the
template block from files/bash_aliases.
Notes:
- URLs must be reachable from inside the container.
127.0.0.1means the container itself, not the host. Use the host's LAN address or service hostname. - Gitea: create the token in Gitea under Settings → Applications → Generate New Token.
- n8n: without
N8N_API_URL/N8N_API_KEYthe server still works as a node-documentation reference; the API pair unlocks creating and managing workflows. Create the key in n8n under Settings → n8n API. - InvokeAI: defaults to
http://127.0.0.1:9090if unset. Upstream hardcodes that URL; the Dockerfile patches the package soINVOKEAI_BASE_URLis honored (and the build fails loudly if a future upstream release breaks the patch). Registration usespython -m invokeai_mcp_serverbecause the package's console script is broken upstream.
Checking it works
Inside the container:
claude mcp list # all three should show as configured
Or in a Claude Code session, run /mcp to see connection status, and try
something like "list my Gitea repos". A server whose env vars are unset
will show as failed/erroring until you set them — the other servers are
unaffected.