MCP Settings Configuration
This guide explains how to configure MCP servers in MCPHub using themcp_settings.json file and related configurations.
Configuration Files Overview
MCPHub uses several configuration files:mcp_settings.json: Your personal configuration of active MCP servers and system configservers.json: Metadata cataloging hundreds of available MCP servers.env: Environment variables and secrets
Basic MCP Settings Structure
mcp_settings.json
Example Configuration
Server Configuration Options
A server entry has the shape"<server-name>": ServerConfig. The relevant fields depend on the transport, which is selected by type.
Top-level fields
type: "stdio" (default)
type: "sse" or type: "streamable-http"
type: "openapi"
The authoritative definition of every field is the
ServerConfig type in src/types/index.ts — consult it if you need behavior not described here.
A protected
openapi.url is downloaded through MCPHub’s authenticated client, so the
configured headers and OpenAPI security credentials (HTTP Basic/Bearer, API key,
OAuth2 token) authenticate the fetch. Credentials are scoped to the document origin only —
they are not forwarded to external $ref resolutions or cross-origin redirects. If a
protected document references external $refs that also require auth, inline the document
via openapi.schema instead.Common MCP Server Examples
Web and API Servers
Fetch Server
Web Scraping with Playwright
Per-session client isolation (stateful servers)
By default MCPHub keeps a single upstream connection per server and shares it across every downstream MCP session. For stateful servers this means all clients share the same state — with Playwright, for example, every session drives the same browser instance and its tabs. SetperSessionClient: true to make MCPHub open a dedicated upstream client per
downstream session instead. Each session gets its own connection (and, for
stdio servers, its own child process), created lazily on first tool call and torn
down automatically when the session ends.
perSessionClient is a MCPHub-side setting: it controls how many upstream
connections MCPHub opens. It is distinct from Playwright MCP’s own --isolated
flag, which controls browser-profile isolation on the Playwright side. The two
pair naturally — enable both for fully isolated browser sessions.--isolated flag:
Upstream protocol negotiation
Streamable HTTP upstreams default toprotocolNegotiation: "auto". MCPHub probes
server/discover and uses modern stateless HTTP when supported; legacy servers
fall back to the existing handshake. HTTP probe timeouts and network or
authentication failures can fail the connection rather than trigger fallback.
To skip discovery for a known legacy endpoint, configure:
"auto" or "legacy". "auto" requires
type: "streamable-http"; stdio and legacy SSE retain legacy negotiation.
Configure this advanced option through settings JSON, JSON import or the server
API; dashboard form edits and duplication preserve it. It is supported in both
file and database storage, templates and declarative settings sync. Editing it
reconnects the server. Shared, isolated and personal connections use the same
policy, except isolated connections forwarding legacy elicitation remain legacy
until a modern input_required bridge is available.
Modern upstreams have no server-push stream. Lists are revalidated on relevant
requests after their upstream TTL expires, with concurrent refreshes coalesced.
Missing, zero or unusable TTLs and partial pages are revalidated on the next
relevant request. Health checks remain opt-in via enableKeepAlive; modern
connections probe server/discover over the network instead of ping.
See the compatibility matrix.
Shared remote SSE and Streamable HTTP servers retry in the background after a connection failure or a closed connection, even when health checks are disabled. Retries use exponential backoff with jitter, from 5–10 seconds initially up to 150–300 seconds, without a retry limit. Successful connections reset the backoff; disabled servers and servers waiting for OAuth authorization do not retry. With health checks disabled, an outage is detected when a request fails or the connection closes. The dashboard shows the next retry and the last retry time/count through the runtime recovery status (attempts, lastAttemptAt, and nextAttemptAt; timestamps are epoch milliseconds).
For modern upstreams with passthroughHeaders, discovery clients and snapshots
are request-local rather than shared across forwarded identities. Each relevant
request adds a discovery round trip; those descriptors are not published to the
global cache or vector index. If an upstream refresh fails, only that upstream
is excluded from the current request; healthy results remain available and
partial lists have zero TTL. Later requests retry the failed upstream.
Routing headers over MCP 2026-07-28
Modern requests useMCP-Protocol-Version: 2026-07-28 and Mcp-Method
matching the JSON-RPC method. tools/call and prompts/get also require
Mcp-Name matching params.name; resources/read requires it to match
params.uri. List methods do not require Mcp-Name. The SDK v2 HTTP client
sets these headers automatically.
For example, a tool call to /mcp with params.name set to
my-server-my-tool sends:
params._meta protocol-version and client-capability envelope. They do not
select a group or grant access: the URL and bearer permissions still determine
the available servers. On a server-specific URL, use the tool name exposed by
that URL in both the body and header. Non-ASCII names use the SDK’s
=?base64?<UTF-8 Base64>?= encoding in Mcp-Name.
Missing required headers, header/body mismatches and invalid name encodings
return HTTP 400 with JSON-RPC error -32020 before dispatch. Legacy
2025-11-25 requests retain their existing handshake and session behavior and
do not require these routing headers.
Stateful tools over MCP 2026-07-28
Modern MCP requests do not create a downstream transport session. To call tools on servers withperSessionClient: true or OpenAPI cookieSession: true, enable
bearer authentication and send X-MCPHub-State-Id with a client-generated UUID v4
on each request that belongs to the same application workflow. For example:
Mcp-Session-Id and the MCP handshake.
The same state ID reuses isolated upstream clients and cookie jars only within
the same bearer credential, user and route. Use a different UUID for each
independent workflow.
Authenticated OpenAI/ChatGPT tool calls that cannot set this extension may omit
it and send the client-declared _meta["openai/session"] conversation hint that
ChatGPT includes with tool calls. MCPHub hashes the hint before using it for state
correlation. The hint never authenticates or authorizes a request, and reuse is
still bounded by the verified bearer credential, user and route. If
X-MCPHub-State-Id is present but invalid, MCPHub fails closed instead of falling
back. If neither usable correlation value is present, stateful tools return a tool
error. Other tools need no state ID.
State lives in memory on one MCPHub process. It expires after 30 minutes without
an active call; running calls pin their state until completion. Expiry and shutdown
close isolated upstream clients and clear cookie jars. The process admits at most
1,000 modern state scopes; excess scopes receive a tool error until capacity is
available. Restart, expiry, bearer rotation or a route change starts fresh state.
Use sticky routing when running multiple replicas. Legacy 2025-11-25 clients
continue using their existing downstream session lifecycle.
File and System Servers
Filesystem Server
SQLite Server
Communication Servers
Slack Server
Development and API Servers
GitHub Server
Map and Location Services
Amap (高德地图) Server
Advanced Configuration
Environment Variable Substitution
MCPHub supports environment variable substitution using${VAR_NAME} syntax:
Proxy Configuration (proxychains4)
MCPHub supports routing STDIO server network traffic through a proxy using proxychains4. This feature is available on Linux and macOS only (Windows is not supported).To use this feature, you must have
proxychains4 installed on your system:- Debian/Ubuntu:
apt install proxychains4 - macOS:
brew install proxychains-ng - Arch Linux:
pacman -S proxychains-ng
Basic Proxy Configuration
Proxy Configuration Options
Proxy with Authentication
Using Custom proxychains4 Configuration
For advanced use cases, you can provide your own proxychains4 configuration file:Group Management
Group Configuration
Editing mcp_settings.json while running
In file mode, MCPHub re-readsmcp_settings.json when it changes, without a restart:
- Server definitions and credentials are picked up on the next server reload —
POST /api/servers/:name/reload, thereloadbutton in the dashboard, ormcphub servers reload <name>. - System settings (
systemConfig, e.g.nameSeparator) are picked up on the next read once the file has changed. - Settings that are read once at process startup still require a restart to take effect: the Better Auth bootstrap,
skipAuth, the listening port, and anything driven by environment variables.
mcp_settings.json is a one-time seed by default. Set MCPHUB_SETTINGS_SYNC=upsert to apply server and group declarations on each startup, or prune to also delete removed managed entries; see declarative database configuration for precedence and OAuth state handling.
System Routing Settings
You can also configure runtime routing and authentication behavior undersystemConfig.routing in mcp_settings.json:
bearerAuthHeaderNamedefaults toAuthorizationand controls which incoming header MCPHub reads for Bearer authentication.allowAuthorizationPassthroughdefaults tofalse. To forward a caller’s upstreamAuthorization, an administrator must explicitly enable it, use a separate MCPHub authentication header such asX-MCP-Authorization, and listAuthorizationin the trusted server’spassthroughHeaders(HTTP MCP) oropenapi.passthroughHeaders(OpenAPI).- The MCPHub authentication header is always blocked.
Authorizationremains blocked in hosted mode, andCookie,Proxy-Authorization,X-Auth-Token, andX-Api-Keyremain blocked regardless of the opt-in. Listing a blocked header does not forward it. - This instance-wide opt-in trusts every configured passthrough destination with the caller’s upstream token. Only enable it for trusted destinations; passthrough configuration remains admin-only. Existing installations keep filtering
Authorizationuntil explicitly opted in. jsonBodyLimitdefaults to1mband controls the Express JSON parser limit for API requests, including large inline OpenAPI schema uploads.
PUT /api/system-config endpoint (authenticate with the currently configured MCPHub header):
X-MCP-Authorization: Bearer <mcphub-key> and Authorization: Bearer <upstream-user-token> with each MCP request. Static upstream headers and personal credentials remain separate authentication options; they do not replace per-request caller tokens.
Tool Result Compression
MCPHub can transparently compress large text tool results before returning them to MCP clients. This is useful when upstream tools return large logs, diffs, search output, JSON arrays, or long text blobs that would otherwise consume too much model context. Tool result compression is disabled by default. Enable and tune it from Settings → Tool Result Compression, or configure it undersystemConfig.toolResultCompression:
Compression only applies to successful tool responses. Responses with
isError: true are returned unchanged, non-text content blocks are preserved, and each text block is evaluated independently. When MCPHub compresses a result, it prepends a marker such as:
Best Practices
Security
-
Use environment variables for sensitive data:
Stdio response buffer
Setoptions.maxBufferSize to a positive safe integer in bytes to allow larger stdio responses:
Allowing internal upstream networks
Administrators can maintain Allowed upstream CIDR ranges in Settings, or setsystemConfig.network.allowedCidrs in JSON storage:
/32 for one IPv4 address or /128 for one IPv6 address). All DNS answers, each redirect destination, and connection-time DNS answers are checked. Removing a range affects subsequent requests, but does not close existing connections or clear cached data. Anonymous OAuth client metadata (CIMD) URLs remain restricted to public addresses.
Only admins can update the list through PUT /api/system-config with {"network":{"allowedCidrs":["192.168.1.0/24"]}}. Sending an empty array clears it. Invalid lists return HTTP 400 without saving. Database installations should use the dashboard or API; the field is stored in the system configuration table.
Use the smallest necessary ranges. Broad ranges such as 0.0.0.0/0 or ::/0 also allow sensitive internal destinations, including loopback and cloud metadata endpoints.
Fake-IP DNS with TUN routing
In Settings → Security → Fake-IP DNS exceptions, administrators can select a server, enter its exact hostname, add or delete rules, and save. The server selector stores its stable ID. Removing all rows and saving clears the exceptions. For SSE and Streamable HTTP upstreams behind a trusted local Fake-IP/TUN setup, administrators can grant an exact hostname on one stable server ID access to198.18.0.0/15, without globally allowing that range:
id from GET /api/servers (not its display name). Hostnames must be lowercase ASCII DNS names, with no scheme, port, wildcard or trailing dot; use punycode for internationalized names. A missing ID never matches. In database mode, use the admin-only PUT /api/system-config with {"network":{"fakeIpExceptions":[{"serverId":"existing-server-uuid","hostname":"mcp.example.com"}]}}. An empty array clears exceptions. Updating either network list preserves the other, including when changing CIDRs through Settings.
The exception applies to requests made through the named server’s MCP transport fetch, including SDK OAuth requests that reuse that fetch. Initial DNS answers, every redirect destination and socket-time DNS answers follow the same policy. Every answer must pass; loopback, private and metadata addresses receive no additional permission. IP-literal URLs and unrelated hostnames or server IDs do not match. Redirects to another hostname require their own matching exception if they resolve to Fake-IP addresses; public destinations remain subject to normal policy. Existing global CIDR allowances and administrator-owner bypasses still apply, so use a non-admin-owned server and no broad CIDR allowances when this narrower boundary is required. Removing an exception affects later requests and lookups, but does not terminate existing streams or connections.
Guarded connections use direct socket DNS validation and bypass configured HTTP/HTTPS proxies. A system-level TUN must intercept and route these connections, and its DNS mapping must agree with the DNS visible inside the MCPHub process/container. Merely allowing the synthetic range does not establish routing. MCPHub trusts the local DNS/TUN mapping and cannot determine the real destination behind a synthetic address; only grant exceptions for trusted endpoints and a trusted proxy environment. TLS still uses the original hostname. This policy does not enable explicit HTTP proxy routing or add exceptions to OpenAPI requests, separate OAuth discovery/token/registration fetches, or anonymous CIMD URLs; these keep their existing SSRF policy. OAuth setups using those separate fetches may therefore still need real DNS results for their endpoints.
On-demand tool snapshots
For stdio servers,startOnDemand: true keeps the child process asleep until it is needed. MCPHub persists the last successful raw tool discovery so a restart can restore tools/list without starting every on-demand server. An empty tool list is also a valid snapshot. The first tool call still connects to the upstream and refreshes discovery; tools removed upstream cannot execute from the snapshot. Failed calls trigger a discovery refresh without replaying the call.
File mode stores snapshots beside the settings file as <settings-path>.capabilities.json; mount that directory on persistent storage to retain snapshots across container replacement. Database mode stores them in the capability_snapshots table. Snapshots stay outside settings exports and contain no launch configuration or credentials. Tool definitions themselves may contain private upstream metadata, so protect snapshot storage like other runtime data.
The server-list and server-detail APIs expose capabilityCache.state (fresh, stale, or missing) and capabilityCache.capturedAt when available. Here fresh means configuration-matching last-known discovery, not guaranteed current upstream state. Launch configuration, effective child environment, and personal credential binding changes invalidate a snapshot. Server/group tool overrides and permissions are reapplied when listing; they are never frozen into the snapshot. Personal snapshots are isolated by authenticated user, and listing still requires a valid binding and current server access.
Missing or incompatible snapshots retain live discovery (startup priming for shared stdio servers, first authenticated use for personal servers). No fleet-wide background refresh is scheduled. Unchanged configuration cannot detect an upstream package update or external permission change until the next live connection. Prompts and resources are not persisted in this phase; personal prompt/resource requests still connect live.
Tool authorization policies
Operators can configuresystemConfig.toolPolicies in file mode or send toolPolicies to the administrator-only PUT /api/system-config endpoint in either storage mode. An omitted or empty array preserves existing access. Administrators can also manage rules in Settings → Tool access policies: add, edit or delete rules, then save the policy set. Blank selectors match any value. Saving an empty set removes policy restrictions while keeping existing permissions.
id, an effect (allow or deny), and optional exact-match username, keyId, groupId, serverId, and tool selectors. Omitted selectors are unconstrained. tool is the original upstream name, before server prefixes, group aliases, or preserveToolNames projection. Key and group IDs are their existing IDs; administrators can retrieve a server’s stable data.config.id from GET /api/servers/:name. File entries without an ID receive a deterministic legacy ID, which is stored on the next DAO write and retained when the server is renamed. New servers receive new IDs; ordinary updates cannot replace an ID. Declarative database sync matches by name and is separate from ordinary DAO renames: when using policies, pin the existing data.config.id as id in each server file entry and retain it across renames. Without a pinned ID, a renamed declaration creates a new identity and old deny rules no longer match. See declarative database configuration.
Username and key selectors establish the subject scope before matching the route or tool. For that subject, any fully matching deny wins. If any allow rules apply to the subject, at least one must fully match the requested route/server/tool; otherwise the call is denied. Multiple allows form a union. Without applicable allows or a matching deny, existing access is retained. Policies always intersect with visibility, key scope, group access, enabled state, and capability selections, including for administrator-owned user keys.
A groupId selects the resolved endpoint group on normal and $smart/<group> routes. Direct server, global, and bare $smart routes have no group context. A group-only allow therefore cannot be bypassed through a direct/global endpoint. Add an allow without groupId to permit the selected servers/tools through those routes.
Discovery and execution share the policy evaluator. Smart Routing limits eligible candidates before vector ranking/top-k, and execution checks the resolved target again. A denied call does not acquire personal credentials or invoke upstream. Allowed user keys retain the owner’s personal OAuth identity and token refresh. Policy configuration errors fail closed. External IdP authentication and claim mapping are outside this policy model.
Activity records include a policy object with decision, reason, optional policyId, serverId, and groupId, alongside caller/key and server/tool identity. File-mode deployments record decisions in application logs; persistent activity history requires database mode. Personal credential payloads remain omitted from activity records, and policy audit metadata never contains credential values.
For direct personal-server endpoints with active policies, list tools before calls that could be interpreted as either raw, prefixed, or gateway wrapper names. Until discovery resolves that ambiguity, all possible targets must be authorized; otherwise the call is denied before credentials are resolved.
The editor warns about IDs absent from the loaded servers, keys or groups. Startup also checks references after database synchronization and logs warnings. Warnings do not block saving, so resources can be configured in advance. An orphaned deny provides no protection; an allow referencing a missing server or group may block its applicable subjects, while a missing key selector normally matches no subject. These checks cannot determine whether a rule with valid IDs matches an actual request; tool names and usernames are not checked.
Administrators can customize the dashboard name in Settings → System Settings → Dashboard name, or set systemConfig.dashboardName in mcp_settings.json (for example, "dashboardName": "Team MCP"). The name appears in the sidebar, header, login page, and browser tab. Names are trimmed and limited to 100 characters. Save an empty value to restore the default branding. This setting persists in both file and database storage modes.