Daemon Mode
Keep MCP connections warm between CLI invocations. Eliminate server startup overhead for stdio subprocesses and reduce latency for HTTP connections.
The Problem
Without a daemon, every mcp2cli command:
- Starts a fresh process
- Reads config
- Spawns a subprocess (stdio) or opens an HTTP connection
- Sends
initialize+initialized - Performs the actual operation
- Tears everything down
For stdio servers especially, steps 2–4 can take 1–5 seconds — unacceptable for interactive use or tight automation loops.
The Solution
The daemon holds the MCP connection open as a background process. CLI invocations detect the running daemon and route requests through a Unix socket — skipping initialization entirely.
sequenceDiagram
participant D as Daemon Process
participant S as MCP Server
participant C1 as CLI Invocation 1
participant C2 as CLI Invocation 2
Note over D,S: Daemon starts and initializes once
D->>S: initialize + initialized
S-->>D: Server capabilities
Note over C1: First command — instant
C1->>D: echo --message hello (via Unix socket)
D->>S: tools/call
S-->>D: Result
D-->>C1: Result
Note over C2: Second command — also instant
C2->>D: add --a 5 --b 3 (via Unix socket)
D->>S: tools/call
S-->>D: Result
D-->>C2: Result
Usage
Start a Daemon
mcp2cli daemon start my-serverThis:
- Loads the named config
my-server - Forks a background process
- Initializes the MCP connection (with a ping)
- Writes a PID file and creates a Unix socket
- Returns immediately — the daemon runs in the background
Check Status
# Status for a specific configmcp2cli daemon status my-server
# Status for all configsmcp2cli daemon statusOutput:
my-server: running (pid 12345, socket /home/user/.local/share/mcp2cli/instances/my-server/daemon.sock)other-server: not runningStop a Daemon
mcp2cli daemon stop my-serverSends SIGTERM to the daemon process and cleans up the PID file and socket.
Automatic Detection
You don’t need to change your commands. When a daemon is running, mcp2cli automatically detects it and routes requests through the socket:
# Without daemon: spawns subprocess, initializes, calls tool, tears downwork echo --message hello # ~2s
# Start daemonmcp2cli daemon start work
# With daemon: connects to socket, calls tool, donework echo --message hello # ~50msThe detection happens in build_client():
- Check if
instances/<name>/daemon.jsonexists - Verify the PID is still alive
- Verify the Unix socket exists
- If all checks pass → use
DaemonMcpClientinstead of direct transport
Daemon Protocol
The daemon communicates over a Unix socket using a simple newline-delimited JSON protocol:
Client → Daemon: {"InvokeAction":{"capability":"echo","arguments":{"message":"hello"},"background":false}}\nDaemon → Client: {"Action":{"message":"...","capability":"echo","content":[...],"data":{...}}}\nEach request is one line of JSON (a serialized McpOperation), and the response is one line of JSON (a serialized McpOperationResult or error envelope).
File Layout
| File | Purpose |
|---|---|
instances/<name>/daemon.json | PID file with process metadata |
instances/<name>/daemon.sock | Unix domain socket for IPC |
PID File Format
{ "pid": 12345, "config_name": "work", "socket_path": "/home/user/.local/share/mcp2cli/instances/work/daemon.sock", "started_at": "2026-03-30T10:15:30Z"}Graceful Shutdown
The daemon handles:
- SIGTERM — graceful shutdown, cleans up PID file and socket
- SIGINT (Ctrl+C) — same as SIGTERM
- Stale detection — if the PID file exists but the process is dead, mcp2cli cleans up automatically
Foreground Mode
For debugging, run the daemon in the foreground:
MCP2CLI_DAEMON_FOREGROUND=1 mcp2cli daemon start workThis keeps the process attached to your terminal with full log output.
Practical Examples
Development Workflow
# Start daemon for your dev servermcp2cli daemon start dev
# Rapid iteration — each call is instantdev echo --message test1dev echo --message test2dev deploy --version 1.0
# Done for the daymcp2cli daemon stop devMultiple Daemons
mcp2cli daemon start devmcp2cli daemon start stagingmcp2cli daemon start prod
# Each alias auto-routes to its daemondev lsstaging lsprod ls
# Check allmcp2cli daemon statusCI/CD with Warm Connections
# Start of pipelinemcp2cli daemon start ci-server
# Run multiple commands without re-init overheadwork --json ls | jq '.data.items | length'work echo --message "smoke-test"work --json doctor | jq '.data.server'
# End of pipelinemcp2cli daemon stop ci-serverLimitations
- Unix-only (requires Unix domain sockets)
- No ad-hoc connections (daemon requires a named config)
- One daemon per config name
- The daemon does not auto-restart if the underlying MCP server crashes
See Also
- Transports — understand what the daemon keeps warm
- Request Timeouts — timeouts still apply through the daemon
- Named Configs & Aliases — daemon requires named configs