← MCP Security Catalog

trade-router-mcp 1.0.13

npm · @traderouter/trade-router-mcp · latest release

Scan failed
Security result
21
Observed tools
46
Version rating
100
Change risk

Independent inventory

Observed 2026-08-22T06:28:58.288Z using mcpSecurity-inventory. Protocol 2025-06-18.

ToolCategoryRisk
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."
    }
  }
}

Resources 0

Resource templates 0

Prompts 0

Changes from previous version

Compared with initial baseline using full_baseline.

RiskChangeSubject
No material changes recorded.

Confirmed vulnerabilities

SeverityFindingAdvisory
No confirmed vulnerability is published for this version.

Provenance

Artifact SHA-256: 490f6fd0b3ca5e41e0d7e60f2259bff6ebe8c05fab853dec3067a1bd4ce35b57

Scanner: mcp-proof-engine 0.1.0.

Let’s talk about MCP security.

Share your details and our security team will contact you.