Skip to content

Configuration reference

The mcphub config file is the single source of truth for which downstream MCP servers exist, how they group, and which agent harnesses mcphub keeps in sync. Edit this one file (or use Studio), then mcphub sync propagates the result into every agent.

Format: YAML, TOML, or JSON

The config can be YAML (mcphub.yaml, the default and the only one that keeps inline comments), TOML (mcphub.toml), or JSON (mcphub.json). mcphub picks the format from the file extension and reads and writes all three — so enable, disable, add, and Studio round-trip in whatever format you chose.

Generate one with mcphub init, choosing a format explicitly with --format:

sh
mcphub init                    # ~/.config/mcphub/mcphub.yaml (default)
mcphub init --format toml      # mcphub.toml
mcphub init --format json      # mcphub.json
mcphub init --from-agents      # union servers from installed harness configs, instead of a blank starter
mcphub init --force            # overwrite an existing config

--from-agents scans your installed harness configs (Claude Code, opencode, Codex, Crush, Forge, Hermes), unions every MCP server they already declare, and wires those agents up in gateway mode — so you can adopt mcphub without retyping servers you already have.

Location

mcphub resolves the config path in this order:

  1. the --config <path> flag,
  2. the MCPHUB_CONFIG environment variable,
  3. the first existing mcphub.{yaml,yml,toml,json} in the current directory,
  4. the first existing one in ~/.config/mcphub/, else ~/.config/mcphub/mcphub.yaml.

The same precedence (flag, then env var, then default) applies to the intelligence database: --db, then MCPHUB_DB, then ~/.local/share/mcphub/mcphub.db.

TIP

Every command accepts --config, --db, and --json as persistent flags — see the CLI reference for the full surface.

Top-level shape

yaml
version: 1
expose: all             # or: lazy
response_budget: 32KB   # complete serialized MCP result budget; 0 = unlimited
verbatim: false         # true = never spool or replace downstream results
connect_timeout: 30s    # per-downstream connect timeout (default 30s)
pin:                    # tools always mounted, even in lazy mode (optional)
  - codemap__codemap_semantic

servers:
  # name -> server definition
  <name>: { ... }

groups:
  # optional named bundles of server names
  <name>: [<server>, ...]

agents:
  # name -> agent (harness) definition
  <name>: { ... }
KeyTypeRequiredDescription
versionintyesConfig schema version. Currently 1.
exposeall | lazynoGateway tool exposure. all (default) mounts every downstream tool as server__tool; lazy advertises only mcphub's seven meta-tools and serves the rest on demand via mcphub_call_tool. See Lazy mode.
pinlist of stringsnoTools that stay mounted even in lazy mode, so agents call them directly instead of discovering them first. Each entry is a bare server (codemap — all its tools), a whole-server wildcard (codemap__*), or one tool (codemap__codemap_semantic) — those are the only shapes; any other wildcard or a trailing __ fails validation, as does a pin naming an unknown server. Manage with mcphub pin / mcphub unpin (--top N auto-pins your N most-called tools from mcphub stats), or p in Studio.
response_budgetbyte-size stringnoComplete serialized MCP result budget. Default 32KB; "0" is unlimited. A non-zero value must be at least 512B so a recovery receipt can fit. Oversized results are stored locally for 24 hours and recovered with mcphub_get_result.
verbatimboolnoReturn every downstream result unchanged and disable result spooling entirely. Default false.
connect_timeoutduration stringnoPer-downstream connect timeout, e.g. 30s, 60s, 2m. Default 30s.
serversmapyesThe downstream MCP servers mcphub manages.
groupsmapnoNamed bundles of server names.
agentsmapyesThe agent harnesses mcphub keeps in sync.

Bounded, lossless results

Small results always pass through unchanged. A result over response_budget is stored losslessly in SQLite for 24 hours and replaced with a compact recovery receipt; the agent recovers the exact serialized payload in bounded pages with mcphub_get_result. See Bounded, lossless results.


servers

A map of server name to definition. Each server is either a local stdio server (command) or a remote server (url) — exactly one of the two.

yaml
servers:
  # stdio server
  codemap:
    command: codemap
    args: [serve]
    env:
      LOG_LEVEL: info
    enabled: true
    description: Code knowledge graph
    tags: [code, search]

  # remote server, with a secret injected from tvault at connect time
  obsidian:
    url: "https://127.0.0.1:27124/mcp"
    transport: http
    headers:
      Authorization: "tvault://obsidian/authorization"
    enabled: false
    description: Obsidian Local REST API

Fields

FieldTypeApplies toDescription
commandstringstdioThe executable to spawn for a local stdio server.
argslist of stringsstdioArguments passed to command.
envmap of string→stringstdioEnvironment variables for the spawned process (merged over the inherited environment).
urlstringremoteThe endpoint of a remote server.
transportstringremotehttp (default, streamable HTTP) or sse.
headersmap of string→stringremoteCustom HTTP headers sent with every request. A value that starts with tvault:// is resolved to a secret at connect time instead of read literally — see Secrets.
vaultstringstdioA TinyVault (tvault) project. The server is launched via tvault run --project <vault> -- <command>, injecting that project's secrets as env vars at spawn — so they never live in mcphub.yaml.
vault_onlylist of stringsstdioInject only these secret keys (least-privilege allowlist).
vault_prefixstringstdioInject only secret keys with this prefix.
enabledboolbothWhether the gateway connects to it and sync (direct mode) writes it.
descriptionstringbothHuman-readable note shown in list, Studio, and mcphub_list_servers.
tagslist of stringsbothFree-form labels.

Rules (validated on load)

  • The name mcphub is reserved (it's the gateway entry sync writes into agents), and a server name must not contain __ — that's the namespacing separator in server__tool.
  • A server must set either command or url — not both, and not neither.
  • transport, if set, must be http or sse. For a remote server with no transport, mcphub uses streamable HTTP.
  • headers only makes sense on a remote server; a server with headers set but no url fails validation with headers only apply to remote (url) servers.
  • vault requires a command (it wraps a spawned process) — it can't be used with a remote url.
  • Only enabled servers are connected by the gateway and written by sync in direct mode.

stdio vs. remote

A server with a command is a stdio server: the gateway spawns it as a subprocess and speaks MCP over its stdin/stdout, with any env merged over the inherited environment. A server with a url is remote: the gateway connects over the network using the chosen transport (http streamable, or sse).

Secrets: vault and tvault:// headers

Two independent mechanisms keep secrets out of mcphub.yaml, both backed by TinyVault (tvault):

yaml
servers:
  # vault: for stdio servers — secrets injected as env vars at spawn
  github:
    command: gh-mcp
    args: [--stdio]
    vault: github            # spawn via `tvault run --project github`
    vault_only: [GH_TOKEN]   # least-privilege allowlist (optional)
    enabled: true

  # tvault:// headers — for remote servers, resolved at connect time
  obsidian:
    url: "https://127.0.0.1:27124/mcp"
    transport: http
    headers:
      Authorization: "tvault://obsidian/authorization"
    enabled: true
  • vault wraps the spawn command as tvault run --project <vault> [--only <vault_only>] [--prefix <vault_prefix>] -- <command> <args...>. In gateway mode the hub spawns it, so the secrets never reach the agent at all. In direct mode sync writes the wrapped command into the agent's config verbatim, so tvault must be on the agent's own PATH too.
  • headers values starting with tvault://<project>/<key> (or tvault://<key> for the active project) are resolved by shelling out to tvault get when the gateway dials the server. This only happens in gateway mode — sync never writes headers into any agent's config, so a direct-mode agent never sees the header, resolved or literal.

mcphub doctor checks that tvault is on PATH whenever a server uses vault. Add a vaulted stdio server from the CLI with:

sh
mcphub add github gh-mcp --vault github --vault-only GH_TOKEN

There is no --vault-prefix or header-setting flag on mcphub add yet — set vault_prefix and headers by editing the config directly. See Secrets for the full walkthrough, including the validation errors and the direct-mode caveats for each mechanism.


groups

Optional named bundles of server names — a convenience for organizing related servers.

yaml
groups:
  coding: [codemap, vecgrep]

Every member must be the name of a server defined under servers; an unknown member fails validation. Flip a whole bundle on at once with mcphub use <group> (add --only to also disable every server not in the group), then run mcphub sync to apply. mcphub groups lists what's defined.


agents

A map of agent name to the harness mcphub syncs into. Each agent points at a config file, chooses a sync mode, and can optionally be scoped to a subset of servers and tools.

yaml
agents:
  claude:
    type: claude
    path: ~/.claude.json
    mode: gateway
  opencode:
    type: opencode
    path: ~/.config/opencode/opencode.json
    mode: direct
  codex:
    type: codex
    path: ~/.codex/config.toml
    mode: gateway
    # disabled: true                 # skip during sync without deleting the definition
    # servers: [codemap, vecgrep]    # only these enabled servers (omit = all; [] = none)
    # tools: [codemap__codemap_find] # gateway-only: only these server__tool names (omit = all; [] = none)

Fields

FieldTypeRequiredDescription
typestringyesThe harness adapter: claude, opencode, codex, crush, forge, hermes, copilot, qwen, gemini, kilo, or kimi.
pathstringyesThe harness config file. Supports leading ~ expansion.
modestringnogateway (default) or direct.
disabledboolnoSkip this agent during sync without deleting its definition.
serverslist of stringsnoWhich enabled downstream servers this agent may reach. Omitted means all; an explicit [] means none.
toolslist of stringsnoWhich server__tool names this agent may call. Gateway mode only. Omitted means every tool of the allowed servers; an explicit [] means none.

type

Selects the file-format adapter that translates mcphub's view of servers into the harness's on-disk format:

typeTarget file (typical)MCP section
claude~/.claude.jsonmcpServers
opencode~/.config/opencode/opencode.jsonmcp
codex~/.codex/config.toml[mcp_servers.*]
crush~/.config/crush/crush.jsonmcp
forge~/forge/.mcp.jsonmcpServers
hermes~/.hermes/config.yamlmcp_servers
copilot~/.copilot/mcp-config.jsonmcpServers
qwen~/.qwen/settings.jsonmcpServers
gemini~/.gemini/settings.jsonmcpServers
kilo~/.config/kilo/kilo.jsoncmcp
kimi~/.kimi/config.toml[mcp_servers.*]

See Supported harnesses for each adapter's format details, including the note that the Codex and Kimi TOML round-trips do not preserve comments or key ordering, and that Kilo's JSONC parser strips comments on write. mcphub agents shows which harnesses are configured (in mcphub.yaml already), available (installed but not yet added), or not_installed.

mode

Controls what sync writes into the agent:

  • gateway (default) — write only the mcphub gateway, so the agent sees a single MCP server and mcphub proxies all the real servers behind it. This is the token-saving default: one tool list, one connection.
  • direct — write every enabled server straight into the agent, verbatim, with no proxy in between.

If mode is omitted (or set to anything other than direct), mcphub treats it as gateway. See Concepts.

disabled

Set disabled: true to keep an agent's definition in the file but skip it during sync. It's reported as skipped rather than removed, so you can re-enable it later without retyping type/path.

servers and tools: per-agent routing

By default every enabled server reaches every non-disabled agent. For multi-agent setups where different agents should see different subsets, give an agent a servers list (which downstream servers it may reach) and/or a tools list (which server__tool names it may call — gateway mode only, since a direct-mode agent talks to each server itself and there's no proxy to filter individual tools):

yaml
agents:
  codex:
    type: codex
    path: ~/.codex/config.toml
    mode: gateway
    servers: [codemap, vecgrep]
    tools: [codemap__codemap_find, vecgrep__vecgrep_search]

Both fields distinguish omitted from empty, which matters:

In mcphub.yamlMeaning
key omitted entirelyAll. No restriction — every enabled server / every tool of the allowed servers.
servers: [] / tools: []None. A deliberately minimal agent.
servers: [a, b] / tools: [a__x]Only these.

In gateway mode, a scoped agent's harness entry is launched as mcphub mcp serve --agent <name>, so the spawned gateway advertises only that subset and refuses out-of-scope calls through mcphub_call_tool, mcphub_describe_tool, mcphub_search_tools, and mcphub_list_servers. In direct mode only the listed servers are written into the agent's config (tools doesn't apply there). A listed server that is disabled, or missing from the enabled set, is dropped silently — routing selects within the enabled servers, it does not enable anything; naming a server that doesn't exist anywhere in servers: is a validation error. tools entries must be exact server__tool names — no wildcards — and when the agent also has a servers list, each tool's server must appear in it. A tools list on a direct-mode agent fails validation (tools routing is gateway-only). mcphub doctor reports each agent's scope (routes to N/M enabled servers) and flags any listed-but-disabled server.

Curation, not a security boundary

Routing controls what the gateway advertises and honors for a well-behaved agent — it keeps context lean and agents on-task. It is not a hard isolation layer: anything that can run mcphub mcp serve without --agent, or talk to the downstream servers directly, sees everything. Use it to stop a review agent from burning tokens on deployment tools, not to protect secrets from a hostile process.

See Per-agent routing for the full walkthrough.


Full example

yaml
version: 1

# all (default) mounts every downstream tool as 'server__tool';
# lazy advertises only mcphub's seven meta-tools and serves the rest on demand.
expose: all

servers:
  codemap:
    command: codemap
    args: [serve]
    enabled: true
    description: Code knowledge graph
    tags: [code, search]
  vecgrep:
    command: vecgrep
    args: [serve, --mcp]
    env:
      VECGREP_HOME: ~/.vecgrep
    enabled: true
    description: Semantic code search
    tags: [code, search]
  bob:
    command: /Users/abdulachik/go/bin/bob
    args: [mcp, serve, --allow-any-workspace]
    enabled: true
    description: Deterministic repository factory and lifecycle reconciler
    tags: [builder, code]
  glyph:
    command: glyph
    args: [mcp]
    enabled: false
    description: TUI behavior testing

  # secrets injected from a tvault project at spawn — never stored in this file
  github:
    command: gh-mcp
    args: [--stdio]
    vault: github            # spawn via `tvault run --project github`
    vault_only: [GH_TOKEN]   # least-privilege allowlist (optional)
    enabled: true
    description: GitHub MCP

  # remote server — a tvault:// header ref resolved at connect time
  obsidian:
    url: "https://127.0.0.1:27124/mcp"
    transport: http
    headers:
      Authorization: "tvault://obsidian/authorization"
    enabled: false
    description: Obsidian Local REST API

# Optional named bundles of servers
groups:
  coding: [bob, codemap, vecgrep]

# Tools that stay mounted directly even under expose: lazy
pin:
  - codemap__codemap_semantic

# Agent harnesses mcphub keeps in sync
agents:
  claude:
    type: claude
    path: ~/.claude.json
    mode: gateway
  opencode:
    type: opencode
    path: ~/.config/opencode/opencode.json
    mode: direct
  codex:
    type: codex
    path: ~/.codex/config.toml
    mode: gateway
    # disabled: true                # skip during sync without deleting the definition
    # Per-agent routing (optional) — restrict what this agent can reach:
    # servers: [codemap, vecgrep]        # only these enabled servers (omit = all; [] = none)
    # tools: [codemap__codemap_find]     # gateway-only: only these server__tool names (omit = all; [] = none)

The Bob entry uses --allow-any-workspace, which grants its read-only MCP tools access to any workspace readable by the Bob process. Use that flag only in a trusted, local, single-user gateway — see the Bob integration guide for the least-privilege --allow-workspace alternative.

See also

Released under the MIT License.