Files
openclaw/docs/cli/mcp.md
Peter Steinberger bb46b79d3c refactor: internalize OpenClaw agent runtime (#85341)
* refactor: extract agent core package

Introduce packages/agent-core as the OpenClaw-owned home for reusable agent loop, harness, session, prompt, and runtime dependency contracts.

* refactor: extract shared llm runtime

Move provider model registries, stream wrappers, OAuth helpers, and LLM utilities into src/llm with plugin-sdk barrels instead of depending on the old embedded runtime layout.

* refactor: remove pi runtime internals

Rename remaining Pi-shaped agent surfaces to OpenClaw agent runtime names, delete obsolete Pi docs and package graph checks, and add the third-party notice for incorporated code.

* refactor: tighten agent session runtime

Make agent-core/runtime dependencies explicit, consolidate compaction and session transcript helpers, and move model/session helpers behind OpenClaw-owned contracts.

* refactor: remove static model and pi auth paths

Drop static model catalogs and Pi auth bridges, move model/provider facts to manifest-owned runtime contracts, and harden internal embedded-agent utilities.

* refactor: remove legacy provider compat paths

* docs: remove agent parity notes

* fix: skip provider wildcard metadata parsing

* refactor: share session extension sdk loading

* refactor: inline acpx proxy error formatter

* refactor: fold edit recovery into edit tool

* fix: accept extension batch separator

* test: align startup provider plugin expectations

* fix: restore provider-scoped release discovery

* test: align static asset packaging expectations

* fix: run static provider catalogs during scoped discovery

* fix: add provider entry catalogs for scoped live discovery

* fix: load lightweight provider catalog entries

* fix: refresh provider-scoped plugin metadata

* fix: keep provider catalog entries on release live path

* fix: keep static manifest models in release live checks

* fix: harden release model discovery

* fix: reduce OpenAI live cache probe reasoning

* fix: disable OpenAI cache probe reasoning

* ci: extend OpenAI gateway live timeout

* fix: extend live gateway model budget

* fix: stabilize release validation regressions

* fix: honor provider aliases in model rows

* fix: stabilize release validation lanes

* fix: stabilize release memory qa

* ci: stabilize release validation lanes

* ci: prefer ipv4 for live docker node calls

* fix: restore shared tool-call stream wrapper

* ci: remove legacy pi test shard alias

* fix: clean up embedded agent test drift

* fix: stabilize runtime alias status

* fix: clean up embedded agent ci drift

* fix: restore release ci invariants

* fix: clean up post-rebase runtime drift

* fix: restore release ci checks

* fix: restore release ci after rebase

* fix: remove stale pi runtime path

* test: align compaction runtime expectations

* test: update plugin prerelease expectations

* fix: handle claude live tool approvals

* fix: stabilize release validation gates

* fix: finish agent runtime import

* test: finish post-rebase agent runtime mocks

* fix: keep codex compaction native

* fix: stabilize codex app-server hook tests

* test: isolate codex diagnostic active run

* test: remove codex diagnostic completion race

# Conflicts:
#	extensions/codex/src/app-server/run-attempt.test.ts

* ci: fix full release manifest performance run id

* refactor: narrow llm plugin sdk boundary

* chore: drop generated google boundary stamps

* fix: repair rebase fallout

* fix: clean up rebased runtime references

* fix: decode codex jwt payloads as base64url

* fix: preserve shipped pi runtime alias

* fix: add scoped sdk virtual modules

* fix: decode llm codex oauth jwt as base64url

* fix: avoid stale vertex adc negative cache

* fix: harden tool arg decoding and codeql path

* fix: keep vertex adc negative checks live

* refactor: consolidate codex jwt and edit helpers

* fix: await codex oauth node runtime imports

* fix: preserve sdk tool and notice contracts

* fix: preserve shipped compat config boundaries

* fix: align codex oauth callback host

* fix: terminate agent-core loop streams on failure

* fix: keep codex oauth callback alive during fallback

* ci: include session tools in critical codeql scans

* fix: keep Cloudflare Anthropic provider auth header

* docs: redirect legacy pi runtime pages

* fix: honor bundled web provider compat discovery

* fix: protect session output spill files

* fix: keep legacy agent dir env blocked

* fix: contain auto-discovered skill symlinks

* fix: harden agent core sdk proxy surfaces

* fix: restore approval reaction sdk compat

* fix: keep live docker runs bounded

* fix: keep codex oauth redirect host aligned

* fix: resolve post-rebase agent runtime drift

* fix: redact anthropic oauth parse failures

* fix: preserve responses strict tool shaping

* fix: repair agent runtime rebase cleanup

* docs: redirect retired parity pages

* fix: bound auto-discovered resources to roots

* fix: repair post-rebase agent test drift

* fix: preserve bundled provider allowlist migration

* fix: preserve manifest-owned provider aliases

* fix: declare photon image dependency

* fix: keep provider headers out of proxy body

* fix: preserve shipped env aliases

* fix: refresh control ui i18n generated state

* fix: quote read fallback paths

* fix: preview edits through configured backend

* test: satisfy core test typecheck

* fix: preserve ZAI usage auth fallback

* test: repair codex diagnostic test

* fix: repair agent runtime rebase drift

* test: finish embedded runner import rename

* fix: repair agent runtime rebase integrations

* test: align compaction oauth fallback expectations

* fix: allow sdk-auth session models

* fix: update doctor tool schema import

* fix: preserve bedrock plugin region

* fix: stream harmony-like prose immediately

* ci: include session runtime in codeql shards

* fix: repair latest rebase integrations

* fix: honor explicit codex websocket transport

* fix: keep openai-compatible credentials provider-scoped

* fix: refresh sdk api baseline after rebase

* fix: route cli runtime aliases through openclaw harness

* test: rename stale harness mock expectation

* test: rename embedded agent overflow calls

* test: clean embedded auth test wording

* test: use openclaw stream types in deepinfra cache test

* fix: refresh sdk api baseline on latest main

* fix: honor bundled discovery compat allowlists

* fix: refresh sdk api baseline after latest rebase

* fix: remove stale rebase imports

* test: rename stale model catalog mock

* test: mock renamed doctor runtime modules

* fix: map canonical kimi env auth

* fix: use internal model registry in bench script

* fix: migrate deepinfra provider catalog entry

* fix: enforce builtin tool suppression

* fix: route compaction auth and proxy payloads safely

* refactor: prune unused llm registry leftovers

* test: update codex hooks session import

* test: fix model picker ci coverage

* test: align model picker auth mock types
2026-05-27 19:24:04 +01:00

20 KiB

summary, read_when, title, sidebarTitle
summary read_when title sidebarTitle
Expose OpenClaw channel conversations over MCP and manage saved MCP server definitions
Connecting Codex, Claude Code, or another MCP client to OpenClaw-backed channels
Running `openclaw mcp serve`
Managing OpenClaw-saved MCP server definitions
MCP MCP

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, and unset

In other words:

  • serve is OpenClaw acting as an MCP server
  • list / show / set / unset is OpenClaw acting as an MCP client-side registry for other MCP servers its runtimes may consume later

Use openclaw 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 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.

The MCP client spawns `openclaw mcp serve`. The bridge connects to the OpenClaw Gateway over WebSocket. Routed sessions become MCP conversations and transcript/history tools. Live events are queued in memory while the bridge is connected. If Claude channel mode is enabled, the same session can also receive Claude-specific push notifications. - live queue state starts when the bridge connects - older transcript history is read with `messages_read` - Claude push notifications only exist while the MCP session is alive - when the client disconnects, the bridge exits and the live queue is gone - one-shot agent entry points such as `openclaw agent` and `openclaw infer model run` retire any bundled MCP runtimes they open when the reply completes, so repeated scripted runs do not accumulate stdio MCP child processes - stdio MCP servers launched by OpenClaw (bundled or user-configured) are torn down as a process tree on shutdown, so child subprocesses started by the server do not survive after the parent stdio client exits - deleting or resetting a session disposes that session's MCP clients through the shared runtime cleanup path, so there are no lingering stdio connections tied to a removed session

Choose a client mode

Use the same bridge in two different ways:

Standard MCP tools only. Use `conversations_list`, `messages_read`, `events_poll`, `events_wait`, `messages_send`, and the approval tools. Standard MCP tools plus the Claude-specific channel adapter. Enable `--claude-channel-mode on` or leave the default `auto`. Today, `auto` behaves the same as `on`. There is no client capability detection yet.

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

```bash openclaw mcp serve ``` ```bash openclaw mcp serve --url wss://gateway-host:18789 --token-file ~/.openclaw/gateway.token ``` ```bash openclaw mcp serve --url wss://gateway-host:18789 --password-file ~/.openclaw/gateway.password ``` ```bash openclaw mcp serve --verbose openclaw mcp serve --claude-channel-mode off ```

Bridge tools

The current bridge exposes these MCP tools:

Lists recent session-backed conversations that already have route metadata in Gateway session state.
Useful filters:

- `limit`
- `search`
- `channel`
- `includeDerivedTitles`
- `includeLastMessage`
Returns one conversation by `session_key` using a direct Gateway session lookup. Reads recent transcript messages for one session-backed conversation. Extracts non-text message content blocks from one transcript message. This is a metadata view over transcript content, not a standalone durable attachment blob store. Reads queued live events since a numeric cursor. Long-polls until the next matching queued event arrives or a timeout expires.
Use this when a generic MCP client needs near-real-time delivery without a Claude-specific push protocol.
Sends text back through the same route already recorded on the session.
Current behavior:

- requires an existing conversation route
- uses the session's channel, recipient, account id, and thread id
- sends text only
Lists pending exec/plugin approval requests the bridge has observed since it connected to the Gateway. Resolves one pending exec/plugin approval request with:
- `allow-once`
- `allow-always`
- `deny`

Event model

The bridge keeps an in-memory event queue while it is connected.

Current event types:

  • message
  • exec_approval_requested
  • exec_approval_resolved
  • plugin_approval_requested
  • plugin_approval_resolved
  • claude_permission_request
- the queue is live-only; it starts when the MCP bridge starts - `events_poll` and `events_wait` do not replay older Gateway history by themselves - durable backlog should be read with `messages_read`

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.

`--claude-channel-mode off`: standard MCP tools only. `--claude-channel-mode on`: enable Claude channel notifications. `--claude-channel-mode auto`: current default; same bridge behavior as `on`.

When Claude channel mode is enabled, the server advertises Claude experimental capabilities and can emit:

  • notifications/claude/channel
  • notifications/claude/channel/permission

Current bridge behavior:

  • inbound user transcript messages are forwarded as notifications/claude/channel
  • Claude permission requests received over MCP are tracked in-memory
  • if the linked conversation later sends yes abcde or no abcde, the bridge converts that to notifications/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:

Gateway WebSocket URL. Gateway token. Read token from file. Gateway password. Read password from file. Claude notification mode. Verbose logs on stderr. Prefer `--token-file` or `--password-file` over inline secrets when possible.

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_send can 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.

Troubleshooting

Usually means the Gateway session is not already routable. Confirm that the underlying session has stored channel/provider, recipient, and optional account/thread route metadata. Expected. The live queue starts when the bridge connects. Read older transcript history with `messages_read`. Check all of these:
- 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
`permissions_list_open` only shows approval requests observed while the bridge was connected. It is not a durable approval history API.

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 OpenClaw and other runtime adapters. OpenClaw stores the definitions centrally so those runtimes do not need to keep their own duplicate MCP server lists.

- these commands only read or write OpenClaw config - they do not connect to the target MCP server - they do not validate whether the command, URL, or remote transport is reachable right now - runtime adapters decide which transport shapes they actually support at execution time - embedded OpenClaw exposes configured MCP tools in normal `coding` and `messaging` tool profiles; `minimal` still hides them, and `tools.deny: ["bundle-mcp"]` disables them explicitly - session-scoped bundled MCP runtimes are reaped after `mcp.sessionIdleTtlMs` milliseconds of idle time (default 10 minutes; set `0` to disable) and one-shot embedded runs clean them up at run end

Runtime adapters may normalize this shared registry into the shape their downstream client expects. For example, embedded OpenClaw consumes OpenClaw transport values directly, while Claude Code and Gemini receive CLI-native type values such as http, sse, or stdio.

Codex app-server also honors an optional codex block on each server. This is OpenClaw projection metadata for Codex app-server threads only; it does not change ACP sessions, generic Codex harness config, or other runtime adapters. Use non-empty codex.agents to project a server only into specific OpenClaw agent ids. Empty, blank, or invalid agent lists are rejected by config validation and omitted by the runtime projection path instead of becoming global. Use codex.defaultToolsApprovalMode (auto, prompt, or approve) to emit Codex's native default_tools_approval_mode for a trusted server. OpenClaw strips the codex metadata before handing the native mcp_servers config to Codex.

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 list
  • openclaw mcp show [name]
  • openclaw mcp set <name> <json>
  • openclaw mcp unset <name>

Notes:

  • list sorts server names.
  • show without a name prints the full configured MCP server object.
  • set expects one JSON object value on the command line.
  • Use transport: "streamable-http" for Streamable HTTP MCP servers. openclaw mcp set also normalizes CLI-native type: "http" to the same canonical config shape for compatibility.
  • unset fails 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
**Stdio env safety filter**

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, NODE_REDIRECT_WARNINGS, NODE_REPL_EXTERNAL_MODULE, NODE_REPL_HISTORY, NODE_V8_COVERAGE, 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, enable a debugger, or redirect runtime output 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 OpenClaw consumes directly.

Example:

{
  "mcp": {
    "servers": {
      "streaming-tools": {
        "url": "https://mcp.example.com/stream",
        "transport": "streamable-http",
        "connectionTimeoutMs": 10000,
        "headers": {
          "Authorization": "Bearer <token>"
        }
      }
    }
  }
}
These commands manage saved config only. They do not start the channel bridge, open a live MCP client session, or prove the target server is reachable.

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_open only includes approvals observed while the bridge is connected