vike
Guides

Connect an agent

Point Claude at vike-cli mcp — 17 tools to author strategies, run backtests, watch a live node, and (behind a preview gate) trade.

vike-cli mcp is a local stdio MCP server that exposes Vike's agent surface as tools: an agent can author and validate a Rhai strategy, run backtests, sweeps and walk-forwards against a data service, read a running trading node's live state, and — gated behind a mandatory preview — place and manage orders on it. The client-side preview is UX; the node's own limits and the core risk gate are what actually enforce.

This page is the Trader-side summary. Build with AI is the same server documented as an MCP surface — Client setup per client (Vike's remote data server is a separate entry the same client can hold at the same time; it is set up on Data client setup), and Trader tools tool by tool.

Add the server

vike-cli mcp speaks MCP's stdio transport (newline-delimited JSON-RPC 2.0), so any MCP client can launch it directly. Two optional flags scope what the tools can reach:

  • --addr <host:port> — the vike-datahub server the backtest tools use (default 127.0.0.1:7878),
  • --node <host:port> — the running vike-tradehub node the trade tools observe and control (no default; without it the create+backtest tools still work, node_snapshot returns a clean error, and a write tool still previews — what errors is a call that passes the gate, carrying both confirm: true and a valid preview_token, and finds no node to send to).

Two more decide which tools the session has at all, and they belong in the same entry:

  • --profile full|read-only|offline — the default is full, all seventeen. read-only serves the ten read tools and withholds the seven order-write ones; offline serves only the four that open no socket. A withheld tool is absent from tools/list as well as refused if called, because the advertised roster and the routing gate are two complements of one pass over the registry (ToolAccess::new, crates/vike-cli/src/cmd/mcp.rs) rather than two lists that can disagree.
  • --deny-tool <name> — withhold one more by name, repeatable.

An unknown value for either is a usage error naming the valid set and never widens to full. Only whoever edits the launch command can change the scope; the agent cannot, and the refusal it gets says so instead of sending it hunting for a switch.

Claude Code:

claude mcp add vike -- vike-cli mcp --node 127.0.0.1:7879

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "vike": {
      "command": "vike-cli",
      "args": ["mcp", "--node", "127.0.0.1:7879"]
    }
  }
}

Node keys

The node tools authenticate with two HMAC keys, resolved from the process environment first and then from the same credential store the daemon reads (<project>/settings/secrets.env):

  • VIKE_TRADEHUB_OBSERVE_KEY — reads (node_snapshot),
  • VIKE_TRADEHUB_CONTROL_KEY — writes (the seven tools below, set_trading_state included).

If a key is in neither place, the affected tools return an error naming both locations (vike-cli secrets path prints where the store resolves; vike-cli secrets list shows key names, never values).

Verify it works

Ask Claude:

show me the node snapshot

That calls the read-only node_snapshot tool and returns the node's live state — orders, positions, per-venue equity, recent events. With no node configured you can still verify the offline half: "list the vike strategy templates" calls list_templates with no server at all.

The 17 tools

Read-only (safe, readOnlyHint):

ToolWhat it doesNeeds
validate_strategyCompile a Rhai strategy — compile is validationnothing (offline)
discover_paramsList a script's tunable param(name, default) knobsnothing (offline)
list_templatesStarter Rhai strategies as {name, code}nothing (offline)
list_indicatorsThe host-bound built-in roster; never your user_data/indicatorsnothing (offline)
run_backtestRun a profile TOML on the datahub, return the report--addr reachable
run_sweepParameter-grid sweep, server-ranked--addr reachable
run_walk_forwardAnchored out-of-sample walk-forward--addr reachable
list_strategiesThe compiled native strategies the server offers--addr reachable
list_seriesEvery stored data series, with coverage--addr reachable
node_snapshotLive node state: orders, positions, equity, events--node + observe key

Order-write (destructiveHint, all preview-gated, all need --node + the control key): submit_order, cancel_order, modify, flatten, market_exit, mass_cancel, set_trading_state. This is the full write-verb roster of the human trade REPL — both surfaces build commands through the same construction site (crate::cmd::verbs), so the two can never drift.

A worked flow

A typical create-and-test session, tool by tool:

  1. list_templates — start from a shipped starter (SMA cross, RSI reversion, Donchian breakout), each parameterized via param(). Read the body before trusting the name: the Donchian starter is a shape, not the indicator — it stands in with sma, because a bare donchian(...) is not bound: its first output line is upper rather than the namesake, so only the per-line accessors (donchian_upper() and its siblings) are callable.
  2. validate_strategy — compile the edited script. A bad script is an ok: false answer with the compiler error, not a tool failure — the agent reads it and fixes the script.
  3. run_backtest — ship a profile TOML (the agent can inline the script via the script argument) and read the returned report JSON.
  4. run_sweep — the same profile with a [sweep] table; the server returns the ranked grid, best first. Follow with run_walk_forward before believing a search.

The safety model

Stated from the source, because an agent with order-writing tools deserves an exact contract:

  • Paper by default, twice over. A venue with no credentials in <project>/settings/secrets.env mounts as paper — absent credentials are the live gate — and the per-venue ceiling policy.venues.<venue> in policy.toml defaults to paper and can only ever refuse: the fold that applies it is a minimum, never a maximum (crates/vike-config/src/venue_mode.rs's VenueMode::cap), so a live line arms nothing by itself. Nothing an MCP tool does can arm a venue.
  • Mandatory preview on every write, and the confirm needs a token. A write executes only on a call carrying both confirm: true and the preview_token an earlier preview of that same command returned. Anything less previews: it returns the fully resolved wire command, a client-side guardrail check, the rationale that would be recorded, and a fresh token. This is not convention — it is the code path: in crates/vike-cli/src/cmd/mcp.rs, Server::call_tool reads confirm as exactly the JSON boolean true (the string "true" previews too) and looks the token up in PendingPreviews, which fires it once, expires it after 60 seconds and binds it to the command it previewed. ⚠ A confirming call with no token is the dangerous shape, because it is not an error: it returns another preview, will_execute: false, isError: false. Read will_execute, never the absence of an error. A preview is also not necessarily offline — with --node set and a control key present it dials the node for a dry-run verdict (Server::node_preview); what it never does is send the command. And the gate is not the only answer available: --profile read-only in the launch command above hands the agent a server whose tools/list does not contain a write tool at all, which is the right shape when the session's job is to read and report.
  • The node is the enforcing gate, not the client. The preview's guardrail (the local policy.toml notional ceiling) is advisory UX. What enforces is server-side on the vike-tradehub node — crates/vike-tradehub/src/server.rs's ControlLimits::vet, a per-connection rate token bucket plus the notional cap built from ControlLimitsConfig, whose ceiling comes from the node's policy.toml (max_notional_per_order) — and, beneath it, the execution core's RiskGate. An agent cannot loosen either from the client side. The two have different reach: the rate token is spent on every command, while the notional cap only judges order-increasing verbs that carry a price (submit_order, modify) — a flatten or mass_cancel is rate-limited but never size-checked, which is the right way round for commands that only reduce exposure.
  • Every order carries a client order id. The node refuses a remote submit with an empty client_order_id, so the local MCP server mints one before the preview renders (crates/vike-cli/src/cmd/verbs.rs's fill_client_order_id — the same generator and wire form the live core uses). The agent does not have to carry that id back: a confirming call executes the stored command rather than the one it rebuilt, so the id that reaches the venue is the id the preview displayed — which is also why same_intent ignores exactly this field when it binds a token to its command. client_order_id in the accepted response is always the authoritative id. The node's registry is coid-keyed but does not dedupe: a repeated id re-sends the order and replaces its registry row.
  • Honest outcomes, per command. Each write tool reports the fate of its own command: accepted, a named refusal, or — on a timeout or dropped connection — an explicit unknown telling the agent to check node_snapshot before retrying, because the command may have executed. There is no shared error latch that could misattribute an old refusal to a new command.
  • A recorded "why". Every write tool takes an optional reason string — the agent's rationale. It is echoed in the preview, sanitized server-side, and lands in the node's audit trail; it never reaches the order, the core, or a venue. The sanitizer is sanitize_reason in crates/vike-tradehub/src/audit.rs: every Unicode control character is stripped, the text is capped at 512 characters (MAX_REASON_CHARS), and a result that comes back empty is recorded as no rationale at all.
  • A record of what was attempted, if you ask for it. The node's trail holds accepted commands only, so a refusal reaches it never — it was refused before a byte left the MCP process. Launch the server with --trace and it appends one JSONL entry per tool call under <project>/settings/state/agent/: the tool, the profile, the arguments and a verdict of ok, preview, refused or error (crates/vike-cli/src/cmd/mcp_trace.rs). It is off unless the flag is given, and it records no secret — credential-shaped argument keys, and credential-shaped SHOUTING_CASE identifiers inside string values, are both redacted — and, for a gated write, the preview token's identity rather than its bytes.

market_exit is the panic button

market_exit cancels every live order and then flattens every net position (optionally scoped to one venue; a hedge-mode long/short leg has no net bucket and is skipped). It is preview-gated like every other write, but treat it as the incident tool it is.

On this page