vike
Tools

node_snapshot

The one read tool against a running vike-tradehub node — orders, positions, per-venue equity, recent events — and the tool that settles an ambiguous write.

node_snapshot reads the live state of a running vike-tradehub node. It is the only read-only tool in vike-cli mcp that talks to a node rather than to a datahub, annotated readOnlyHint: true and openWorldHint: true in tools/list (crates/vike-cli/src/cmd/mcp.rs's tools_spec). It needs --node <host:port> and VIKE_TRADEHUB_OBSERVE_KEY — the observe key, not the control key (crates/vike-cli/src/cmd/nodekeys.rs's OBSERVE_KEY_ENV).

Input schema

It takes no arguments: "inputSchema": { "type": "object", "properties": {} }. It is also the one node tool with no reason property — a read has no rationale to file, and the tools/list test in crates/vike-cli/src/cmd/mcp.rs asserts the property is absent.

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"node_snapshot","arguments":{}}}

What comes back

Server::tool_node_snapshot serializes the node's WireSnapshot as-is — "already a flat, serde projection". The schema is crates/vike-tradehub-client/src/wire.rs's WireSnapshot, a standalone mirror of the core's rendered snapshot rather than the core type itself, so an internal refactor cannot silently change what an agent reads:

FieldWhat it holds
seqper-publish sequence number; 0 means no real frame has arrived yet
venue, symbolthe primary engine's mount
trading_stateActive, Reducing or Halted for the primary engine
balancethe primary venue's cash balance
equity_totalcross-venue total equity
venuesper-venue ledger blocks — balance, realized PnL, fees, funding, equity, unrealized, margin used, free buying power, that venue's own trading_state, and its positions
ordersthe order registry in insertion order, spanning every engine; status is the rendered string
positionsthe primary venue's positions — the documented mirror of venues[0].positions
held_exitspending bracket exits held off the venue until their OTO parent fills; empty on non-bracket runs
recent_eventsthe bounded delivered-event tail, already rendered to lines
faultset once a handler panicked — the core is halted in safe state
barsbounded OHLCV tails for the chart
identitywhich daemon, which strategy, paper or live, which build

bars and identity are #[serde(default)], so a node that predates either field simply omits it.

Two bounds are applied node-side, in crates/vike-tradehub/src/publish.rs's project. bars is filtered to the primary (venue, symbol) only and tail-sliced to CHART_BARS_CAP closed bars plus the forming candle — the core's own bar vector is unbounded and would eventually overflow the framer. recent_events is the core's own bounded ring.

How fresh it is, and what it is not

The observe connection is opened lazily on the first call and then kept open — it stays subscribed so the node keeps pushing frames, which is why the MCP server holds persistent connections rather than dialling per call. A freshly-subscribed connection answers with WireSnapshot::empty (seq: 0) until the first frame lands, so tool_node_snapshot polls every 50 ms for up to about two seconds for a real one before returning.

The observer is lossy by contract

You get the latest published state, never every intermediate one. The node's publisher samples the core's arc-swap cell on a POLL_INTERVAL of 15 ms against a core that publishes coalesced at 16 ms or slower, and each subscriber's mailbox is a bounded MAILBOX_CAP drop-oldest queue, so a slow reader loses old frames rather than back-pressuring the publisher (crates/vike-tradehub/src/publish.rs). Never treat two consecutive snapshots as a complete event history — recent_events is a tail, not a ledger.

Nothing here touches the core's hot fold. The publisher's only interaction with the core is one atomic load of the already-published snapshot, on its own thread; reading a snapshot cannot slow the node down.

Its other job: settling an ambiguous write

Every write tool points here when it cannot answer. Server::execute waits ACK_WAIT — two seconds — for the node's verdict on the command it just sent, and two of the four outcomes are genuinely unknown rather than failed: a timeout returns outcome: "unknown", and a dropped control connection returns an error saying the outcome is unknown and the command may have executed. Both say the same thing: call node_snapshot before retrying, because retrying blind is how one intent becomes two orders. Acceptance is the same story from the other side — it means the node took the command, not that the order filled.

When it errors

Both failures are clean tool errors, never panics.

  • No node configured — ensure_observe returns no vike-tradehub node configured — pass --node before any network work happens; node_snapshot_without_node_is_a_clean_error pins it.
  • No observe key — the error names both places the key is looked for, the process environment and the credential store, and points at vike-cli secrets path and vike-cli secrets list. The message says both because it once said only "not set in the environment" while the daemon's own keys sat unread in the store.

A non-null fault is not a tool error but is the most important thing in the payload: the core entered safe state, which halts every engine and sweeps its working orders (crates/vike-core/src/runtime/watchdog.rs's enter_safe_state).

Concepts: Portfolio and snapshot, The node protocol. Tools: set_trading_state, market_exit.

Show me the node snapshot — what is open, where is the equity, and is anything faulted?

On this page