AI Trading MCP runs as two completely separate OS processes that communicate over a local HTTP bridge. The boundary is deliberate: Claude Code and the trading engine have independent lifecycles, and crashing or restarting one cannot corrupt the other’s state. Understanding this model is essential before going live.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/backtest-kit/ai-trading-mcp/llms.txt
Use this file to discover all available pages before exploring further.
The Two-Process Model
npx -y @backtest-kit/mcp@latest) lives inside Claude Code’s process tree. It is stateless: it knows nothing about open positions, candle history, or the Telegram feed. Its only job is to receive JSON-RPC tool calls from Claude over stdio and relay them to the trading process over HTTP.
The trading process (@backtest-kit/cli, started with npm start) owns all state: the engine loop for every symbol, the Telegram scraper, the broker adapter, the persistence layer, and the audit trail. It exposes the HTTP bridge on 127.0.0.1:60051 and remains running regardless of what happens in the Claude Code session.
The HTTP Bridge
The bridge is started by theserve() call at the bottom of config/setup.config.ts:
127.0.0.1:60051. Both values are overridable via environment variables:
| Variable | Default | Purpose |
|---|---|---|
CC_MCP_HOST | 127.0.0.1 | Interface the bridge listens on |
CC_MCP_PORT | 60051 | Port the bridge listens on |
.env propagates automatically to both ends.
The Error Envelope
Transport success is not operation success. When the engine rejects a tool call — for example,open_position against a symbol that already holds an open position — the HTTP response still returns 200. The result payload carries an error field:
- If the operation succeeded:
erroris an empty string. - If the operation failed:
errorcontains the engine’s exact rejection message.
isError: true tool result. Claude can read the message and decide whether to retry, close an existing position first, or report the failure to the user. Nothing is silently swallowed.
This envelope pattern means you cannot tell from the HTTP status code alone whether a trade was placed. Always check the
error field in integration tests and monitoring scripts.mcp.servers.json
mcp.servers.json in the repo root is the config file Claude Code reads when you run npm run start:claude:
npx -y @backtest-kit/mcp@latest as a child process and communicates with it over stdio JSON-RPC. The @latest tag means you always pick up the current published version of the MCP server package without a local install step.
MCP Schema Registration
Themanual_mcp schema is registered in packages/agent/src/config/setup.ts using addMCPSchema from backtest-kit. This is the single integration point that wires the Telegram feed and portfolio state into the get_status tool result:
ioc.statusControllerService.getStatus composes everything the model sees on every get_status call: the engine’s portfolio snapshot (one message per symbol), command history, and the last 15 Telegram posts including any chart screenshot image blocks.
config/loader.config.ts imports @pro/agent and @pro/main into the CLI runtime:
config/alias.config.ts maps those package names to the compiled output so the CLI can resolve them at start-up:
npm run build must be run before npm start — the aliases point to build artifacts that don’t exist until the workspace packages are compiled.
Concurrency: the queued() Wrapper
StatusControllerService wraps its getStatus implementation in a queued() utility from functools-kit. This means only one get_status fetch can be in flight at a time — if Claude sends a second call while the first is still awaiting the Telegram fetch, the second call lines up and waits rather than spawning a parallel GramJS request. This prevents concurrent calls from stampeding the Telegram client, which is a single persistent connection. A 90-second timeout guards against a hung fetch; if it fires, the connection is torn down and rebuilt on the next call, and the agent receives a clean error it can act on.Persistence Wiring
config/setup.config.ts configures the persistence backend for each engine subsystem. In live mode, state survives process restarts:
| Subsystem | Live mode | Backtest / paper mode |
|---|---|---|
Signals (SessionLive) | Persisted to dump/data/ | Local (in-process) |
| Storage | Persisted to dump/data/ | In-memory |
| Recent | Persisted to dump/data/ | In-memory |
| Notifications | Persisted to dump/data/ | In-memory |
| Memory | Persisted to dump/data/ | Local |
| State | Persisted to dump/data/ | Local |
dump/report/*.jsonl — one file each for live, performance, max_drawdown, and highest_profit. Restart the trading process and the open position, its OCO brackets, and its full history are still present.
Why the Two-Process Design Matters
Splitting the agent and the trading engine into separate processes has two critical consequences:- Claude Code can restart without affecting the trading process. If you close the Claude Code session, lose your terminal, or restart the agent, all open positions remain active. The trading process keeps running, its engine loop keeps ticking, and TP/SL orders remain on the book (in live mode). Nothing is liquidated by an agent crash.
-
The trading process can restart without losing state. Because live-mode subsystems are persisted to disk, restarting
npm startafter a server reboot or a dependency update brings the engine back to the exact state it left: same open positions, same bracket orders, same signal history. The model will see the recovered state on its nextget_statuscall.