Configuration
OpalServe v3 supports three operating modes: local (single developer), team-server (centralized hub), and team-client (connect to a hub). This page covers every configuration option.
Config File Locations
OpalServe uses cosmiconfig and searches for config in this order:
opalserve.config.ts/.js/.mjs/.cjsopalserve.config.json.opalserverc/.opalserverc.json/.opalserverc.yamlopalservekey inpackage.json~/.opalserve/config.json(global fallback)
The opalserve init wizard writes to option 5 by default. You can override the config path with --config:
opalserve start --config ./my-config.jsonOperating Modes
Local Mode (Default)
For individual developers. Runs everything on your machine. No auth required.
{
"mode": "local",
"servers": [],
"gateway": { "port": 3456 },
"storage": { "path": "~/.opalserve/data.db" }
}Team Server Mode
For the team admin. Runs a centralized OpalServe instance that team members connect to. Requires auth configuration.
{
"mode": "team-server",
"servers": [
{
"name": "github",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "ghp_xxx" }
}
}
],
"gateway": {
"port": 3456,
"host": "0.0.0.0"
},
"auth": {
"enabled": true,
"jwtSecret": "your-secure-random-secret",
"apiKeys": true,
"sessionTtl": 86400
},
"team": {
"name": "Acme Engineering",
"maxUsers": 50,
"allowSignup": false,
"defaultRole": "developer"
},
"storage": {
"path": "/var/lib/opalserve/data.db"
},
"rateLimiting": {
"enabled": true,
"windowMs": 60000,
"maxRequests": 100
},
"logging": {
"level": "info"
}
}Team Client Mode
For developers connecting to a team server. Minimal config — just the server URL and credentials.
{
"mode": "team-client",
"teamServer": {
"url": "https://opalserve.internal.company.com",
"apiKey": "osk_abc123..."
},
"gateway": {
"port": 3456
}
}Login instead of manual config
You do not need to write the team-client config by hand. Use the CLI:
opalserve login https://opalserve.internal.company.comThis stores your credentials securely and sets the mode to team-client automatically.
Full Config Reference
Top-Level Fields
| Field | Type | Default | Description |
|---|---|---|---|
mode | string | "local" | Operating mode: local, team-server, or team-client |
servers | Server[] | [] | MCP servers to connect to (local and team-server modes) |
gateway | object | {} | HTTP API and gateway settings |
auth | object | {} | Authentication configuration (team-server mode) |
team | object | {} | Team settings (team-server mode) |
teamServer | object | {} | Remote server connection (team-client mode) |
storage | object | {} | Database storage settings |
rateLimiting | object | {} | Rate limiting configuration |
logging | object | {} | Log level and output |
knowledgeBase | object | {} | Knowledge base settings |
Server Configuration
Each entry in the servers array defines an MCP server to connect to.
| Field | Type | Default | Description |
|---|---|---|---|
name | string | required | Unique name (lowercase, hyphens allowed) |
transport | Transport | required | Transport configuration (see below) |
enabled | boolean | true | Whether to connect on startup |
tags | string[] | [] | Tags for organization and filtering |
autoConnect | boolean | true | Auto-connect when opalserve start runs |
description | string | "" | Human-readable description (shown in dashboard) |
Transport Types
stdio — Launch a local process:
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/docs"],
"env": {},
"cwd": "/optional/working/dir"
}sse — Connect to a remote SSE endpoint:
{
"type": "sse",
"url": "https://my-mcp-server.example.com/sse",
"headers": { "Authorization": "Bearer token" }
}streamable-http — Connect to a Streamable HTTP endpoint:
{
"type": "streamable-http",
"url": "https://my-mcp-server.example.com/mcp",
"headers": {}
}Gateway Configuration
| Field | Type | Default | Description |
|---|---|---|---|
port | number | 3456 | HTTP API port |
host | string | 127.0.0.1 | Bind address. Use 0.0.0.0 for team-server mode |
cors | string[] | ["*"] | Allowed CORS origins |
trustProxy | boolean | false | Trust reverse proxy headers (X-Forwarded-For) |
Auth Configuration
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable JWT authentication |
jwtSecret | string | — | Secret for signing JWT tokens. Required if auth is enabled |
apiKeys | boolean | true | Allow API key authentication |
sessionTtl | number | 86400 | Session lifetime in seconds (default: 24 hours) |
bcryptRounds | number | 12 | Bcrypt cost factor for password hashing |
Keep your JWT secret secure
The jwtSecret should be a cryptographically random string of at least 32 characters. Never commit it to version control. Use environment variables instead:
export OPALSERVE_JWT_SECRET=$(openssl rand -hex 32)Team Configuration
| Field | Type | Default | Description |
|---|---|---|---|
name | string | "" | Team or organization name |
maxUsers | number | 100 | Maximum number of user accounts |
allowSignup | boolean | false | Allow self-registration (default: invite only) |
defaultRole | string | "developer" | Default role for new users: admin, developer, viewer |
inviteExpiry | number | 604800 | Invite link expiry in seconds (default: 7 days) |
Team Server Connection (Client Mode)
| Field | Type | Default | Description |
|---|---|---|---|
url | string | required | URL of the team server |
apiKey | string | — | API key for authentication |
syncInterval | number | 300 | How often to sync server list, in seconds |
fallbackToLocal | boolean | true | Use local servers if team server is unreachable |
Storage Configuration
| Field | Type | Default | Description |
|---|---|---|---|
path | string | ~/.opalserve/data.db | SQLite database path |
walMode | boolean | true | Enable WAL mode for better concurrent performance |
Rate Limiting
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable rate limiting |
windowMs | number | 60000 | Time window in milliseconds |
maxRequests | number | 100 | Max requests per window per user |
toolCallLimit | number | 50 | Max tool calls per window per user |
Knowledge Base
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Enable the knowledge base |
maxDocumentSize | number | 1048576 | Max document size in bytes (default: 1MB) |
maxDocuments | number | 1000 | Max documents in the knowledge base |
chunkSize | number | 512 | Token chunk size for indexing |
chunkOverlap | number | 64 | Overlap between chunks |
Logging
| Field | Type | Default | Description |
|---|---|---|---|
level | string | "info" | Log level: silent, error, warn, info, debug, trace |
Environment Variable Overrides
Any config field can be overridden with an environment variable. These take priority over the config file.
| Variable | Overrides | Example |
|---|---|---|
OPALSERVE_MODE | mode | team-server |
OPALSERVE_PORT | gateway.port | 8080 |
OPALSERVE_HOST | gateway.host | 0.0.0.0 |
OPALSERVE_JWT_SECRET | auth.jwtSecret | your-secret |
OPALSERVE_LOG_LEVEL | logging.level | debug |
OPALSERVE_DB_PATH | storage.path | /var/lib/opalserve/data.db |
OPALSERVE_TEAM_SERVER_URL | teamServer.url | https://opalserve.company.com |
GITHUB_TOKEN | GitHub server env | ghp_xxx |
SLACK_BOT_TOKEN | Slack server env | xoxb-xxx |
Example: Full Team Server Config
{
"mode": "team-server",
"servers": [
{
"name": "github",
"description": "GitHub repositories and issues",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "ghp_xxx" }
},
"tags": ["code", "github"]
},
{
"name": "slack",
"description": "Slack workspace",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": { "SLACK_BOT_TOKEN": "xoxb-xxx" }
},
"tags": ["communication"]
},
{
"name": "docs",
"description": "Engineering documentation",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/opt/docs"]
},
"tags": ["docs"]
}
],
"gateway": {
"port": 3456,
"host": "0.0.0.0",
"cors": ["https://dashboard.company.com"],
"trustProxy": true
},
"auth": {
"enabled": true,
"jwtSecret": "use-env-variable-instead",
"apiKeys": true,
"sessionTtl": 86400
},
"team": {
"name": "Acme Engineering",
"maxUsers": 50,
"allowSignup": false,
"defaultRole": "developer"
},
"storage": {
"path": "/var/lib/opalserve/data.db"
},
"rateLimiting": {
"enabled": true,
"windowMs": 60000,
"maxRequests": 100,
"toolCallLimit": 50
},
"knowledgeBase": {
"enabled": true,
"maxDocuments": 500,
"chunkSize": 512
},
"logging": {
"level": "info"
}
}