OpalServe

MCP Gateway

OpalServe is itself an MCP server. Editors connect to it as a single endpoint and inherit every tool from every backend server.

OpalServe speaks MCP. Any MCP-compatible client, Claude Desktop, Cursor, Cline, your own, can connect to OpalServe as a single endpoint and access every tool from every backend MCP server registered upstream.

This page describes the gateway transports, the editor link command, and what happens to a tool call as it travels from the editor through OpalServe to a backend server.

Transports

OpalServe ships an stdio transport in v3.4. SSE and streamable-HTTP transports are scheduled for v3.5.

opalserve start --mcp

That command runs OpalServe in stdio mode, no HTTP server, no dashboard, just the MCP protocol on stdin and stdout. This is what an editor spawns when linked.

For multi-machine setups (developers connecting to a hosted team server), use the team-client mode: OpalServe runs locally as a thin client, fetches the registry from the team server, and exposes the gateway over local stdio.

opalserve link is the supported way to point an editor at OpalServe.

opalserve link claude       # Claude Desktop
opalserve link cursor       # Cursor
opalserve link cline        # Cline (VS Code extension)
opalserve link --all        # link every detected editor
opalserve link --status     # show what is currently linked, no changes

Each editor adapter writes to the editor's MCP config file:

EditorConfig path
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json (macOS), %APPDATA%/Claude/claude_desktop_config.json (Windows)
Cursor~/.cursor/mcp.json
Clineinside the VS Code workspace settings

Existing config is backed up to <file>.opalserve-backup before any write.

The command written to each editor is npx -y opalserve mcp by default. Override globally with the OPALSERVE_LINK_COMMAND env var, useful when you have a specific binary path.

What gets exposed

When an editor connects to OpalServe over MCP, it sees:

  • Every tool from every registered backend server, namespaced as serverName:toolName
  • The graph_search tool from the Graphiti sidecar (if Team Brain is enabled)
  • A small set of OpalServe-native tools, currently opalserve_search (full-text search across the tool index) and opalserve_status (returns the same shape as GET /api/v1/health)

Tool calls flow:

Editor  ──→  OpalServe gateway  ──→  Registry  ──→  Backend MCP server
              (validates,           (records          (executes,
               authorizes,           usage_event,     returns result)
               rate-limits)          forwards)

Every call is recorded in the usage_events table, visible in the dashboard, in opalserve admin stats, and in the per-user /me/activity.

Authentication in stdio mode

In team-client mode, the local stdio gateway uses the API key from ~/.opalserve/config.json to authenticate against the team server. The editor itself stays anonymous, it is OpalServe that holds the key.

In local mode there is no auth; the gateway simply forwards calls to the locally registered servers.

Errors

Tool call errors are returned in the standard MCP isError: true shape with a normalized error message. The original backend error message is preserved under the error.context field for debugging.

Network errors (backend MCP server unreachable, timeout) are surfaced with code: "SERVER_DISCONNECTED". The editor sees this as a normal MCP error and can retry; OpalServe will attempt to reconnect to the backend on the next call.

Performance

Stdio is zero-overhead for the editor → OpalServe hop. The cost is the OpalServe → backend hop, which is also stdio for most servers. Expect latencies that mirror running the backend MCP server directly, ~5-30ms for filesystem operations, ~50-200ms for HTTP-backed servers like GitHub.

OpalServe does not cache tool results. The usage_events table is append-only and is the only side effect of a call.

Security

Every backend MCP server runs under the OpalServe parent process. Sensitive env vars (GitHub tokens, Slack secrets, database URLs) are passed at server registration time and never logged. The gateway does not expose them through any tool.

If your team has a server that should be available to admins only, use opalserve admin permissions --user <email> --servers <allowed> to restrict per-user access.