Vurto Swap
by cryptoconspiracy · remote · no sign-in to list tools · v1.0.0 · published by GitHub user cryptoconspiracy
Token swaps at the best net price on 9 EVM chains and Solana. No API key, non-custodial.
18 tools: 6 do something that can't be undone, 8 change things and 4 only read.
Scanned Oct 21, 2026
- Deletes or cancels0Claude Code: deny
- Can't be undone6Claude Code: ask: see these tools
- Changes things8Claude Code: ask: see these tools
- Only reads4Claude Code: allow: see these tools
4 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.
claude mcp add --transport http vurto-swap https://swap.vurto.cc/mcpFindings
Matches of fixed checks, with the text they matched.
- Warnprepare_signing
The server marks "prepare_signing" read-only (readOnlyHint: true), and its own name, description or input give the class "irreversible".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The input addresses people (input.step.tx.to): what it sends cannot be taken back.
- Infoswap_build
The description mentions "credential".
What this check looks forMatched text
description: "...ss the wallet that will sign. A machine credential is optional and only raises your limit..."
- Infonn_build
The description mentions "credential".
What this check looks forMatched text
description: "...ss the wallet that will sign. A machine credential is optional and only raises your limit..."
- Inforeport_execution
The description mentions "credential".
What this check looks forMatched text
description: "...network. No API key required; a machine credential only raises limits."
Tools
Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.
18 tools
Can't be undone 6Claude Code: ask
invoice_createCreate a payment request: who receives, which token, how much, on which network.No findings
Why it is in this group
- The name "invoice_create" says "create": a word for a change.
- The input addresses people (input.recipient): what it sends cannot be taken back.
Description, as the server wrote it Create a payment request: who receives, which token, how much, on which network. Returns invoice.id, invoice.label (INV-XXXX-XXXX, what people copy), invoice.url (share this; it previews with the QR on WhatsApp and Telegram) and invoice.qr (PNG). No signature or API key needed. Only VERIFIED tokens of the network are accepted, by address or symbol — an unverified token is refused because a cloned "USDC" with its own pool would let the creator sell a fake at any price. The payer can pay with ANY token on that network.
Annotations the server declares
- title: Create an invoice
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
invoice_payBuild the plan to pay an invoice from payer, with the token payer holds (default: the invoice token).No findings
Why it is in this group
- The name "invoice_pay" says "pay": a word that usually means money moves, which cannot be taken back.
Description, as the server wrote it Build the plan to pay an invoice from payer, with the token payer holds (default: the invoice token). Nothing is signed or sent here. method "transfer": same token, a direct transfer built from the stored invoice (no fee, no gain; the receiver sees the payer as sender). method "swap": another token; amountIn is computed so the GUARANTEED minimum output covers the requested amount, the route is always the one with GAIN when there is one, and the output goes straight to the receiver (the transaction is public and signed by the payer, so the receiver can see the paying wallet on-chain). Any surplus over the requested amount goes to the receiver. plan has the same shape as a swap_build plan: on EVM sign steps[] in order with prepare_signing (approve steps first, then the transaction); on Solana pass {transaction, executionRef} to prepare_signing and POST the signed transaction to /v1/svm/execute. If simulation.status is approval_required, send the approve and call invoice_pay again. Then call invoice_report_payment with the hash (EVM) or signature (Solana). Errors: price_moved (the minimum fell below the request between quote and build — call again), no_route, native_sol_only (an invoice in SOL can only be paid in SOL), invoice_already_paid, private_invoice_paused (a private invoice created before 14/10/2026, paused until the Vurto vault exists). Both wallets are screened before the plan is built: the paying one (payer_blocked) and the receiving one (receiver_blocked). screening_unavailable (503) means the screening could not finish, try again in a few seconds.
Annotations the server declares
- title: Build an invoice payment
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
invoice_report_paymentHand the payment transaction to the server, right after sending it.No findings
Why it is in this group
- The name "invoice_report_payment" says "payment": a word that usually means money moves, which cannot be taken back.
Description, as the server wrote it Hand the payment transaction to the server, right after sending it. The server reads the transaction on-chain and measures what reached the receiver in the invoice token; the payer must be the signer and the transaction must be newer than the invoice. The payer is screened again here (payer_blocked: a sanctioned or issuer-frozen payer does not count as paid). Pending until mined; invoice_get re-checks. An invoice holds at most 5 pending and 30 unconfirmed payments; past that, too_many_pending (429) until the network confirms the transaction, and a confirmed one is always accepted, so call again once it is mined. A hash pays each receiver once (tx_already_used once it confirmed another invoice of the same receiver and token); different receivers in one transaction are a batch payout.
Annotations the server declares
- title: Report an invoice payment
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
payout_batchPayroll and supplier payouts on Solana: pay up to 20 wallets their exact amounts, in the token the payer holds (no swap).No findings
Why it is in this group
- The name "payout_batch" says "payout": a word that usually means money moves, which cannot be taken back.
- The input addresses people (input.recipients): what it sends cannot be taken back.
Description, as the server wrote it Payroll and supplier payouts on Solana: pay up to 20 wallets their exact amounts, in the token the payer holds (no swap). The paying wallet and every receiving wallet are screened first (OFAC SDN list and the issuer freeze of six stablecoins); a blocked payer refuses with payer_blocked (403), and one blocked recipient refuses the whole batch with receiver_blocked (403) and details.index of that row, before anything is created. Each recipient becomes a regular invoice (history, on-chain verification). Returns { invoices[], transactions[] }: the transfers are packed in as few transactions as fit the network limit, each with its invoiceIds. Sign each transactions[i].transaction (prepare_signing, then POST to /v1/svm/execute), then payout_report_payment with that signature and those invoiceIds. Errors: batch_svm_only, batch_duplicate_recipient (add the amounts up in one row), batch_self_payment, too_many_recipients, token_not_listed, screening_unavailable (503, try again).
Annotations the server declares
- title: Build a batch payout
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
payout_report_paymentHand one batch transaction to the server, right after sending it, with the invoiceIds that payout_batch listed for it.No findings
Why it is in this group
- The name "payout_report_payment" says "payout": a word that usually means money moves, which cannot be taken back.
Description, as the server wrote it Hand one batch transaction to the server, right after sending it, with the invoiceIds that payout_batch listed for it. Each invoice is verified on-chain like any invoice payment (what reached that receiver); call again a few seconds later if some are still pending.
Annotations the server declares
- title: Report a batch payout transaction
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
prepare_signingSynthesizes the local CLI signer invocation for one step of a swap_build plan.1 finding
Why it is in this group
- The input addresses people (input.step.tx.to): what it sends cannot be taken back.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Findings
- Warn
The server marks "prepare_signing" read-only (readOnlyHint: true), and its own name, description or input give the class "irreversible".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}; The input addresses people (input.step.tx.to): what it sends cannot be taken back.
Description, as the server wrote it Synthesizes the local CLI signer invocation for one step of a swap_build plan. Does not call the Vurto backend — this only assembles the payload. You (the agent) do not need a private key and must never ask for one in chat: signing happens locally on the user's machine. RUN the command yourself as a background task (it blocks until the user approves/rejects/times out, then prints one JSON line and exits) and react to its exit — never ask the user "did you sign?". EVM supports "approve"/"transaction" steps (send tx.to/tx.data on-chain) and "signature" steps (sign step.typedData off-chain, EIP-712 — a CoW order; no gas, no transaction, no hash). expected_keys in the response tells you which result field to read: txHash for the first two, signature for the third. Solana has no steps[] and no approve: pass chainId "solana-mainnet" and step {transaction: build.transaction, executionRef: build.executionRef}. The response returns a different signer (Solana keys are not EVM keys) with the same shape, and expected_keys is signedTransaction — POST it to /v1/svm/execute, which broadcasts it and returns the signature.
Annotations the server declares
- title: Assemble the local signer command
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
Changes things 8Claude Code: ask
destination_authorizeHand over the signature of destination_challenge.No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Description, as the server wrote it Hand over the signature of destination_challenge. The server checks it is the paying wallet's signature over that exact challenge, for that receiver and chain, unexpired and unused, and then lets builds deliver to that receiver for 30 minutes. Nothing else unlocks it. Errors: signature_invalid, authorization_expired, authorization_replayed, authorization_destination_mismatch, authorization_network_mismatch.
Annotations the server declares
- title: Authorize another destination with the wallet signature
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
destination_challengeDestination lock.No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Description, as the server wrote it Destination lock. A receiver different from the signing wallet is refused by swap_build, double_build and nn_build (403 destination_not_authorized) until the paying wallet signs an authorization for that exact address on that chain. This returns {nonce, message, expiresAt} plus, on EVM, typedData (EIP-712, the same fields) and, on Solana, proofTransaction (a memo that can never land, for Ledger). Show the user the full receiver and network and get their explicit yes; then sign: on EVM call prepare_signing with step {type: "signature", typedData} and run it; on Solana sign message (or proofTransaction) with the wallet. Then call destination_authorize. Never sign this without the user asking to send to that address. Paying an invoice does not need it.
Annotations the server declares
- title: Ask to send the output to another wallet
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
double_buildBuilds signable/sendable plans for BOTH legs of a Double Out or Double In swap — two ordinary swap_build calls under the hood, kept together for convenience.No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Description, as the server wrote it Builds signable/sendable plans for BOTH legs of a Double Out or Double In swap — two ordinary swap_build calls under the hood, kept together for convenience. Returns { legA, legB }, each a full SwapPlan exactly like swap_build's. The two legs are NOT atomic — there is no combined contract call, each is a transaction (or CoW signature) the wallet sends separately, same as any other swap. Execute leg A fully first (steps, signing, report_execution) and confirm it landed before starting leg B. If leg A fails or is rejected, do NOT execute leg B — proceeding would leave the wallet with only half the ratio the user asked for, which defeats the purpose of a Double swap.
Annotations the server declares
- title: Build a two-leg plan
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
nn_buildBuilds ONE signable/sendable atomic transaction executing every leg of an N:N basket through VurtoSwapRouter.1 finding
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Findings
- Info
The description mentions "credential".
What this check looks forMatched text
description: "...ss the wallet that will sign. A machine credential is optional and only raises your limit..."
Description, as the server wrote it Builds ONE signable/sendable atomic transaction executing every leg of an N:N basket through VurtoSwapRouter. Always re-quotes the whole basket fresh from chainId/inputLegs/outputLegs — there is no quoteId handoff for N:N, pass the same fields used for nn_quote (or skip nn_quote and call this directly). No API key required: pass the wallet that will sign. A machine credential is optional and only raises your limit from the per-IP cap to the credential budget. Returns steps[]: one approve step per DISTINCT input token that still needs allowance, followed by ONE transaction step that executes every leg atomically. The approve target is the VurtoSwapRouter address (steps[].spender / the build's router), NOT each leg's underlying provider — this router pulls every input token itself inside one contract call, so approving providers individually the way swap_build does would approve the wrong address. If simulation.status is approval_required, send the approve step(s) first and call nn_build again for the executable transaction. legs[].routeSwitch, when present on a leg, means the provider the quote picked for THAT leg refused to build (it hit its request limit) and the leg was built with another provider instead: {from, to, reason}. Only that leg changed, the others are untouched, and the replacement is what will be signed: say which provider replaced it before the user signs. IMPORTANT: report_execution and swap_status do NOT support nn_build's transaction step — both key off a single quoteId, and this build has none (it is one transaction covering every leg, not one quote). After sending it, confirm success by checking the transaction receipt directly, not swap_status.
Annotations the server declares
- title: Build a basket plan
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
nn_quoteN:N — quotes a basket where N input tokens fund M output tokens in ONE atomic on-chain transaction.No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Description, as the server wrote it N:N — quotes a basket where N input tokens fund M output tokens in ONE atomic on-chain transaction. The backend runs a waterfall allocation deciding which input finances which output, then quotes the real tokenIn->tokenOut route for each resulting slice through the same provider fan-out swap_quote uses. NOT decomposable into independent swap_quote/double_quote calls — the allocation itself is the thing being computed, not just N+M separate prices for legs you already know. inputLegs[]: what you sell (tokenIn + amount or amountRaw, each). outputLegs[]: what you want back, as outputPercent — an integer percent of the TOTAL basket value, not a fixed amount, because the actual split depends on the allocation; every outputLegs[].outputPercent in the request must sum to exactly 100. Up to 10 combined input+output legs; the waterfall never produces more than inputLegs.length + outputLegs.length - 1 real on-chain legs. Returns { legs[], failures[] }. Each entry in legs[] is a real quoted tokenIn->tokenOut leg (a NormalizedQuote under .quote, plus amountIn/tokenIn/tokenOut/receiver for that slice) — this is what nn_build will execute, not a rough preview. failures[] lists any slice that found no route; a partial basket is possible and reported, never silently dropped.
Annotations the server declares
- title: Compare basket routes
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
report_executionReports a completed swap, closing the loop.1 finding
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Findings
- Info
The description mentions "credential".
What this check looks forMatched text
description: "...network. No API key required; a machine credential only raises limits."
Description, as the server wrote it Reports a completed swap, closing the loop. EVM transaction: pass wallet + txHash + quoteId; never report an approve step as an execution. EVM CoW signature: pass wallet + chainId + quoteId + signature; the server reloads the stored build and submits the signed order, returning uid (there is no transaction hash for this path). Solana: pass buildId + signature; the server verifies the fee payer and transaction on the network. No API key required; a machine credential only raises limits.
Annotations the server declares
- title: Report a completed swap
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
swap_buildBuild a signable/sendable plan for a swap.1 finding
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Findings
- Info
The description mentions "credential".
What this check looks forMatched text
description: "...ss the wallet that will sign. A machine credential is optional and only raises your limit..."
Description, as the server wrote it Build a signable/sendable plan for a swap. This is the tool that does the work — an agent that only knows this tool can execute a swap end to end. Quotes and builds the best route in one call when quoteId is omitted (recommended): a route with GAIN first, re-quoting up to 3 rounds total before accepting one without gain, the same rule as Invoice; pass quoteId from a prior swap_quote to build exactly that route instead. No API key required: pass the wallet that will sign. A machine credential is optional and only raises your limit from the per-IP cap to the credential budget. Four things to hold onto: 1. steps[] are ORDERED and REQUIRED. Skipping an approve step guarantees a revert. 2. If simulation.status is "approval_required", sign/send only the approve step(s), do not report them as the swap execution, then call swap_build again with quoteId set to the quote.id of that build (the approved route; without it a fresh quote may pick another provider whose spender you never approved). If it is "incomplete", do not sign anything: the transaction was never independently verified. 3. If a step has type "signature", there is no transaction and never will be one for that step — what exists afterward is the uid from report_execution, not a hash. 4. If the provider is cowswap and the token sold is the chain's native asset, the transaction only REGISTERS the order — a successful receipt is not a successful swap. Use swap_status, not the receipt, to know what actually happened. 5. routeSwitch, when present, means the route you asked for refused to build (it hit its request limit) and the plan was built with another provider instead: {from, to, reason}. The quote in the plan is the route that will actually be signed. If the user picked that route themselves, say which provider replaced it before they sign.
Annotations the server declares
- title: Build a swap plan
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
wallet_checkCheck any wallet (EVM 0x address or Solana base58, case-sensitive) before paying it or taking its money: OFAC SDN list on both families; on Solana also the issuer freeze of USDC an…No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Description, as the server wrote it Check any wallet (EVM 0x address or Solana base58, case-sensitive) before paying it or taking its money: OFAC SDN list on both families; on Solana also the issuer freeze of USDC and EURC (Circle), USDT (Tether), PYUSD and USDG (Paxos) and USD1 (World Liberty), the issuer freeze index, and a fund trail up to three hops back. Returns verdict passed, blocked or unavailable, with each check. Paying an invoice (invoice_pay) runs this check on the receiving wallet and refuses with receiver_blocked, so a payment through Vurto Payments never reaches a sanctioned or frozen wallet. To pay someone directly, create an invoice to their wallet (invoice_create) and pay it with invoice_pay. Plain swaps (swap_build, double_build, nn_build) do not run it.
Annotations the server declares
- title: Check a wallet before paying
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
Only reads 4Claude Code: allow
double_quoteCompares ranked routes for TWO swap legs at once — "Double Out" (one source token split into two destinations) or "Double In" (two source tokens converging on one destination).No findings
Why it is in this group
- The description's first verb is "compare": a word for reading.
Description, as the server wrote it Compares ranked routes for TWO swap legs at once — "Double Out" (one source token split into two destinations) or "Double In" (two source tokens converging on one destination). This exists because building a liquidity pool or matching a target ratio needs both legs priced against the market at the same instant, not one after another with the price moving in between. Each leg is independently quoted (two ordinary swap_quote calls under the hood) — this tool is a convenience that keeps them together, not a combined/atomic route. For mode "out": legA.tokenIn must equal legB.tokenIn (the shared source); tokenOut differs. For mode "in": legA.tokenOut must equal legB.tokenOut (the shared destination); tokenIn differs. Pass the exact amount each leg should trade — this tool does not compute percentages or splits for you. If the shared token is the chain's native asset, remember gas is paid twice (once per leg's eventual transaction) — do not quote/build a total that leaves nothing for the second leg's gas.
Annotations the server declares
- title: Compare two-leg routes
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
invoice_getRead an invoice by id (INV-XXXX-XXXX, with or without dashes): requested amount, token, network, receiver, status (open or paid), the paying transaction once paid, and received (th…No findings
Why it is in this group
- The name "invoice_get" says "get": a word for reading.
Description, as the server wrote it Read an invoice by id (INV-XXXX-XXXX, with or without dashes): requested amount, token, network, receiver, status (open or paid), the paying transaction once paid, and received (the raw amount measured on-chain so far). Pending payments are re-checked on-chain by the read, at most two per read and each at most every 15 seconds. confidential is true only on a private invoice created before 14/10/2026: its receiver reads null here, it can no longer be paid (invoice_pay answers private_invoice_paused), and its paying transaction, once paid, shows the receiver on-chain.
Annotations the server declares
- title: Read an invoice
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
swap_quoteCompare ranked routes across providers for a swap, without building or spending anything.No findings
Why it is in this group
- The description's first verb is "compare": a word for reading.
Description, as the server wrote it Compare ranked routes across providers for a swap, without building or spending anything. Ranked by net value after gas and platform fee, not raw output, with ONE unit price for the output token across every route, so a friendlier price feed can never put a route that delivers fewer tokens on top. Each quote also carries estimatedGas, the gas in units behind the same gasUsd, if you would rather rank against a gas price you read yourself. A quote is only usable by swap_build for about 10-12 seconds — do not hold onto a quoteId and build it later, quote again instead.
Annotations the server declares
- title: Compare swap routes
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: false
- openWorldHint: true
swap_statusRe-checks a swap.No findings
Why it is in this group
- The name "swap_status" says "status": a word for reading.
Description, as the server wrote it Re-checks a swap. EVM: pass wallet + executionId (the id from report_execution); for CoW ETH-flow this consults the orderbook and distinguishes order_expired_refundable from order_expired_refunded instead of trusting the registration receipt. Solana: pass signature; answers come directly from the network and may be confirmed, pending, failed or expired.
Annotations the server declares
- title: Check a swap status
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: true
This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.
Install
Pinned to version 1.0.0. Values in angle brackets are yours to fill in.
claude mcp add --transport http vurto-swap https://swap.vurto.cc/mcpRun in a terminal.
Claude Code permissions
Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.
{
"permissions": {
"allow": [
"mcp__vurto-swap__swap_quote",
"mcp__vurto-swap__double_quote",
"mcp__vurto-swap__swap_status",
"mcp__vurto-swap__invoice_get"
],
"ask": [
"mcp__vurto-swap__swap_build",
"mcp__vurto-swap__double_build",
"mcp__vurto-swap__nn_quote",
"mcp__vurto-swap__nn_build",
"mcp__vurto-swap__prepare_signing",
"mcp__vurto-swap__report_execution",
"mcp__vurto-swap__invoice_create",
"mcp__vurto-swap__wallet_check",
"mcp__vurto-swap__destination_challenge",
"mcp__vurto-swap__destination_authorize",
"mcp__vurto-swap__invoice_pay",
"mcp__vurto-swap__payout_batch",
"mcp__vurto-swap__payout_report_payment",
"mcp__vurto-swap__invoice_report_payment"
],
"deny": []
}
}Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as vurto-swap. Review it before you use it.
