Skip to main content
Beyond being an MCP client (consuming external tools — see MCP Integration), ChatCLI can also be a server: other agents/clients — Claude Code, Claude Desktop, IDEs, editors, even another ChatCLI — can drive ChatCLI over the protocol.
These are two external subcommands, both speaking JSON-RPC over stdio (stdin/stdout carry the protocol; all logging goes to the file logger):
  • chatcli mcp-server (alias mcp-serve) — an MCP (Model Context Protocol) server. Negotiates revision 2025-03-26 or 2024-11-05.
  • chatcli acp — an ACP (Agent Client Protocol) server, for editors (Zed) and agent-to-agent use.

chatcli mcp-server

Exposes ChatCLI’s entire capability surface — not a curated subset:

Harness tools

The quality parameter maps to the CHATCLI_QUALITY_* namespace, so a caller can turn on plan, refine, verify, reflexion, convergence and lessons for a single run:

Every plugin tool

All registered built-in and external plugins are advertised individually (37 on a default build): files (read, search, tree, coder), web (websearch, webfetch, http, api-explorer), memory (memory, recall), knowledge (knowledge, context, compress, docs-flatten), visuals (diagram, graphview, image), plus moa, lsp, scheduler, session, osv, wikipedia, registry-tags, todo, tools, channels, send, proc, skill, speak
  • Each tool carries its usage embedded in the description and a readOnlyHint annotation derived from ChatCLI’s per-plugin capability metadata.
  • Arguments follow the same contract the agent uses: a JSON envelope ({"cmd":"read","args":{...}}) or a flat string.
  • Interactive tools that require a live terminal (ask, voice, park) are never exposed — over stdio they would hang forever.

Exposure policy — CHATCLI_MCP_TOOLS

Skills as MCP prompts

Every installed skill is served through prompts/list / prompts/get — the client can pull ChatCLI’s whole skill catalog as ready-to-use prompts. Slash-command templates join the same listing, carrying the MCP-spec arguments field (an args argument built from the command’s argument-hint; skills with an argument-hint carry it too): prompts/get with {"name":"review-pr","arguments":{"args":"1326 security"}} returns the fully expanded template, with pre-execution lines resolved through the security policy.

Local state as MCP resources — chatcli://

Everything the user built in ChatCLI is browsable read-only through resources/list / resources/read: Mutations go through the tools surface (memory, context, manage_session, …). CHATCLI_MCP_RESOURCES=off disables the resources surface entirely.

Cross-channel continuity — the conversation hub

The server joins the conversation hub in resume mode: it adopts the principal’s active conversation instead of rotating it, so a thread started in the interactive REPL or on a gateway channel (Telegram, Slack…) continues seamlessly from any MCP client — and the turns made over MCP show up back in the REPL. CHATCLI_MCP_HUB=off opts out; CHATCLI_MCP_HUB_PRINCIPAL isolates the MCP thread under its own principal.

Unattended safety — CHATCLI_MCP_DANGER

stdin carries the protocol, so the server runs unattended (every interactive confirmation auto-approves, like the gateway daemon). Dangerous commands in coder_task exec calls are always hard-blocked regardless of policy; for the remaining shell-command gate, CHATCLI_MCP_DANGER=block declines dangerous commands in-band (the model sees the refusal and replans) instead of auto-approving. Default is allow, matching the gateway.

Approval prompts via elicitation

Clients that declare the elicitation capability at initialize get a better contract: coder-policy ask rules and dangerous coder_task exec commands raise an elicitation/create approval form in the client instead of the blanket behavior above. When the action has a persistable policy pattern, the form offers the full terminal vocabulary as a decision enum — allow_once, allow_always, deny_once, deny_always — and the always choices persist a rule in coder_policy.json, exactly like the terminal prompt (exec commands never get the always choices, by design). Dangerous exec commands keep the simple approve boolean form. Anything except an explicit accept with an allow decision denies — decline, cancel or a transport failure — and the model replans in-band. Clients without the capability (most wrapped CLIs) keep the exact contract of the previous section; no server→client request is ever sent to them. Some clients declare the capability but never actually render the form — the run would otherwise sit frozen waiting for an answer until the client killed the call. Each approval round-trip is therefore bounded by CHATCLI_MCP_PERMISSION_TIMEOUT (a Go duration like 90s/10m or plain seconds; default 600s; 0/off lifts the bound to a 24h ceiling — never truly unbounded; the same variable bounds ACP permission dialogs). MCP clients that enforce their own shorter tools/call timeout kill the whole call first — tune the variable below your client’s limit to keep the run alive. An unanswered form denies fail-safe — never auto-approves, since the form may be visible with the user about to say no — and the model is told the request got no response (not a user denial), so it continues without the action and can explain what happened. After the first timeout, later prompts in the same run fail fast instead of stalling again. If your client persistently declares elicitation without showing dialogs, set CHATCLI_MCP_ELICITATION=off to disable the bridge entirely and restore the unattended contract of the previous section. To skip the forms entirely for a session, the manage_session tool’s policy_mode action (name: auto) switches the session into policy automode: ask rules auto-approve while deny rules and safety-immune operations keep gating; name: interactive restores the forms.

No provider configured? Still useful

An MCP client brings its own model — ChatCLI’s direct tools don’t need a local LLM. Without any key/OAuth in ChatCLI, the LLM-backed tools (ask_chatcli, agent_task, coder_task) are simply hidden from tools/list, and every direct tool keeps working (persistent memory, knowledge bases, LSP, diagrams, scheduler… driven by the caller’s model). Configure a provider and restart to enable the harness tools.

The environment an MCP client passes on

An MCP client spawns the server as a child process without your shell profile: CHATCLI_DOTENV and everything you export from .zshrc/.bashrc never reach it, and its working directory is whatever the client chose. ChatCLI therefore discovers its environment file as $CHATCLI_DOTENV./.env~/.chatcli/.env~/.env, first match wins — keep yours in one of the home locations and the server sees exactly what your terminal sees. Anything the client must pin explicitly goes in its env block. This is the usual explanation for two symptoms: providers that work in the terminal being absent from tools/list, and Bedrock answering from the wrong AWS account (without AWS_PROFILE/BEDROCK_PROFILE the SDK falls back to the default profile, and the credential chain then fails with the misleading no EC2 IMDS role found). The boot log records which file loaded, and credential errors name the profile, the environment file in effect and the aws sso login command to refresh the session.

Connecting from Claude Code

Or in a JSON config:
The agent and coder render to stdout; the backend captures that output during the run and returns it as the tool result. Direct tool calls are stdout-captured too, so a chatty plugin can never corrupt the protocol channel. Long-running calls don’t block the read loop — requests dispatch concurrently, which is what makes cancellation work.

chatcli acp

A full Agent Client Protocol server: sessions with chat/agent/coder modes, structured tool calls and plan updates, slash commands and native IDE permission dialogs — the way to run ChatCLI inside JetBrains IDEs and Zed.
  • Structured updates — agent/coder runs emit native tool_call/tool_call_update, agent_thought_chunk and plan frames; the IDE renders collapsible tool calls and a live plan instead of a streamed transcript.
  • Slash commands/coder, /config, /model and a headless allowlist are advertised to the client and work from the IDE prompt box.
  • Permission dialogs — dangerous commands and security-policy ask rules raise session/request_permission (the IDE’s native dialog with allow/reject, once/always) instead of blanket auto-approve/block.
  • Cancellationsession/cancel interrupts an in-flight prompt and closes any open tool call.
  • Session restoresession/load (capability loadSession: true) brings a prior session id back to life (live state, or its mcp-<id> autosave mirror after a restart) and replays the conversation into the client; /session from the prompt box operates per session and binds to named sessions for cross-surface continuity.
Full setup (JetBrains ~/.jetbrains/acp.json, Zed agent_servers), the command surface, security model and protocol details live on the dedicated page: ACP — ChatCLI inside your IDE.

See also