Custom Servers
Beyond the built-in github server, you can expose
any number of additional MCP servers to the agent via the mcp_servers list in
config.yaml. Each entry is one of these kinds:
Remote (
type: httportype: sse) — an HTTP/SSE endpoint reached over the network. Seturl, and optionallyheadersfor authentication. This is the right choice for hosted third-party servers such as the Vercel MCP server.Stdio (
type: stdio) — a command launched by Claude Code inside the agent container. Setcommand, and optionallyargsandenv. The command must be available in the agent image.Container (
type: container) — a server claude-forge runs as a sidecar container, reached athttp://<name>:<port><path>(default path/mcp). Use this for any MCP server packaged as a container, or to run a locally-installed one that the agent image doesn’t have. By default it runs once and is shared across sessions (see Scope below). Two forms:- Native HTTP image — set
image+port(+ optionalargs). The image serves MCP over HTTP itself. - Wrapped stdio — set
command(+ optionalargs). claude-forge runs the command inside a sidecar and bridges its stdio to HTTP with supergateway. The baseimagedefaults tonode:22-slim(sonpx-based servers work); override it when the command needs a different runtime or extra CLIs. Pass secrets viaenv(the wrapped process inherits the sidecar’s environment) and host paths viamounts(host:container[:ro]).
The sidecar’s
nameis used as its network hostname, so it must be a valid DNS label. A server that fails to start is skipped with a warning rather than aborting the session.Scope (
scope:, container only) controls how the instance is reused:global(default) — a single shared instance on theforge-sharednetwork, reused across all sessions, so N sessions don’t spawn N copies. A global server is shared across projects, outlives individual sessions, and is managed withclaude-forge mcp restartrather than per-session cleanup — so it must not depend on any one session’s or project’s secrets.session— one sidecar per session, on the session network, torn down when the session ends. Use it for servers that need per-session/per-project isolation.
- Native HTTP image — set
Note: a
type: stdioserver runs in the agent container and needs its command baked into the agent image; atype: containerwrapped stdio server runs in its own sidecar, so you can bring arbitrary runtimes without modifying the agent image. Remote HTTP servers are reachable because the agent container has normal outbound internet — the git gateway only proxies git traffic.
Environment variable expansion
${VAR} references in url, headers, command, args, and env are
expanded from your host environment when a session starts, so API tokens can be
supplied without being written into config.yaml:
mcp_servers:
- name: example
type: http
url: https://mcp.example.com
headers:
Authorization: "Bearer ${EXAMPLE_TOKEN}"export EXAMPLE_TOKEN=...
claude-forge start "work session"Server names must be unique and may not shadow the built-in github server.
OAuth MCP servers (e.g. Vercel)
Some hosted MCP servers authenticate via an interactive OAuth flow instead of a
static token. That flow (browser + localhost callback) cannot complete inside
the headless container, so authenticate once on the host — Claude Code stores
the resulting token in ~/.claude/.credentials.json, which claude-forge mounts
into the container, so every session reuses it.
Mark such servers with oauth: true:
mcp_servers:
- name: vercel
type: http
url: https://mcp.vercel.com
oauth: trueAuthenticate once on the host (use the same name and URL so the container finds the token):
claude mcp add --transport http vercel https://mcp.vercel.com
claude # then run: /mcp → vercel → AuthenticateAt session start, claude-forge preflights every oauth: true server and prints
a warning (without blocking the session) if its token is missing or expired, so
you learn up front that the server won’t connect rather than discovering it
mid-session.
Note: OAuth token reuse relies on host and container sharing the file-based credential store, which is the case on Linux/WSL. On macOS the token is kept in the system Keychain (not the mounted file), so this carry-over does not apply there.