All posts
8 min read

Build a TON Trading Agent with MCP: Read, Quote, Swap

A TON trading agent on MCP: how an agent reads balances, gets a firm quote, and builds a non-custodial swap — get_balance, get_swap_quote, build_swap_tx.

TON trading agentAI trading agentMCPTON swapnon-custodialOmniston

The problem every TON trading agent runs into first

You ask an AI agent to "swap 50 USDT for GRAM when the price dips" — and it sends a transaction for 50,000 USDT instead of 50. That's because USDT on TON has decimals = 6 (50 USDT = 50,000,000 raw units), while the agent defaulted to the usual nine-zero jetton math — and inflated the amount by a factor of 1000. A 1000x error, real money, an irreversible transaction. The mirror-image bug has the same root cause: the agent sees a raw 1000000000 in the balance and confidently reports "you hold a billion USDT" when it's actually 1,000.

These aren't made-up horror stories — they're exactly the traps everyone walks into when wiring an LLM into TON DeFi through raw RPC: mixed-up decimals, no way to read a jetton balance without the jetton-wallet address, a private key leaking through the context. Below is how to build a TON trading agent that reads balances, gets a firm quote, and builds a swap — without ever touching your keys. The tool: TONNode, a hosted MCP server for TON.

What a TON trading agent is and why it needs MCP

A trading agent is an LLM (Claude, Cursor, Codex, or any other MCP client) that can read network state and prepare trades on request: "show my USDT balance", "how much GRAM do I get for 500 USDT", "build the swap". On its own, the model can't see the blockchain — it needs tools.

That's exactly what MCP (Model Context Protocol) does — the standard agents use to call external tools. Instead of teaching the model to hand-craft raw ADNL requests and parse BOC cells, you hand it a set of typed functions: "get balance", "get quote", "build transaction". TONNode plugs in as a source of those tools and gives the agent exactly 16 functions for working with the network: reads, swaps, cross-chain, wallet generation.

A trading agent needs five of them, and all five are available even on the free plan:

read (get_balance, get_jetton_balance)
   -> pin down decimals (get_jetton_info)
      -> quote (get_swap_quote)
         -> build the swap (build_swap_tx)
            -> the wallet signs via TonConnect

The key detail in that last step: it's the user's wallet that signs, not the server. TONNode returns unsigned messages — we'll get to why that's non-negotiable at the end.

Step 1: the agent reads balances (get_balance, get_jetton_balance)

Before swapping anything, the agent has to know what it's working with. Two tools:

  • get_balance — the GRAM balance of an address. GRAM is Toncoin, renamed in June 2026; the network itself is still called TON.
  • get_jetton_balance — the balance of a jetton: USDT, NOT, anything else. The magic here is that the jetton wallet is derived on-chain. You pass the owner address and the jetton master address, and TONNode derives the jetton-wallet address itself and reads its balance. No need to know that address up front or store it anywhere.

The prompt to the agent is literally just this:

Check wallet UQAbc...xyz:
how much GRAM and how much USDT does it hold?

Under the hood the model calls get_balance for the native balance and get_jetton_balance for USDT. One catch: what comes back isn't "human" amounts yet — it's raw units. And this is where it gets important. For how to get a USDT balance in one call without wrestling with jetton-wallet addresses, there's a separate deep dive: /blog/usdt-balance-ton-one-call.

decimals decide everything: get_jetton_info and why USDT = 6

Balances and amounts on TON are stored in raw units — integers with no fractional part. To get a human-readable amount, you divide the raw number by 10^decimals. And here's the trap: different jettons have different decimals.

  • USDT has decimals = 6. So 1 USDT = 1,000,000 raw units.
  • Most jettons on TON have decimals = 9 (like GRAM). So 1 token = 1,000,000,000 raw units.

Mixing up 6 and 9 means being off by exactly 1000x. That's the "billion USDT" from the top of this article. For a trading agent this isn't cosmetic — it's the whole basis for trusting it: if it confuses orders of magnitude, it cannot be allowed to build trades.

That's why the pipeline has get_jetton_info built into it — it returns the jetton's metadata: name, symbol, supply, and — most importantly — decimals. The correct logic inside the agent:

raw       = get_jetton_balance(...)   // e.g. 1000000000
decimals  = get_jetton_info(...)      // for USDT → 6
human     = raw / 10 ** decimals      // 1000000000 / 1e6 = 1000 USDT

The same raw value at decimals = 9 would be 1 token — a wildly different answer. Don't hardcode decimals in the prompt and don't let the model "recall" them from memory: on a new jetton it will get them wrong. Have it pull them from get_jetton_info every single time and recompute from the actual value. A detailed breakdown of this trap and why it costs people money: /blog/jetton-decimals-ton.

Step 2: a firm quote via Omniston (get_swap_quote)

Balances are read and converted into the right units — now the agent needs a price. In DeFi, a "rough price from memory" doesn't work: liquidity is spread across several DEXes, the rate keeps moving, and the agent has to work from a live quote, not a guess.

get_swap_quote returns a firm quote for a GRAM ⇄ jetton swap via the Omniston protocol, which aggregates liquidity from TON's two largest DEXes — STON.fi and DeDust. The agent doesn't have to poll pools, compare prices, or compute slippage itself: Omniston returns the best route from the combined liquidity.

Get me a quote: how much GRAM do I get for 50 USDT right now?

The model calls get_swap_quote with the amount 50000000 (those raw units from the previous step) and gets concrete numbers back: how much goes in, how much comes out, over which route, with what slippage. This is the decision point: if the agent has a condition ("only swap if the rate beats X"), it compares the quote against the threshold and either moves forward or waits for the next iteration. Important: a quote is not a trade. No funds move, nothing gets signed. It's a pure market read.

Step 3: building the unsigned swap (build_swap_tx) and signing in the wallet

The user sees the quote and says "yes, let's swap." The agent calls build_swap_tx and gets back an unsigned transaction for the swap, ready for TonConnect.

Note the word "unsigned." The server assembles a correct message — recipient address, payload, amount, route parameters — and returns it as-is. The message then goes to the user's wallet (Tonkeeper, MyTonWallet, anything TonConnect-compatible), the user sees exactly what they're signing, and confirms it themselves. The signature comes from the user's private key, which lives in their wallet — not on the server.

get_balance / get_jetton_balance   →  read what you hold
        ↓
get_jetton_info                    →  pin down decimals, convert
        ↓
get_swap_quote (Omniston)          →  firm quote
        ↓
build_swap_tx                      →  unsigned transaction
        ↓
user's wallet (TonConnect)         →  sign and send

Every step is a separate, explicit tool call. The agent never takes liberties with money on its own initiative: it prepares, and the decision and the signature stay with the human. The full non-custodial swap walkthrough, from quote to signature, is laid out step by step here: /blog/agent-swap-ton-noncustodial.

Non-custodial by design: why the server never holds the agent's keys

This isn't marketing copy — it's an architectural boundary. TONNode's swap, cross-chain, and wallet-generation tools are strictly non-custodial:

  • The server never signs transactions.
  • The server never stores private keys or funds.
  • Everything it hands out is unsigned TonConnect messages.

Why does this matter for a trading agent specifically? Because an agent by definition works with money and by definition can screw up — misread the request, mix up an amount, get stuck in a loop. If the keys lived on the server and it signed on its own, an agent's mistake would mean lost funds without you ever knowing. In the non-custodial scheme, you are the last line of defense: not a single transaction leaves until your wallet confirms it.

Compare that with the official @ton/mcp from the TON Foundation — a custodial agent wallet: it holds an operator key and signs on its own (a split-key scheme where the agent holds the operator key and the user holds the owner key). It has genuine strengths — autonomous spending with no human in the loop, NFT and DNS support, official Foundation status. But the trust model is different: there, the agent really can move funds. TONNode deliberately draws the opposite boundary: the server signs nothing, ever. A full comparison of the two approaches: /blog/custodial-vs-noncustodial-mcp.

How to hook it up and start in 5 minutes

Good news: building the trading pipeline costs nothing. But don't confuse the two free paths — they come with different tool sets.

The local public config gives you the full read set (8 tools: get_masterchain_info, get_balance, get_account_state, get_transactions, run_get_method, get_jetton_balance, parse_address, get_jetton_info). Installs via npx, no key required:

{
  "mcpServers": {
    "ton": {
      "command": "npx",
      "args": ["-y", "@tonnode/mcp"]
    }
  }
}

The @tonnode/mcp package is open source (MIT), lives on npm and GitHub (tonnode/mcp), and speaks TON's native ADNL protocol with no HTTP layers between the agent and the network. Drop the config into Claude Desktop, Cursor, or any MCP client — and your agent can already read balances and call get_jetton_info.

The quotes themselves, though — get_swap_quote and build_swap_tx — belong to the SWAP group and go through the hosted endpoint. Here's the key point: the free Hobby key unlocks all 16 tools, including quoting and swap building. So the entire trading pipeline (read → quote → swap) can be built for free — but through the hosted Hobby key, not the local public config. The hosted endpoint config:

{
  "mcpServers": {
    "ton": {
      "type": "http",
      "url": "https://mcp.tonnode.io/mcp",
      "headers": { "Authorization": "Bearer tn_live_…" }
    }
  }
}

TONNode has exactly 16 tools, and every plan gets all 16 — you pay only for throughput, never for features:

  • Hobby — free forever, 60 requests/min, no card.
  • Pro — $29/mo, 300 requests/min.
  • Scale — $199/mo, 1200 requests/min.

For getting started and putting the trading pipeline through its paces, the free Hobby key is more than enough: 60 requests per minute covers a lot of sequential agent calls. No card required, and the key is issued right after sign-in.

Get a free Hobby key (60 req/min, no card): tonnode.io/dashboard?plan=hobby

The full list of 16 tools: tonnode.io/mcp · Pricing: tonnode.io/pricing


Wire up the five-tool pipeline — get_balance, get_jetton_balance, get_jetton_info, get_swap_quote, build_swap_tx — keep decimals under control, and leave signing to the wallet. What you get is a trading agent that reads balances accurately, takes a firm quote, and prepares swaps for real amounts — without ever getting access to anyone's keys. That's exactly how a TON trading agent should work.

Give your agent TON access

16 MCP tools: reads, non-custodial swaps, cross-chain and wallets. Free tier — 60 req/min, no card required.