1.0.13npm · @traderouter/trade-router-mcp · latest release
Observed 2026-08-22T06:28:58.288Z using mcpSecurity-inventory. Protocol 2025-06-18.
| Tool | Category | Risk |
|---|---|---|
auto_swapBuilds, signs, and submits a Solana swap in a single call. Equivalent to build_swap → local sign → submit_signed_swap, but the MCP server handles the encoding conversion (base58 → base64) for you.
WHEN TO USE: For most swaps. This is the simplest path. Use build_swap + submit_signed_swap separately only when you need to inspect or modify the transaction before signing (e.g. agent-layer validation of the output amount).
WHAT IT DOES: Calls /swap to get an unsigned tx, signs it locally with TRADEROUTER_PRIVATE_KEY (key never leaves the process), submits via /protect (Jito MEV-protected). Returns the swap details and confirmation in one response.
RETURNS: { swap: { swap_tx, pool_type, amount_in, min_amount_out, price_impact, slippage, decimals }, protect: { status, signature, sol_balance_pre, sol_balance_post, token_balances } }. If swap-build fails, only the swap object is returned with status="error".
SIDE EFFECTS: Submits a real on-chain transaction (unless TRADEROUTER_DRY_RUN=true, which short-circuits to { dry_run: true, tool, args }). Requires TRADEROUTER_PRIVATE_KEY to be set.
⚠️ TRUST: This tool signs whatever transaction the server returns without inspecting the bytes against the requested swap parameters. If api.traderouter.ai is compromised, a malicious server could return a transaction that drains your wallet. Mitigations: use TRADEROUTER_DRY_RUN for testing; use a dedicated trading wallet with limited balance; or use build_swap + submit_signed_swap with your own decode+verify step. See SECURITY.md.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58). Must match the wallet derived from TRADEROUTER_PRIVATE_KEY."
},
"token_address": {
"type": "string",
"description": "SPL token mint address (base58)."
},
"action": {
"type": "string",
"enum": [
"buy",
"sell"
],
"description": "\"buy\" spends SOL to receive token; \"sell\" spends token to receive SOL."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for action=\"buy\". Lamports (1 SOL = 1e9 lamports). Example: 100000000 = 0.1 SOL."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "REQUIRED for action=\"sell\". Basis points of current holdings (10000 = 100%)."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 1500,
"description": "Slippage tolerance in basis points (default 1500 = 15%). Memecoins typically need 1500-2500."
}
}
} | — | — |
build_swapBuilds an unsigned Solana swap transaction via POST /swap. Returns the transaction as base58 — the caller must decode, sign locally, re-encode as base64, and submit via submit_signed_swap.
WHEN TO USE: When you want to inspect or modify the transaction before signing (e.g. agent-layer validation), or when you want to control the sign+submit flow yourself. For a one-step swap, use auto_swap instead.
WHAT IT DOES: Calls api.traderouter.ai/swap with wallet_address, token_address, action ('buy' or 'sell'), and either amount (lamports, for buy) or holdings_percentage (bps, for sell). The server picks the best DEX route across Raydium, PumpSwap, Orca, and Meteora based on liquidity, builds a VersionedTransaction, and returns it base58-encoded.
RETURNS: On success: { status: "success", data: { swap_tx, pool_type, pool_address, amount_in, min_amount_out, price_impact, slippage, decimals } }. The pool_type field is an open enum (treat unknown values gracefully). On error: { status: "error", error, code }. "Error running simulation" usually means the route is unsellable right now (dead pool, zero balance, no route) — do not retry-loop.
SIDE EFFECTS: None. This tool does NOT submit or sign anything.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58, 32-44 chars). Usually the same value returned by get_wallet_address."
},
"token_address": {
"type": "string",
"description": "SPL token mint address (base58). Example: DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 for BONK."
},
"action": {
"type": "string",
"enum": [
"buy",
"sell"
],
"description": "\"buy\" spends SOL to receive token; \"sell\" spends token to receive SOL."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for action=\"buy\", FORBIDDEN for action=\"sell\". Lamports of SOL to spend (1 SOL = 1,000,000,000 lamports). Example: 100000000 = 0.1 SOL."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "REQUIRED for action=\"sell\", FORBIDDEN for action=\"buy\". Basis points of current holdings to sell (10000 = 100%). Example: 5000 = sell 50%."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 1500,
"description": "Maximum slippage in basis points (10000 = 100%). Default 1500 (15%). For low-liquidity or newly-launched tokens use 1500-2500. 500 bps will often fail on memecoins."
}
}
} | — | — |
cancel_orderCancels an active limit, trailing, TWAP, or combo order. Once cancelled, the order is removed server-side and no further fills will arrive.
WHEN TO USE: To kill an order before it triggers (e.g. you no longer want to take that position) or to halt remaining TWAP slices.
WHAT IT DOES: Sends { action: "cancel_order", order_id } over the WebSocket. Server removes the order from its scheduler and confirms with { type: "order_cancelled", order_id } (or { type: "twap_order_cancelled" } for TWAP orders).
RETURNS: { wallet, order_id, status: "cancelled" }. Idempotent — cancelling an already-cancelled or already-filled order returns an error but is safe to retry.
SIDE EFFECTS: Stops all future fills for the order. For partial-fill TWAP orders, slices already executed are not reverted; only remaining slices are skipped.Input schema{
"type": "object",
"required": [
"wallet_address",
"order_id"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"order_id": {
"type": "string",
"description": "The order_id to cancel."
}
}
} | — | — |
check_orderReturns the current status of a specific order by order_id. More targeted than list_orders.
WHEN TO USE: To check whether a known order has triggered, expired, or been cancelled. Useful when polling for a specific order's outcome rather than scanning the full list.
WHAT IT DOES: Sends { action: "check_order", order_id } over the WebSocket. Server returns { type: "order_status", order_id, status, ... }.
RETURNS: { wallet, order_id, status: "active"|"triggered"|"filled"|"cancelled"|"expired", ... }. If the order doesn't exist (already expired or cancelled), the server returns an error.
SIDE EFFECTS: None — pure read. Does not affect the order state or trigger any server-side processing.Input schema{
"type": "object",
"required": [
"wallet_address",
"order_id"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"order_id": {
"type": "string",
"description": "The order_id returned by a place_*_order call. Format: a server-assigned UUID-like string."
}
}
} | — | — |
connect_websocketOpens (or reuses) the persistent WebSocket connection to wss://api.traderouter.ai/ws for a wallet, performs the Ed25519 challenge-response handshake, and waits up to 25 seconds for the "registered" confirmation.
WHEN TO USE: Before placing limit / trailing / TWAP / combo orders. get_wallet_address calls this implicitly, so you only need this tool to FORCE-reconnect or to register a wallet other than the env-derived one.
WHAT IT DOES: Connects to the WebSocket, receives the server's challenge { type: "challenge", nonce }, signs the nonce bytes with TRADEROUTER_PRIVATE_KEY (Ed25519), sends { action: "register", wallet_address, signature: "<base58>" }, waits for { type: "registered", authenticated: true }.
RETURNS: { wallet, message: "WebSocket connected and registered" | "WebSocket not yet registered; commands may be queued", connected: bool, registered: bool, ... }.
SIDE EFFECTS: Spawns/maintains a background WebSocket connection. If TRADEROUTER_PRIVATE_KEY is missing or doesn't match wallet_address, registration will fail with authenticated:false and order placement will be rejected.Input schema{
"type": "object",
"required": [
"wallet_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58). Must correspond to the keypair held in TRADEROUTER_PRIVATE_KEY for register to succeed."
}
}
} | — | — |
connection_statusReturns the current state of the persistent WebSocket connection for a wallet (connected, registered, last heartbeat time, queued message count).
WHEN TO USE: For debugging. If place_*_order calls are failing or hanging, check this first to see whether the WebSocket is actually authenticated.
WHAT IT DOES: Inspects the in-memory ConnectionManager for the given wallet — no network call.
RETURNS: { wallet, connected: bool, registered: bool, lastHeartbeat: <ISO timestamp>, ... }.
SIDE EFFECTS: None.Input schema{
"type": "object",
"required": [
"wallet_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
}
}
} | — | — |
extend_orderExtends the expiry time of an active limit or trailing order. expiry_hours sets the NEW total lifetime (counted from order creation, not from now).
WHEN TO USE: When you want to keep a pending order alive longer than the original expiry_hours allowed (max 336 = 14 days).
WHAT IT DOES: Sends { action: "extend_order", order_id, expiry_hours } over the WebSocket. Server updates the order's expires_at and confirms with { type: "order_extended", order_id }.
RETURNS: { wallet, order_id, expiry_hours, status: "extended" }. Cannot extend TWAP orders (they have no separate expiry — they live exactly duration seconds).
SIDE EFFECTS: Mutates server-side order state (expires_at field). The order continues from the same phase it was in — extending does not reset the trail high-water mark or restart the limit watcher. Idempotent if called with the same expiry_hours that already applies.Input schema{
"type": "object",
"required": [
"wallet_address",
"order_id",
"expiry_hours"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"order_id": {
"type": "string",
"description": "The order_id to extend."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"description": "New total lifetime in hours, counted from the original creation time. Max 336 (14 days). Cannot be less than the elapsed time since creation."
}
}
} | — | — |
get_fill_logReturns the in-memory log of all order_filled events received over the WebSocket since the MCP server process started (capped at 200 entries).
WHEN TO USE: Audit which orders have triggered, with their on-chain signatures. Useful for end-of-session reporting or debugging "did my order fill?"
WHAT IT DOES: Reads from the ConnectionManager's circular buffer. Does not query the API.
RETURNS: { wallet, fills: [{ order_id, order_type, signature, filled_at, triggered_mcap, filled_mcap, status, server_signature_verified }] }.
SIDE EFFECTS: None.
⚠️ NOT PERSISTED: This log is cleared when the MCP server restarts. For long-term audit, store fills externally as they arrive.Input schema{
"type": "object",
"required": [
"wallet_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
}
}
} | — | — |
get_flex_cardReturns the URL of a flex trade-card PNG that visualizes a wallet's position in a token (entry price, current PnL, etc.). Used for sharing trades on social media.
WHEN TO USE: After a notable swap, to generate a shareable image for X / Discord / Telegram.
WHAT IT DOES: Constructs the URL https://api.traderouter.ai/flex?wallet_address=W&token_address=T. Does NOT fetch the image — it returns the URL string for the caller to embed or share.
RETURNS: { url: "<full URL>", wallet_address, token_address }. The URL itself returns image/png when fetched. 400 on invalid params, 501 if flex-card image deps are not configured server-side, 500 on internal errors.
SIDE EFFECTS: None.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint address (base58)."
}
}
} | — | — |
get_holdingsScans every SPL token account on a wallet and returns the holdings list. Most accurate Solana wallet scanner available — catches tokens that standard RPC token-account scans miss.
WHEN TO USE: When you need the full token balance for a wallet, including obscure or newly-launched tokens, before deciding what to sell or display in a portfolio view.
WHAT IT DOES: Calls POST /holdings with the wallet address. Server enumerates every Token Program 2022 + SPL Token Program account, resolves liquid pool info per token, and returns the list.
RETURNS: { data: [{ address: "<mint>", valueNative: <lamports>, amount: <raw_units>, decimals }] }. Empty wallet returns {} (not an empty array). Apply a defensive valueNative > 0 filter on the caller side; some edge cases return stale data.
SIDE EFFECTS: None — pure read.
⚠️ TIMEOUT: Set client HTTP timeout to AT LEAST 100 seconds. Wallets with many tokens take time to fully scan.Input schema{
"type": "object",
"required": [
"wallet_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58). No signing required — public key only."
}
}
} | — | — |
get_mcapReturns market-cap and price data for one or more SPL tokens. Used by limit-order strategies to compute target market caps relative to current.
WHEN TO USE: Before placing a limit_order with a market-cap target (so you know what current mcap is), or for portfolio valuation.
WHAT IT DOES: Calls GET /mcap with comma-delimited mint addresses. Server queries its market-cap index (computed from liquid pool reserves) and returns per-token data.
RETURNS: An object keyed by mint address. Each value can include marketCap (USD), priceUsd, pair_address, pool_type. Empty object if no tokens are provided or none are found.
SIDE EFFECTS: None — pure read.Input schema{
"type": "object",
"required": [
"tokens"
],
"additionalProperties": false,
"properties": {
"tokens": {
"type": "string",
"description": "Comma-delimited SPL token mint addresses (base58). Example: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263,JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\"."
}
}
} | — | — |
get_wallet_addressReturns the public Solana wallet address derived from the TRADEROUTER_PRIVATE_KEY environment variable, and triggers the persistent WebSocket connection to api.traderouter.ai for that wallet.
WHEN TO USE: Call this once at session start, before any other Trade Router tool. The returned wallet address is the identity used by every other tool.
WHAT IT DOES: Reads the base58 private key from env, derives the Solana public key locally (no network call for derivation), then opens a WebSocket to wss://api.traderouter.ai/ws and authenticates via challenge-response signing of a server-issued nonce. The private key never crosses the network.
RETURNS: { configured: true, wallet_address: "<base58>" } on success. { configured: false, error: "TRADEROUTER_PRIVATE_KEY not set" } if the env var is missing — in that case, only read-only tools (get_holdings, get_mcap, get_flex_card) will work for arbitrary wallets, and write tools will fail.
SIDE EFFECTS: Spawns a background WebSocket connection that persists for the lifetime of the MCP server process.Input schema{
"type": "object",
"properties": {},
"additionalProperties": false
} | — | — |
list_ordersReturns all currently active orders (limit, trailing, TWAP, combo) for a wallet. Used to audit pending orders and find order_ids for cancel_order or extend_order.
WHEN TO USE: Periodically, to detect expired orders (the server does NOT push an expiry event — orders silently disappear from results when expiry_hours is reached). Also to confirm that a place_*_order call actually registered.
WHAT IT DOES: Sends { action: "list_orders" } over the WebSocket. Server returns { type: "order_list", orders: [{ order_id, order_type, token_address, target_mcap, trail_bps, amount, holdings_percentage, slippage, expires_at, status, ... }] }.
RETURNS: { wallet, orders: [...] }. Empty array if no active orders. Each order includes its current phase (e.g. limit_trailing_twap can be in "limit-watching", "trailing-watching", or "twap-executing" phases).
SIDE EFFECTS: None — pure read.Input schema{
"type": "object",
"required": [
"wallet_address"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58). Must be registered on the WebSocket (via get_wallet_address or connect_websocket) for the request to succeed."
}
}
} | — | — |
place_limit_orderPlaces a market-cap-triggered limit order over the WebSocket. The server polls market cap ~every 5 seconds and fires the swap when the target is crossed.
WHEN TO USE: When you want to enter or exit at a specific market-cap level, not at current price. Examples: "buy BONK when its mcap drops to $500M", "sell BONK when its mcap doubles".
WHAT IT DOES: Sends { action: "sell"|"buy", token_address, target, slippage, expiry_hours, ... } to the server over WS. Server registers the order, returns { type: "order_created", order_id, params_hash, server_signature }. The MCP verifies server_signature against the Ed25519 trust anchor before treating the order as accepted.
TARGET SEMANTICS: target is in basis points relative to the CURRENT mcap at order placement (NOT your wallet entry price). For SELL: target > 10000 = take-profit (e.g. 20000 = mcap doubles). target < 10000 = stop-loss (e.g. 5000 = halves). For BUY: target < 10000 = dip buy. target > 10000 = breakout entry.
WHEN ORDER FILLS: Server pushes order_filled with an unsigned tx. The MCP signs locally and submits via /protect, then logs the fill (visible via get_fill_log).
SIDE EFFECTS: Order persists server-side until trigger, expiry, or cancel_order. The MCP server process must keep its WS open to receive fills — restarting the process WHILE an order is pending may cause you to miss the fill notification (the order itself stays alive on the server).Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"target"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint to buy or sell."
},
"action": {
"type": "string",
"enum": [
"sell",
"buy"
],
"description": "\"sell\" closes a position when target is hit; \"buy\" opens a position when target is hit."
},
"target": {
"type": "integer",
"minimum": 1,
"description": "Target market cap in BPS vs current mcap at placement. >10000 = above current, <10000 = below current. E.g. 20000 = mcap doubles, 5000 = mcap halves. Server stores this in params_hash (signed) so it cannot be silently changed."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for action=\"buy\". Lamports of SOL to spend when triggered."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "REQUIRED for action=\"sell\". Basis points of holdings to sell (10000 = 100%). Resolved at FILL TIME, not placement."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 1500,
"description": "Slippage tolerance in BPS at fill time. Default 1500 (15%)."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until the order auto-cancels server-side. Default 144 (6 days). Max 336 (14 days). Order silently expires; the server does NOT push an expiry event — use check_order or list_orders to detect."
}
}
} | — | — |
place_limit_trailing_orderCOMBO ORDER: Wait for a limit target, then activate a trailing stop. When the trail triggers, execute as a SINGLE swap (not TWAP).
WHEN TO USE: To enter at a specific mcap, then ride the trend with a trailing stop. Example: "Buy BONK if mcap drops to $500M, then sell with a 15% trailing stop after entry."
WHAT IT DOES: Server waits for limit target. When crossed, sends limit_trailing_activated and starts trailing-stop tracking. When trail retraces enough, sends order_filled with a single unsigned tx.
RETURNS: { wallet, order_id, message: "Limit-Trailing order accepted", target, trail, expiry_hours, params_hash, server_signature }. The order_id stays the same across both phases (limit-watching → trailing-watching → filled). Use check_order to see which phase the order is currently in.
SIDE EFFECTS: Server-side state created — the limit watcher runs until target hits or expiry_hours elapses. Once limit triggers, the trail tracker takes over (high-water for sell, low-water for buy) until reversal exceeds trail BPS. cancel_order works in both phases. expiry_hours covers the LIMIT phase only — once trail activates, the order has no expiry (extend_order resets the limit phase only).Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"target",
"trail"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"limit_trailing_sell",
"limit_trailing_buy"
],
"description": "sell when limit hits (then trail until reversal); buy when limit hits (then trail until rebound)."
},
"target": {
"type": "integer",
"minimum": 1,
"description": "Market-cap target in BPS vs current mcap at placement."
},
"trail": {
"type": "integer",
"minimum": 1,
"description": "Trail distance in BPS, applied AFTER limit fires. 1000 = 10% retracement."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for buy. Lamports of SOL to spend."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "REQUIRED for sell. Basis points of holdings."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 500,
"description": "Slippage at the single-swap fill (BPS)."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until limit phase auto-cancels (before activation)."
}
}
} | — | — |
place_limit_trailing_twap_orderCOMBO ORDER (the full chain): Wait for a market-cap limit target → activate trailing stop → on trail trigger, execute exit/entry as TWAP slices.
WHEN TO USE: For the most sophisticated single-tool strategy. Example: "Buy BONK at mcap $500M, then sell with a 15% trailing stop, and when the trail fires distribute the exit over 30 minutes via TWAP."
WHAT IT DOES: Server orchestrates all three phases. Sends limit_trailing_activated when trail starts, limit_trailing_twap_triggered when trail fires, twap_execution per slice. The 11-field params_hash includes target, trail, frequency, and duration — all signed by the server, verified locally.
RETURNS: { wallet, order_id, message: "Limit-Trailing-TWAP order accepted", target, trail, frequency, duration, expiry_hours, params_hash, server_signature }. The parent order_id covers the limit + trailing phases; the spawned TWAP at trail-fire gets its own child order_id (delivered via twap_order_created event). check_order on the parent reports the current phase ("limit-watching", "trailing-watching", or "twap-spawned").
SIDE EFFECTS: Server-side state created — the watcher runs continuously through three phases. cancel_order on the parent works during limit and trailing phases but NOT once the child TWAP has spawned (cancel that TWAP's order_id directly). expiry_hours covers the LIMIT phase only. params_hash is the strongest commitment in the suite (11 fields including target, trail, frequency, duration, slippage) — verified locally before order acceptance.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"target",
"trail",
"frequency",
"duration"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"limit_trailing_twap_sell",
"limit_trailing_twap_buy"
],
"description": "Full combo direction."
},
"target": {
"type": "integer",
"minimum": 1,
"description": "Market-cap target in BPS vs current."
},
"trail": {
"type": "integer",
"minimum": 1,
"description": "Trail distance in BPS, applied after limit fires."
},
"frequency": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Number of TWAP slices after trail fires."
},
"duration": {
"type": "integer",
"minimum": 60,
"description": "Total seconds the TWAP will run."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "Total to spend (buy lamports) or sell (token base units) across all TWAP slices."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "Sell only: BPS of holdings at TWAP-creation time."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 500,
"description": "Slippage per TWAP slice (BPS)."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until limit phase auto-cancels."
}
}
} | — | — |
place_limit_twap_orderCOMBO ORDER: Wait for a market-cap target to be crossed, then execute the entry/exit as a TWAP rather than a single swap. Server-orchestrated; no client-side state machine needed.
WHEN TO USE: When you want a trigger-then-distribute pattern. Example: "If BONK's mcap hits $500M, ladder out of my position over 30 minutes via TWAP."
WHAT IT DOES: Server waits for limit target. When crossed, sends limit_twap_triggered, then twap_order_created for the spawned TWAP, then twap_execution per slice (each with server_signature for verification).
RETURNS: { wallet, order_id, message: "Limit-TWAP order accepted", target, frequency, duration, expiry_hours, params_hash, server_signature }. The order_id is what you'd pass to check_order, cancel_order, or extend_order. Server returns an error event over WS if the wallet is not registered, or if both amount and holdings_percentage are missing.
SIDE EFFECTS: Server-side state created — the order watches the market-cap feed continuously until target hits or expiry_hours elapses. Once limit triggers, a child TWAP order is spawned with its own order_id (delivered via twap_order_created event); cancel_order on the parent only cancels the limit phase, not the child TWAP after it spawns. params_hash signs an 11-field commitment (target_bps, trail_bps n/a, frequency, duration, etc.) — verified locally against the trust anchor before the order is treated as accepted.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"target",
"frequency",
"duration"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"limit_twap_sell",
"limit_twap_buy"
],
"description": "sell when target is crossed (then TWAP exit), or buy when target is crossed (then TWAP entry)."
},
"target": {
"type": "integer",
"minimum": 1,
"description": "Market-cap target in BPS vs current mcap at placement. See place_limit_order for full semantics."
},
"frequency": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Number of TWAP slices to spawn after the limit triggers."
},
"duration": {
"type": "integer",
"minimum": 60,
"description": "Total seconds the spawned TWAP will run. Slice interval = duration / frequency."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "Total to spend (buy lamports) or sell (token base units) across all TWAP slices."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "Sell only: BPS of holdings at TWAP-creation time."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 500,
"description": "Slippage per TWAP slice (BPS). Default 500."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until the LIMIT phase auto-cancels (before TWAP fires). Default 144."
}
}
} | — | — |
place_trailing_orderPlaces a trailing-stop sell or trailing buy order over the WebSocket. The server tracks the high-water mark (or low-water mark for buy) of mcap and fires when it retraces by trail BPS.
WHEN TO USE: To ride a trend without picking a fixed exit. "Sell BONK when mcap drops 10% from its peak" — sell trail-stop. "Buy DOGE when mcap rebounds 5% from its low" — buy trail.
WHAT IT DOES: Sends { action: "trailing_sell"|"trailing_buy", token_address, trail, ... } to the server. Server tracks the running high (sell) or low (buy) of mcap and fires when retracement >= trail BPS. Server returns order_created with params_hash (signed), then later order_filled with an unsigned tx for local signing.
TRAIL SEMANTICS: trail is in basis points. trail=1000 means a 10% retracement triggers. Example (trailing_sell): mcap peaks at $100k, trail=1000, trigger at $90k. If mcap then peaks at $150k, trigger moves up to $135k.
SIDE EFFECTS: Order persists server-side until trigger, expiry, or cancel_order.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"trail"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"trailing_sell",
"trailing_buy"
],
"description": "trailing_sell closes a position after a retracement from peak; trailing_buy opens a position after a rebound from trough."
},
"trail": {
"type": "integer",
"minimum": 1,
"description": "Trail distance in BPS (basis points). 1000 = 10%. Server tracks high-water (sell) or low-water (buy) mark and fires when reversal exceeds this."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for trailing_buy. Lamports of SOL to spend when triggered."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "REQUIRED for trailing_sell. Basis points of holdings to sell (10000 = 100%)."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 1500,
"description": "Slippage in BPS at fill. Default 1500 (15%)."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until auto-cancel. Default 144."
}
}
} | — | — |
place_trailing_twap_orderCOMBO ORDER: Wait for a trailing-stop trigger, then execute the exit as a TWAP rather than a single swap.
WHEN TO USE: To ride a trend with a trailing stop, but exit gradually via TWAP when the trail fires (minimizing market impact on a low-liquidity exit). Example: "Sell BONK if mcap drops 15% from peak, but spread the exit over 30 min."
WHAT IT DOES: Server tracks high-water (sell) or low-water (buy) mark. When reversal exceeds trail BPS, sends trailing_twap_triggered, then twap_order_created, then twap_execution per slice.
RETURNS: { wallet, order_id, message: "Trailing-TWAP order accepted", trail, frequency, duration, expiry_hours, params_hash, server_signature }. order_id is the parent (trailing-watching) phase; the spawned TWAP gets its own child order_id at trigger time.
SIDE EFFECTS: Server-side state created — the trailing-watcher runs continuously until trail fires or expiry_hours elapses. cancel_order on the parent stops the trailing phase but does NOT cancel a child TWAP that has already spawned. The 11-field params_hash includes trail BPS, frequency, duration, slippage — signed by server, verified locally.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"trail",
"frequency",
"duration"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"trailing_twap_sell",
"trailing_twap_buy"
],
"description": "sell after retracement from peak (then TWAP); buy after rebound from trough (then TWAP)."
},
"trail": {
"type": "integer",
"minimum": 1,
"description": "Trail distance in BPS. 1000 = 10%. See place_trailing_order for full semantics."
},
"frequency": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Number of TWAP slices after trail fires."
},
"duration": {
"type": "integer",
"minimum": 60,
"description": "Total seconds the spawned TWAP will run."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "Total to spend (buy lamports) or sell (token base units) across all TWAP slices."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "Sell only: BPS of holdings at TWAP-creation time."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 500,
"description": "Slippage per slice (BPS)."
},
"expiry_hours": {
"type": "integer",
"minimum": 1,
"maximum": 336,
"default": 144,
"description": "Hours until trailing phase auto-cancels."
}
}
} | — | — |
place_twap_orderPlaces a Time-Weighted Average Price (TWAP) buy or sell order. The total amount is split into N equal slices executed every (duration / frequency) seconds.
WHEN TO USE: For DCA, large entries/exits where minimizing market impact matters more than getting a single price. Example: "DCA 1 SOL into JUP over 6 hours in 12 slices" → twap_buy with amount=1e9, frequency=12, duration=21600.
WHAT IT DOES: Server registers the order, returns twap_order_created with order_id, frequency, duration, interval_seconds, amount_per_execution. Then for each slice, server pushes twap_execution { execution_num, executions_total, executions_remaining, next_execution_at, server_signature, data: { swap_tx } }. The MCP verifies server_signature, signs swap_tx, submits via /protect. Final twap_order_completed when all slices done.
SLICING: amount (or holdings_percentage at creation time, then resolved to a fixed token amount) is divided by frequency. Each slice executes at duration / frequency intervals.
SIDE EFFECTS: Each slice is a real on-chain transaction. The order persists server-side and the MCP server must stay running to receive twap_execution pushes. cancel_order halts remaining slices.Input schema{
"type": "object",
"required": [
"wallet_address",
"token_address",
"action",
"frequency",
"duration"
],
"additionalProperties": false,
"properties": {
"wallet_address": {
"type": "string",
"description": "Solana wallet public key (base58)."
},
"token_address": {
"type": "string",
"description": "SPL token mint."
},
"action": {
"type": "string",
"enum": [
"twap_buy",
"twap_sell"
],
"description": "twap_buy spends SOL to acquire token over N slices; twap_sell sells token for SOL over N slices."
},
"frequency": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Number of slice executions. Total amount is divided by this number. Example: frequency=12 with duration=21600 (6h) = one slice every 30 minutes."
},
"duration": {
"type": "integer",
"minimum": 60,
"description": "Total run time in seconds. Min 60, max ~2,592,000 (30 days). Order has no separate expiry — it lives exactly this long."
},
"amount": {
"type": "integer",
"minimum": 1,
"description": "REQUIRED for twap_buy (total SOL lamports to spend across all slices). For twap_sell, optional — sell exactly this many token base units total."
},
"holdings_percentage": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "For twap_sell: basis points of CURRENT holdings to sell (resolved once at creation, then divided by frequency). Use either this or amount, not both."
},
"slippage": {
"type": "integer",
"minimum": 100,
"maximum": 2500,
"default": 500,
"description": "Slippage in BPS per slice. Default 500 (5%) — TWAP slices are smaller so tolerate tighter slippage."
}
}
} | — | — |
submit_signed_swapSubmits a fully-signed, base64-encoded Solana transaction via POST /protect (Jito MEV-protected lane). Blocks until the transaction confirms on-chain.
WHEN TO USE: Pair with build_swap when you want to inspect/modify the transaction before signing. For a single-call swap, prefer auto_swap.
WHAT IT DOES: POSTs the signed transaction to api.traderouter.ai/protect, which submits via Jito bundles + a staked connection lane (preventing mempool visibility for sandwich-resistance), waits for on-chain confirmation, and returns the signature plus pre/post SOL balance and token balance changes.
RETURNS: On success: { status: "success", signature, sol_balance_pre, sol_balance_post, token_balances: [{ mint, balance, decimals, balance_change, ui_amount_string }] }. On error: { status: "error", error, code }. On 503 (protect lane unavailable), the MCP server falls back to direct RPC submission automatically — you lose MEV protection but the transaction still lands.
SIDE EFFECTS: Submits a real on-chain transaction (unless TRADEROUTER_DRY_RUN=true). Costs ~0.000005 SOL in network fees plus the routed swap fee.
⚠️ ENCODING: The swap_tx returned by build_swap is BASE58. This tool requires BASE64. Decode the base58, deserialize as VersionedTransaction, sign, re-serialize, base64-encode.
⚠️ TIMEOUT: Set client HTTP timeout to 30 seconds — confirmation latency varies with network congestion.Input schema{
"type": "object",
"required": [
"signed_tx_base64"
],
"additionalProperties": false,
"properties": {
"signed_tx_base64": {
"type": "string",
"description": "A signed Solana VersionedTransaction, base64-encoded. Note: build_swap returns base58; you must convert before passing here."
}
}
} | — | — |
Compared with initial baseline using full_baseline.
| Risk | Change | Subject |
|---|---|---|
| No material changes recorded. | ||
| Severity | Finding | Advisory |
|---|---|---|
| No confirmed vulnerability is published for this version. | ||
Artifact SHA-256: 490f6fd0b3ca5e41e0d7e60f2259bff6ebe8c05fab853dec3067a1bd4ce35b57
Scanner: mcp-proof-engine 0.1.0.