> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcphub.app/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Settings Configuration

> Configure MCP servers and their settings for MCPHub

# 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

```json theme={null}
{
  "mcpServers": {
    "server-name": {
      "command": "command-to-run",
      "args": ["arg1", "arg2"],
      "env": {
        "ENV_VAR": "value"
      }
    }
  }
}
```

### Example Configuration

```json theme={null}
{
  "mcpServers": {
    "fetch": {
      "command": "uvx",
      "args": ["mcp-server-fetch"],
      "env": {
        "USER_AGENT": "MCPHub/1.0"
      }
    },
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest", "--headless"]
    },
    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
        "SLACK_TEAM_ID": "${SLACK_TEAM_ID}"
      }
    }
  }
}
```

## 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

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | `"stdio" \| "sse" \| "streamable-http" \| "openapi"` | Recommended | Transport. Defaults to `stdio` when omitted but a `command` is provided. |
| `enabled` | boolean | no | Defaults to `true`. Disabled servers stay in settings but are not connected. |
| `owner` | string | no | Username that owns the entry. Defaults to the creating user or `admin`. Used for user-scoped routes (`/:user/mcp/...`). |
| `visibility` | `"private" \| "group" \| "public"` | no | Runtime access for non-admin users. Defaults to `private`; `group` grants access to `sharedWithUsers`. |
| `sharedWithUsers` | string\[] | no | Local usernames allowed to discover and call a server whose `visibility` is `group`. Ignored for other visibility values. |
| `description` | string | no | Free-form description displayed in the dashboard. |
| `options` | object | no | Per-server runtime options (see `src/types/index.ts`). |
| `proxy` | object | no | Optional HTTP proxy settings (`url`, `noProxy`, etc.). |
| `oauth` | object | no | Upstream OAuth client settings (used when the upstream server requires OAuth). |
| `enableKeepAlive` | boolean | no | For `sse` / `streamable-http`: enable periodic health checks and automatic reconnect attempts. |
| `keepAliveInterval` | number | no | Health check and reconnect interval in milliseconds. Defaults to `60000`. |
| `perSessionClient` | boolean | no | Create a dedicated upstream client per downstream MCP session instead of sharing one connection across all sessions. Use for stateful servers like Playwright. See [Per-session client isolation](#per-session-client-isolation-stateful-servers). |
| `tools`, `prompts`, `resources` | object | no | Per-item overrides: `{ "<name>": { "enabled": true, "description": "..." } }`. Managed via the dashboard or the per-resource API endpoints. |

### `type: "stdio"` (default)

| Field | Type | Required | Description |
| - | - | - | - |
| `command` | string | yes | Executable to spawn. |
| `args` | string\[] | no | Command-line arguments. |
| `env` | object | no | Extra environment variables for the child process. `${ENV}` placeholders in values are expanded against the MCPHub process environment. |

### `type: "sse"` or `type: "streamable-http"`

| Field | Type | Required | Description |
| - | - | - | - |
| `url` | string | yes | Upstream endpoint URL. |
| `headers` | object | no | Static headers sent on every request. |
| `passthroughHeaders` | string\[] | no | Inbound HTTP header names to forward from the caller to the upstream server. |

### `type: "openapi"`

| Field | Type | Required | Description |
| - | - | - | - |
| `openapi.url` | string | one of `url`/`schema` | URL of an OpenAPI document MCPHub will download. |
| `openapi.schema` | object | one of `url`/`schema` | Inline OpenAPI document. |
| `headers` | object | no | Static headers applied to outbound calls, including the spec download itself. |
| `openapi.passthroughHeaders` | string\[] | no | Headers to forward from the caller. |

The authoritative definition of every field is the `ServerConfig` type in [src/types/index.ts](src/types/index.ts) — consult it if you need behavior not described here.

<Note>
  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 `$ref`s that also require auth, inline the document
  via `openapi.schema` instead.
</Note>

## Common MCP Server Examples

### Web and API Servers

#### Fetch Server

```json theme={null}
{
  "fetch": {
    "command": "uvx",
    "args": ["mcp-server-fetch"],
    "env": {
      "USER_AGENT": "MCPHub/1.0",
      "MAX_REDIRECTS": "10"
    }
  }
}
```

#### Web Scraping with Playwright

```json theme={null}
{
  "playwright": {
    "command": "npx",
    "args": ["@playwright/mcp@latest", "--headless"],
    "timeout": 60000,
    "env": {
      "PLAYWRIGHT_BROWSERS_PATH": "/tmp/browsers"
    }
  }
}
```

### 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.

<Note>
  `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.
</Note>

```json theme={null}
{
  "mcpServers": {
    "playwright": {
      "type": "streamable-http",
      "url": "http://playwright-mcp:3000/mcp",
      "perSessionClient": true
    }
  }
}
```

Or with a locally spawned Playwright MCP using its `--isolated` flag:

```json theme={null}
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest", "--headless", "--isolated"],
      "perSessionClient": true
    }
  }
}
```

<Tip>
  Only enable `perSessionClient` for servers that actually hold per-session state.
  It multiplies upstream connections (and stdio child processes) by the number of
  concurrent sessions, so leave it off for stateless servers.
</Tip>

### 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:

```http theme={null}
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: my-server-my-tool
```

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:

```http theme={null}
Authorization: Bearer <your-key>
X-MCPHub-State-Id: 65b523af-e4d0-4d99-8e06-461a62a14967
```

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

```json theme={null}
{
  "filesystem": {
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
    "env": {
      "ALLOWED_OPERATIONS": "read,write,list"
    }
  }
}
```

#### SQLite Server

```json theme={null}
{
  "sqlite": {
    "command": "uvx",
    "args": ["mcp-server-sqlite", "--db-path", "/path/to/database.db"],
    "env": {
      "SQLITE_READONLY": "false"
    }
  }
}
```

### Communication Servers

#### Slack Server

```json theme={null}
{
  "slack": {
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-slack"],
    "env": {
      "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
      "SLACK_TEAM_ID": "${SLACK_TEAM_ID}",
      "SLACK_APP_TOKEN": "${SLACK_APP_TOKEN}"
    }
  }
}
```

### Development and API Servers

#### GitHub Server

```json theme={null}
{
  "github": {
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-github"],
    "env": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
    }
  }
}
```

### Map and Location Services

#### Amap (高德地图) Server

```json theme={null}
{
  "amap": {
    "command": "npx",
    "args": ["-y", "@amap/amap-maps-mcp-server"],
    "env": {
      "AMAP_MAPS_API_KEY": "${AMAP_API_KEY}"
    }
  }
}
```

<Tip>
  Looking for more servers? The bundled [Market catalog](https://docs.mcphub.app/features/server-management) in the dashboard lists hundreds of known MCP servers with copy-paste-ready configurations.
</Tip>

## Advanced Configuration

### Environment Variable Substitution

MCPHub supports environment variable substitution using `${VAR_NAME}` syntax:

```json theme={null}
{
  "mcpServers": {
    "api-server": {
      "command": "python",
      "args": ["-m", "api_server"],
      "env": {
        "API_KEY": "${API_KEY}",
        "API_URL": "${API_BASE_URL}/v1"
      }
    }
  }
}
```

### 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).

<Note>
  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`
</Note>

#### Basic Proxy Configuration

```json theme={null}
{
  "mcpServers": {
    "fetch-via-proxy": {
      "command": "uvx",
      "args": ["mcp-server-fetch"],
      "proxy": {
        "enabled": true,
        "type": "socks5",
        "host": "127.0.0.1",
        "port": 1080
      }
    }
  }
}
```

#### Proxy Configuration Options

| Field | Type | Default | Description |
| - | - | - | - |
| `enabled` | boolean | `false` | Enable/disable proxy routing |
| `type` | string | `socks5` | Proxy protocol: `socks4`, `socks5`, or `http` |
| `host` | string | - | Proxy server hostname or IP address |
| `port` | number | - | Proxy server port |
| `username` | string | - | Proxy authentication username (optional) |
| `password` | string | - | Proxy authentication password (optional) |
| `configPath` | string | - | Path to custom proxychains4 config file |

#### Proxy with Authentication

```json theme={null}
{
  "mcpServers": {
    "secure-server": {
      "command": "npx",
      "args": ["-y", "@example/mcp-server"],
      "proxy": {
        "enabled": true,
        "type": "http",
        "host": "proxy.example.com",
        "port": 8080,
        "username": "${PROXY_USER}",
        "password": "${PROXY_PASSWORD}"
      }
    }
  }
}
```

#### Using Custom proxychains4 Configuration

For advanced use cases, you can provide your own proxychains4 configuration file:

```json theme={null}
{
  "mcpServers": {
    "custom-proxy-server": {
      "command": "python",
      "args": ["-m", "custom_mcp_server"],
      "proxy": {
        "enabled": true,
        "configPath": "/etc/proxychains4/custom.conf"
      }
    }
  }
}
```

<Tip>
  When `configPath` is specified, all other proxy settings (`type`, `host`, `port`, etc.) are ignored, and the custom configuration file is used directly.
</Tip>

## Group Management

### Group Configuration

```json theme={null}
{
  "groups": {
    "production": {
      "name": "Production Tools",
      "description": "Stable production servers",
      "servers": ["fetch", "slack", "github"]
    },
    "experimental": {
      "name": "Experimental Features",
      "description": "Beta and experimental servers",
      "servers": ["experimental-ai", "beta-search"]
    }
  }
}
```

## 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; see [declarative database configuration](/configuration/database-configuration#declarative-servers-and-groups-gitops) 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`:

```json theme={null}
{
  "systemConfig": {
    "routing": {
      "enableBearerAuth": true,
      "bearerAuthHeaderName": "X-MCP-Authorization",
      "jsonBodyLimit": "5mb",
      "skipAuth": false
    }
  }
}
```

* `bearerAuthHeaderName` defaults to `Authorization` and controls which incoming header MCPHub reads for Bearer authentication.
* Use a custom header such as `X-MCP-Authorization` when an upstream MCP/OpenAPI server also needs to passthrough `Authorization`.
* `jsonBodyLimit` defaults to `1mb` and controls the Express JSON parser limit for API requests, including large inline OpenAPI schema uploads.

## 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`:

```json theme={null}
{
  "systemConfig": {
    "toolResultCompression": {
      "enabled": false,
      "minTokens": 2000,
      "maxOutputTokens": 1200,
      "strategy": "auto"
    }
  }
}
```

| Field | Type | Default | Description |
| - | - | - | - |
| `enabled` | boolean | `false` | Enable transparent compression for successful tool results. |
| `minTokens` | number | `2000` | Only compress a text block when its estimated token count is at or above this threshold. |
| `maxOutputTokens` | number | `1200` | Target token budget for each compressed text block. |
| `strategy` | `"auto" \| "json" \| "log" \| "search" \| "diff" \| "text"` | `"auto"` | Compression strategy. `auto` detects common structured output formats. |

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:

```text theme={null}
[mcphub:compressed-tool-result strategy=log original_tokens=9000 compressed_tokens=1200 omitted_lines=240]
```

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:

   ```json theme={null}
   {
     "env": {
       "API_KEY": "${API_KEY}",
       "DATABASE_PASSWORD": "${DB_PASSWORD}"
     }
   }
   ```

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:

```json theme={null}
{
  "type": "stdio",
  "command": "node",
  "args": ["server.js"],
  "options": { "maxBufferSize": 268435456 }
}
```

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:

```json theme={null}
{
  "systemConfig": {
    "network": {
      "allowedCidrs": ["192.168.1.0/24", "fd00:1234::/64"]
    }
  }
}
```

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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.