openclaw mcp has two jobs:
- run OpenClaw as an MCP server with
openclaw mcp serve - manage OpenClaw-owned outbound MCP server definitions with
list,show,set, andunset
In other words:
serveis OpenClaw acting as an MCP serverlist/show/set/unsetis OpenClaw acting as an MCP client-side registry for other MCP servers its runtimes may consume later
Use [openclaw acp](/docs/openclaw-docs/cli/acp when OpenClaw should host a coding harness session itself and route that runtime through ACP.
OpenClaw as an MCP server
This is the openclaw mcp serve path.
When to use serve
Use openclaw mcp serve when:
- Codex, Claude Code, or another MCP client should talk directly to OpenClaw-backed channel conversations
- you already have a local or remote OpenClaw Gateway with routed sessions
- you want one MCP server that works across OpenClaw's channel backends instead of running separate per-channel bridges
Use [openclaw acp](/docs/openclaw-docs/cli/acp instead when OpenClaw should host the coding runtime itself and keep the agent session inside OpenClaw.
How it works
openclaw mcp serve starts a stdio MCP server. The MCP client owns that process. While the client keeps the stdio session open, the bridge connects to a local or remote OpenClaw Gateway over WebSocket and exposes routed channel conversations over MCP.
Choose a client mode
Use the same bridge in two different ways:
What serve exposes
The bridge uses existing Gateway session route metadata to expose channel-backed conversations. A conversation appears when OpenClaw already has session state with a known route such as:
channel- recipient or destination metadata
- optional
accountId - optional
threadId
This gives MCP clients one place to:
- list recent routed conversations
- read recent transcript history
- wait for new inbound events
- send a reply back through the same route
- see approval requests that arrive while the bridge is connected
Usage
Bridge tools
The current bridge exposes these MCP tools:
Useful filters:
- `limit`
- `search`
- `channel`
- `includeDerivedTitles`
- `includeLastMessage`
Use this when a generic MCP client needs near-real-time delivery without a Claude-specific push protocol.
Current behavior:
- requires an existing conversation route
- uses the session's channel, recipient, account id, and thread id
- sends text only
- `allow-once`
- `allow-always`
- `deny`
Event model
The bridge keeps an in-memory event queue while it is connected.
Current event types:
messageexec_approval_requestedexec_approval_resolvedplugin_approval_requestedplugin_approval_resolvedclaude_permission_request
Claude channel notifications
The bridge can also expose Claude-specific channel notifications. This is the OpenClaw equivalent of a Claude Code channel adapter: standard MCP tools remain available, but live inbound messages can also arrive as Claude-specific MCP notifications.
When Claude channel mode is enabled, the server advertises Claude experimental capabilities and can emit:
notifications/claude/channelnotifications/claude/channel/permission
Current bridge behavior:
- inbound
usertranscript messages are forwarded asnotifications/claude/channel - Claude permission requests received over MCP are tracked in-memory
- if the linked conversation later sends
yes abcdeorno abcde, the bridge converts that tonotifications/claude/channel/permission - these notifications are live-session only; if the MCP client disconnects, there is no push target
This is intentionally client-specific. Generic MCP clients should rely on the standard polling tools.
MCP client config
Example stdio client config:
{
"mcpServers": {
"openclaw": {
"command": "openclaw",
"args": [
"mcp",
"serve",
"--url",
"wss://gateway-host:18789",
"--token-file",
"/path/to/gateway.token"
]
}
}
}
For most generic MCP clients, start with the standard tool surface and ignore Claude mode. Turn Claude mode on only for clients that actually understand the Claude-specific notification methods.
Options
openclaw mcp serve supports:
Security and trust boundary
The bridge does not invent routing. It only exposes conversations that Gateway already knows how to route.
That means:
- sender allowlists, pairing, and channel-level trust still belong to the underlying OpenClaw channel configuration
messages_sendcan only reply through an existing stored route- approval state is live/in-memory only for the current bridge session
- bridge auth should use the same Gateway token or password controls you would trust for any other remote Gateway client
If a conversation is missing from conversations_list, the usual cause is not MCP configuration. It is missing or incomplete route metadata in the underlying Gateway session.
Testing
OpenClaw ships a deterministic Docker smoke for this bridge:
pnpm test:docker:mcp-channels
That smoke:
- starts a seeded Gateway container
- starts a second container that spawns
openclaw mcp serve - verifies conversation discovery, transcript reads, attachment metadata reads, live event queue behavior, and outbound send routing
- validates Claude-style channel and permission notifications over the real stdio MCP bridge
This is the fastest way to prove the bridge works without wiring a real Telegram, Discord, or iMessage account into the test run.
For broader testing context, see [Testing](/docs/openclaw-docs/help/testing.
Troubleshooting
- the client kept the stdio MCP session open
- `--claude-channel-mode` is `on` or `auto`
- the client actually understands the Claude-specific notification methods
- the inbound message happened after the bridge connected
OpenClaw as an MCP client registry
This is the openclaw mcp list, show, set, and unset path.
These commands do not expose OpenClaw over MCP. They manage OpenClaw-owned MCP server definitions under mcp.servers in OpenClaw config.
Those saved definitions are for runtimes that OpenClaw launches or configures later, such as embedded Pi and other runtime adapters. OpenClaw stores the definitions centrally so those runtimes do not need to keep their own duplicate MCP server lists.
Runtime adapters may normalize this shared registry into the shape their downstream client expects. For example, embedded Pi consumes OpenClaw transport values directly, while Claude Code and Gemini receive CLI-native type values such as http, sse, or stdio.
Saved MCP server definitions
OpenClaw also stores a lightweight MCP server registry in config for surfaces that want OpenClaw-managed MCP definitions.
Commands:
openclaw mcp listopenclaw mcp show [name]openclaw mcp set <name> <json>openclaw mcp unset <name>
Notes:
listsorts server names.showwithout a name prints the full configured MCP server object.setexpects one JSON object value on the command line.- Use
transport: "streamable-http"for Streamable HTTP MCP servers.openclaw mcp setalso normalizes CLI-nativetype: "http"to the same canonical config shape for compatibility. unsetfails if the named server does not exist.
Examples:
openclaw mcp list
openclaw mcp show context7 --json
openclaw mcp set context7 '{"command":"uvx","args":["context7-mcp"]}'
openclaw mcp set docs '{"url":"https://mcp.example.com","transport":"streamable-http"}'
openclaw mcp unset context7
Example config shape:
{
"mcp": {
"servers": {
"context7": {
"command": "uvx",
"args": ["context7-mcp"]
},
"docs": {
"url": "https://mcp.example.com",
"transport": "streamable-http"
}
}
}
}
Stdio transport
Launches a local child process and communicates over stdin/stdout.
| Field | Description |
|---|---|
command | Executable to spawn (required) |
args | Array of command-line arguments |
env | Extra environment variables |
cwd / workingDirectory | Working directory for the process |
OpenClaw rejects interpreter-startup env keys that can alter how a stdio MCP server starts up before the first RPC, even if they appear in a server's env block. Blocked keys include NODE_OPTIONS, PYTHONSTARTUP, PYTHONPATH, PERL5OPT, RUBYOPT, SHELLOPTS, PS4, and similar runtime-control variables. Startup rejects these with a configuration error so they cannot inject an implicit prelude, swap the interpreter, or enable a debugger against the stdio process. Ordinary credential, proxy, and server-specific env vars (GITHUB_TOKEN, HTTP_PROXY, custom *_API_KEY, etc.) are unaffected.
If your MCP server genuinely needs one of the blocked variables, set it on the gateway host process instead of under the stdio server's env.
SSE / HTTP transport
Connects to a remote MCP server over HTTP Server-Sent Events.
| Field | Description |
|---|---|
url | HTTP or HTTPS URL of the remote server (required) |
headers | Optional key-value map of HTTP headers (for example auth tokens) |
connectionTimeoutMs | Per-server connection timeout in ms (optional) |
Example:
{
"mcp": {
"servers": {
"remote-tools": {
"url": "https://mcp.example.com",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}
}
Sensitive values in url (userinfo) and headers are redacted in logs and status output.
Streamable HTTP transport
streamable-http is an additional transport option alongside sse and stdio. It uses HTTP streaming for bidirectional communication with remote MCP servers.
| Field | Description |
|---|---|
url | HTTP or HTTPS URL of the remote server (required) |
transport | Set to "streamable-http" to select this transport; when omitted, OpenClaw uses sse |
headers | Optional key-value map of HTTP headers (for example auth tokens) |
connectionTimeoutMs | Per-server connection timeout in ms (optional) |
OpenClaw config uses transport: "streamable-http" as the canonical spelling. CLI-native MCP type: "http" values are accepted when saved through openclaw mcp set and repaired by openclaw doctor --fix in existing config, but transport is what embedded Pi consumes directly.
Example:
{
"mcp": {
"servers": {
"streaming-tools": {
"url": "https://mcp.example.com/stream",
"transport": "streamable-http",
"connectionTimeoutMs": 10000,
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}
}
Current limits
This page documents the bridge as shipped today.
Current limits:
- conversation discovery depends on existing Gateway session route metadata
- no generic push protocol beyond the Claude-specific adapter
- no message edit or react tools yet
- HTTP/SSE/streamable-http transport connects to a single remote server; no multiplexed upstream yet
permissions_list_openonly includes approvals observed while the bridge is connected
Related
- [CLI reference](/docs/openclaw-docs/cli
- [Plugins](/docs/openclaw-docs/cli/plugins