vike
Tools

MCP tools

The seventeen tools vike-cli mcp advertises, what each one reaches, the profile that can withhold whole rings of them, and the gates — confirm plus a single-use preview_token — that stand between an agent and a real order.

tools/list returns the whole registry in one response. tools_spec() in crates/vike-cli/src/cmd/mcp.rs is that registry — every tool's name, description, input schema and risk annotations — and Server::call_tool's match name is the dispatch half. Each tool has its own page below: what it does, its schema, a call you can paste into a stdio session, the shape that comes back, and one prompt that reaches it.

Three planes, and what each one needs

The tools split by what they touch, not by what they do. Nothing in the first group opens a socket at all.

PlaneToolsNeeds
Offline — pure vike-script, no servervalidate_strategy · discover_params · list_templates · list_indicatorsnothing
A vike-datahub serverrun_backtest · run_sweep · run_walk_forward · list_strategies · list_series--addr, default 127.0.0.1:7878 (DEFAULT_ADDR)
A running vike-tradehub nodenode_snapshot--node + the observe key
The same node, order-writesubmit_order · cancel_order · modify · flatten · market_exit · mass_cancel · set_trading_state--node + the control key

The two halves fail separately and the offline four never notice: Server::ensure_observe and Server::ensure_control run before any socket is opened, and a missing key produces an error that names both places it looked. The server page has the flag and key detail.

The registry a session sees can be smaller than this

tools/list returns the whole registry only under the default --profile full. An operator who launches the server as --profile read-only serves the first three rows above and withholds the fourth; --profile offline serves only the first; --deny-tool NAME takes out one more, and is repeatable. A withheld tool is absent from the advertised registry as well as refused by tools/call, because ToolAccess::new produces the advertised set and its withheld complement from one pass over tools_spec() — an advertised-but-refused tool, or a withheld-but-routed one, is the bug a scoping feature must not ship with. The rings are predicates rather than second rosters: read-only is the negation of is_write_tool (so an eighth write verb joins it by construction) and offline is each tool's own openWorldHint annotation read back. Which tools each ring leaves you, and how a refusal reads, is on vike-cli mcp.

Every result has the same shape

A success is tool_ok: the payload pretty-printed into one text content block, the same value again as structuredContent, isError: false. A failure is tool_err — the message as text with isError: true. That is an ordinary tool result, not a JSON-RPC error, so the agent reads it and retries rather than seeing the call fail at the protocol layer. Even a panicking tool arrives that way: Server::handle wraps every call in catch_unwind and turns a panic into tool panicked: <name>, pinned by a_panicking_tool_becomes_iserror_not_a_dead_session.

Ten read, seven write

The split is machine-pinned rather than conventional. Every read-only tool carries readOnlyHint: true and every write tool carries destructiveHint: true in tools_spec(), and tools_list_has_read_and_write_tools_with_correct_hints fails the build if a tool falls on the wrong side — it also asserts each write tool's description mentions confirm, so at least half the gate is part of the advertised contract. Only half: the description is what that test reads, and the schema carries the other half. Both properties are defined once and spliced into all seven tools — confirm_property and preview_token_property — so the wording cannot drift between them, which is how the old inline copies ended up in four different spellings. The write roster is a fixed-size const, WRITE_TOOLS: [&str; 7], because it must stay the full write-verb set of the human trade REPL: both surfaces build their commands through the one construction site in crate::cmd::verbs, so they cannot drift into two vocabularies.

A write needs confirm: true AND a preview_token — and one without the other is a preview, not an error

Server::call_tool's write arm reads the two together: a preview_token is only looked up when confirm is the JSON boolean true, and a confirm with no token binds nothing. Fail either condition and preview_of returns the resolved wire command, the advisory guardrail check, the node's own dry-run when there is a node to ask, the rationale that would be recorded — and a fresh preview_token. Nothing is sent, and nothing is flagged: will_execute: false is the only signal. confirm is read as a JSON boolean and nothing else, so "true", 1 and "yes" fall through the same way.

A token that is unknown, already used, expired past PREVIEW_WINDOW or bound to a different command is the loud case — a tool error naming which. The mechanism, and why the token is deliberately not a secret, is on Live node.

The arming ceiling applies to every order-placing tool

A write tool mounts nothing. It hands a WireCommand to a node that is already running, and what that node may do to a venue was decided at its mount, not here. vike_mount::make_engine consults the deployment's per-venue arming ceiling — policy.venues.<venue>, ordered paper < demo < live — first, above the credential read: a paper venue returns the paper client having loaded no credential, fetched no instrument grid and opened no socket. The ceiling can only ever refuse, because vike_config::VenueMode::cap is min and never max, so venues.bybit = "live" does not put bybit live — it declines to stop it. Below that sits the older rule, that absent credentials are the live gate.

Two more gates stand between an accepted command and a fill, and both are server-side on the node: ControlLimits::vet consumes a rate token on every command and applies its notional cap only to the order-increasing verbs that carry a price (Submit and Modify — cancel, flatten, mass-cancel, market-exit and set-trading-state are risk-reducing and never size-capped), and beneath it the execution core's RiskGate. The preview's own guardrail is client-side advisory UX; nothing an agent sends from here can loosen either. Risk and arming is the concept page, policy.toml the key.

Where to start

Drive Vike from Claude runs the whole loop end to end; reference/cli/mcp is the verb that starts the server.

On this page