Skip to main content

MCP Settings Configuration

This guide explains how to configure MCP servers in MCPHub using the mcp_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 config
  • servers.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. Set perSessionClient: 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.
Or with a locally spawned Playwright MCP using its --isolated flag:
Enable perSessionClient for servers that hold per-session state or need legacy tool-call elicitation forwarding. It multiplies upstream connections (and stdio child processes) by the number of concurrent sessions, so leave it off when neither feature is needed.

Upstream protocol negotiation

Streamable HTTP upstreams default to protocolNegotiation: "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:
The optional field accepts "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 use MCP-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:
These headers accompany the normal JSON-RPC body, including the modern 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 with perSessionClient: 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:
This is an MCPHub extension, independent of 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

Looking for more servers? The bundled Market catalog in the dashboard lists hundreds of known MCP servers with copy-paste-ready configurations.

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:
When configPath is specified, all other proxy settings (type, host, port, etc.) are ignored, and the custom configuration file is used directly.

Group Management

Group Configuration

Editing mcp_settings.json while running

In file mode, MCPHub re-reads mcp_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, the reload button in the dashboard, or mcphub 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.
In database mode, 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 under systemConfig.routing in mcp_settings.json:
  • bearerAuthHeaderName defaults to Authorization and controls which incoming header MCPHub reads for Bearer authentication.
  • allowAuthorizationPassthrough defaults to false. To forward a caller’s upstream Authorization, an administrator must explicitly enable it, use a separate MCPHub authentication header such as X-MCP-Authorization, and list Authorization in the trusted server’s passthroughHeaders (HTTP MCP) or openapi.passthroughHeaders (OpenAPI).
  • The MCPHub authentication header is always blocked. Authorization remains blocked in hosted mode, and Cookie, Proxy-Authorization, X-Auth-Token, and X-Api-Key remain 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 Authorization until explicitly opted in.
  • jsonBodyLimit defaults to 1mb and controls the Express JSON parser limit for API requests, including large inline OpenAPI schema uploads.
Administrators can enable this in Settings → Keys → Allow Authorization passthrough after saving a separate MCPHub authentication header. The switch is hidden in hosted mode. In database mode, you can also use the admin-only PUT /api/system-config endpoint (authenticate with the currently configured MCPHub header):
After configuring the server’s passthrough list, send 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 under systemConfig.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:
The activity log records the original upstream output before compression, so operators can inspect full results in MCPHub even when clients receive compressed content.

Best Practices

Security

  1. Use environment variables for sensitive data:
This comprehensive guide covers all aspects of configuring MCP servers in MCPHub for various use cases and environments.

Stdio response buffer

Set options.maxBufferSize to a positive safe integer in bytes to allow larger stdio responses:
Omitting this option retains the SDK default of 10 MiB (10485760 bytes). The limit applies to the read buffer containing the serialized MCP message, including its envelope. A response that exceeds the limit closes the transport. Raising the limit allows greater memory use; choose a finite limit appropriate for the server. Zero, negative values, fractions, and non-finite values are rejected. This option does not change HTTP transports or the SDK’s large-message processing performance.

Allowing internal upstream networks

Administrators can maintain Allowed upstream CIDR ranges in Settings, or set systemConfig.network.allowedCidrs in JSON storage:
The list defaults to empty. It permits all users’ upstream MCP (SSE and Streamable HTTP), OpenAPI, and upstream OAuth requests to addresses in those ranges. Public addresses remain accessible; admin-owned servers retain their existing unrestricted internal-network access. Server visibility and sharing permissions are unchanged. Each entry must be an IPv4 or IPv6 address with a prefix length (for example /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 to 198.18.0.0/15, without globally allowing that range:
Use the existing server’s 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 configure systemConfig.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.
Each rule has a unique 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.