Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/mcp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @ton/mcp

## Unreleased

### Minor Changes

- Added `build_ton_transfer`, `build_jetton_transfer`, and `build_nft_transfer` — prepare-only tools that build a transaction and return a ready-to-send `transaction` (`messages`, `validUntil`, `fromAddress`) without broadcasting, mirroring the `get_swap_quote` pipeline. Preview the result with `emulate_transaction`, then broadcast with `send_raw_transaction`, passing `transaction.fromAddress` along with the messages. Because they do not sign, the build tools are available to read-only and operator-keyless agentic wallets.

Transfers go through the single `build_*` → `emulate_transaction` → `send_raw_transaction` path. There are no one-shot `send_ton`/`send_jetton`/`send_nft` tools — build, preview, then broadcast explicitly.

## 0.1.15-alpha.18

### Patch Changes
Expand Down
18 changes: 10 additions & 8 deletions packages/mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,18 @@ Get the status of a transaction by its normalized hash to know if it is pending,

### Transfers

#### `send_ton`
Send TON to an address. Amount is in human-readable format (e.g., `"1.5"` means 1.5 TON). Returns top-level `normalizedHash`. Default flow: poll `get_transaction_status` until completed or failed; user can skip.
`build_ton_transfer`, `build_jetton_transfer`, and `build_nft_transfer` do **not** broadcast. They build a transaction and return ready-to-send `messages` (the `transaction` field). Preview them with `emulate_transaction`, then broadcast with `send_raw_transaction` — the same pipeline used by `get_swap_quote`. Only `send_raw_transaction` signs and sends. When broadcasting, pass the returned `transaction.fromAddress` along with the messages: jetton and NFT transfers are bound to the wallet they were built for.

#### `build_ton_transfer`
Build a TON transfer to an address. Amount is in human-readable format (e.g., `"1.5"` means 1.5 TON). Returns `transaction: { messages, validUntil, fromAddress }`. Preview with `emulate_transaction`, then broadcast with `send_raw_transaction`.

**Parameters:**
- `toAddress` (required): Recipient TON address
- `amount` (required): Amount in TON (e.g., `"1.5"`)
- `comment` (optional): Transaction comment/memo

#### `send_jetton`
Send Jettons to an address. Amount is in human-readable format. Returns top-level `normalizedHash`. Default flow: poll `get_transaction_status` until completed or failed; user can skip.
#### `build_jetton_transfer`
Build a Jetton transfer to an address. Amount is in human-readable format. Returns `transaction: { messages, validUntil, fromAddress }`. Preview with `emulate_transaction`, then broadcast with `send_raw_transaction` (pass `fromAddress` too — the messages target the sender's jetton wallet).

**Parameters:**
- `toAddress` (required): Recipient TON address
Expand All @@ -235,7 +237,7 @@ Send Jettons to an address. Amount is in human-readable format. Returns top-leve
- `comment` (optional): Transaction comment/memo

#### `send_raw_transaction`
Send a raw transaction with full control over messages. Supports multiple messages. Returns top-level `normalizedHash`. Default flow: poll `get_transaction_status` until completed or failed; user can skip.
Sign and broadcast a raw transaction with full control over messages. Supports multiple messages. This is the tool that actually sends prepared transactions (from `build_ton_transfer` / `build_jetton_transfer` / `build_nft_transfer` / `get_swap_quote`). Returns top-level `normalizedHash`. Default flow after send: poll `get_transaction_status` until completed or failed; user can skip.

**Parameters:**
- `messages` (required): Array of messages, each with:
Expand All @@ -244,7 +246,7 @@ Send a raw transaction with full control over messages. Supports multiple messag
- `stateInit` (optional): Initial state for deploying a contract (Base64)
- `payload` (optional): Message payload data (Base64)
- `validUntil` (optional): Unix timestamp after which the transaction becomes invalid
- `fromAddress` (optional): Sender wallet address
- `fromAddress` (optional): Sender wallet address; when broadcasting a prepared transaction, pass its `transaction.fromAddress`

#### `emulate_transaction`
Dry-run a raw transaction without broadcasting it. Accepts the same `messages` format as `send_raw_transaction` and returns the expected TON and Jetton balance changes, fees, and high-level actions so agents can verify a transaction before sending.
Expand Down Expand Up @@ -287,8 +289,8 @@ Get detailed information about a specific NFT by its address.
**Parameters:**
- `nftAddress` (required): NFT item contract address

#### `send_nft`
Transfer an NFT from the wallet to another address. Returns `normalizedHash`. Default flow: poll `get_transaction_status` until completed or failed; user can skip.
#### `build_nft_transfer`
Build an NFT transfer from the wallet to another address. Returns `transaction: { messages, validUntil, fromAddress }`. Preview with `emulate_transaction`, then broadcast with `send_raw_transaction` (pass `fromAddress` too).

**Parameters:**
- `nftAddress` (required): NFT item contract address to transfer
Expand Down
33 changes: 28 additions & 5 deletions packages/mcp/USAGE_EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ npx @ton/mcp@alpha get_known_jettons

**Approximate agent response**

> `USDT` was found in the list of known jettons with master contract address `EQ...`. That address can be used with `send_jetton` or `get_swap_quote`.
> `USDT` was found in the list of known jettons with master contract address `EQ...`. That address can be used with `build_jetton_transfer` or `get_swap_quote`.

## TON Proof Authentication

Expand Down Expand Up @@ -194,14 +194,33 @@ npx @ton/mcp@alpha generate_ton_proof --domain getgems.io --payload getgems-llm

```bash
npx @ton/mcp@alpha resolve_dns --domain foundation.ton
npx @ton/mcp@alpha send_ton --toAddress EQ... --amount 1
npx @ton/mcp@alpha build_ton_transfer --toAddress EQ... --amount 1
npx @ton/mcp@alpha emulate_transaction --messages '<transaction.messages>'
npx @ton/mcp@alpha send_raw_transaction --messages '<transaction.messages>' --fromAddress '<transaction.fromAddress>'
npx @ton/mcp@alpha get_transaction_status --normalizedHash <NORMALIZED_HASH>
```

**Approximate agent response**

> `foundation.ton` was resolved to TON address `EQ...`. The `1 TON` transfer was sent with `normalizedHash: <NORMALIZED_HASH>`. Transaction status: `completed`.

### Preview a TON transfer before sending

**User request**

`Prepare a 0.5 TON payment to UQAbc... and show me what happens before sending`

**Approximate command list**

```bash
npx @ton/mcp@alpha build_ton_transfer --toAddress UQAbc... --amount 0.5
npx @ton/mcp@alpha emulate_transaction --messages '<transaction.messages>'
```

**Approximate agent response**

> Prepared the `0.5 TON` transfer (it was not sent). Emulation shows the expected balance changes and fees. Confirm to broadcast it with `send_raw_transaction`.

### Send a jetton

**User request**
Expand All @@ -212,13 +231,15 @@ npx @ton/mcp@alpha get_transaction_status --normalizedHash <NORMALIZED_HASH>

```bash
npx @ton/mcp@alpha get_jettons
npx @ton/mcp@alpha send_jetton --jettonAddress EQ... --toAddress UQAbc... --amount 25
npx @ton/mcp@alpha build_jetton_transfer --jettonAddress EQ... --toAddress UQAbc... --amount 25
npx @ton/mcp@alpha emulate_transaction --messages '<transaction.messages>'
npx @ton/mcp@alpha send_raw_transaction --messages '<transaction.messages>' --fromAddress '<transaction.fromAddress>'
npx @ton/mcp@alpha get_transaction_status --normalizedHash <NORMALIZED_HASH>
```

**Approximate agent response**

> `USDT` was found in the wallet, and the `25 USDT` transfer to `UQAbc...` was sent. `normalizedHash: <NORMALIZED_HASH>`. Current status: `completed`.
> `USDT` was found in the wallet. I prepared the `25 USDT` transfer to `UQAbc...`, previewed it, then broadcast it with `send_raw_transaction`. `normalizedHash: <NORMALIZED_HASH>`. Current status: `completed`.

### Swap TON for a jetton

Expand Down Expand Up @@ -335,7 +356,9 @@ npx @ton/mcp@alpha get_nft --nftAddress EQ...
**Approximate command list**

```bash
npx @ton/mcp@alpha send_nft --nftAddress EQ... --toAddress UQReceiver...
npx @ton/mcp@alpha build_nft_transfer --nftAddress EQ... --toAddress UQReceiver...
npx @ton/mcp@alpha emulate_transaction --messages '<transaction.messages>'
npx @ton/mcp@alpha send_raw_transaction --messages '<transaction.messages>' --fromAddress '<transaction.fromAddress>'
npx @ton/mcp@alpha get_transaction_status --normalizedHash <NORMALIZED_HASH>
```

Expand Down
39 changes: 23 additions & 16 deletions packages/mcp/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,29 +86,29 @@ Returns: Transaction status (pending, completed, failed) and trace details
Get list of known/popular Jettons on TON.
Returns: array with symbol, name, address, decimals

### send_ton
Send TON to an address.
### build_ton_transfer
Build a TON transfer to an address. Does NOT broadcast.
Parameters:
- toAddress (required): recipient address
- amount (required): amount in TON (e.g., "1.5")
- comment (optional): transaction memo
Returns: top-level normalizedHash plus details
Returns: transaction {messages, validUntil, fromAddress} ready for emulate_transaction (preview) then send_raw_transaction (broadcast)

### send_jetton
Send Jettons to an address.
### build_jetton_transfer
Build a Jetton transfer to an address. Does NOT broadcast.
Parameters:
- toAddress (required): recipient address
- jettonAddress (required): token contract address
- amount (required): human-readable amount
- comment (optional): transaction memo
Returns: top-level normalizedHash plus details
Returns: transaction {messages, validUntil, fromAddress} ready for emulate_transaction (preview) then send_raw_transaction (broadcast)

### send_raw_transaction
Send raw transaction with full control.
Sign and broadcast a raw transaction with full control. This is the tool that actually sends prepared transactions (from build_ton_transfer/build_jetton_transfer/build_nft_transfer/get_swap_quote).
Parameters:
- messages (required): array of {address, amount (nanoTON), stateInit?, payload?}
- validUntil (optional): expiry timestamp
- fromAddress (optional): sender address
- fromAddress (optional): sender address; pass transaction.fromAddress when broadcasting a prepared transaction
Returns: top-level normalizedHash plus details

### emulate_transaction
Expand Down Expand Up @@ -145,12 +145,13 @@ Get NFT details.
Parameters:
- nftAddress (required): NFT item contract address

### send_nft
Transfer NFT to another address.
### build_nft_transfer
Build an NFT transfer to another address. Does NOT broadcast.
Parameters:
- nftAddress (required): NFT to transfer
- toAddress (required): recipient address
- comment (optional): transaction memo
Returns: transaction {messages, validUntil, fromAddress} ready for emulate_transaction (preview) then send_raw_transaction (broadcast)

### resolve_dns
Resolve TON DNS-compatible domain to wallet address.
Expand Down Expand Up @@ -250,13 +251,17 @@ Parameters:

### Sending TON
1. If recipient is a DNS name rather than a raw address: resolve_dns first
2. send_ton with resolved address
3. Default: poll get_transaction_status until completed or failed. User can ask to skip.
2. build_ton_transfer with resolved address (builds only — does NOT broadcast)
3. emulate_transaction with the returned transaction.messages to preview balance changes and fees (recommended before sending)
4. Confirm with user, then send_raw_transaction with transaction.messages and transaction.fromAddress to broadcast
5. Default: poll get_transaction_status until completed or failed. User can ask to skip.

### Sending Tokens
1. get_jettons to find token address
2. send_jetton with token details
3. Default: poll get_transaction_status until completed or failed. User can ask to skip.
2. build_jetton_transfer with token details (builds only — does NOT broadcast)
3. emulate_transaction with the returned transaction.messages to preview balance changes and fees (recommended before sending)
4. Confirm with user, then send_raw_transaction with transaction.messages and transaction.fromAddress to broadcast
5. Default: poll get_transaction_status until completed or failed. User can ask to skip.

### Swapping Tokens
1. get_known_jettons if needed for addresses
Expand Down Expand Up @@ -299,11 +304,13 @@ Parameters:
- If the host client exposes a structured confirmation or choice tool (approval dialog, option picker, request_user_input-style UI), use it for yes/no approvals and small option sets instead of free-text replies
- Always confirm transfers/swaps with user before executing; prefer structured confirmation UI when available, otherwise use a short natural-language yes/no confirmation, and never require a fixed phrase
- Prefer callback/status tools over asking the user to paste data that can be discovered automatically, but only in long-lived stdio/HTTP MCP server sessions, not raw CLI
- send_ton/send_jetton/get_swap_quote use human-readable amounts
- build_ton_transfer/build_jetton_transfer/get_swap_quote use human-readable amounts
- Registry mode uses the local TON config file from `~/.config/ton/config.json` or `TON_CONFIG_PATH`
- Agentic onboarding callback state is persisted in the local config; in stdio mode use `AGENTIC_CALLBACK_BASE_URL` and/or `AGENTIC_CALLBACK_PORT` when you need a stable callback endpoint across restarts
- Registry management responses are sanitized and do not expose mnemonic, private keys, operator private keys, or Toncenter API keys
- Read tools can work with imported agentic wallets without `operator_private_key`; write tools cannot
- generate_ton_proof is not a transaction, but it requires signing access and will not work with read-only imported agentic wallets
- TonProof signs wallet ownership for a domain and payload; only generate it for domains/payloads the user or verifying service intentionally provided
- **Default flow:** After any send, poll get_transaction_status until completed or failed. User can specify whether to check status.
- `build_ton_transfer`/`build_jetton_transfer`/`build_nft_transfer` and `get_swap_quote` only BUILD transactions (return `transaction.messages`); they do not broadcast. `send_raw_transaction` is the only tool that signs and sends.
- Standard transfer flow: build with build_ton_transfer/build_jetton_transfer/build_nft_transfer → preview with `emulate_transaction` → broadcast with `send_raw_transaction`, passing the prepared `transaction.fromAddress` (jetton/NFT messages are bound to the wallet they were built for)
- **Default flow:** After broadcasting via send_raw_transaction, poll get_transaction_status until completed or failed. User can specify whether to check status.
21 changes: 13 additions & 8 deletions packages/mcp/skills/ton-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ npx @ton/mcp@alpha get_jetton_balance --jettonAddress EQAbc...

# All values are passed as plain strings; JSON objects/arrays are also accepted
npx @ton/mcp@alpha get_transactions --limit 10
npx @ton/mcp@alpha send_ton --toAddress UQA... --amount 0.1 --comment "hi"
npx @ton/mcp@alpha build_ton_transfer --toAddress UQA... --amount 0.1 --comment "hi"
npx @ton/mcp@alpha generate_ton_proof --domain getgems.io --payload getgems-llm
```

Expand Down Expand Up @@ -93,12 +93,14 @@ Without `MNEMONIC` or `PRIVATE_KEY`, the CLI uses the local config registry at `

| Tool | Required args | Optional args |
| ---- | ------------- | ------------- |
| `send_ton` | `--toAddress`, `--amount` | `--comment`, `--walletSelector` |
| `send_jetton` | `--toAddress`, `--jettonAddress`, `--amount` | `--comment`, `--walletSelector` |
| `send_nft` | `--nftAddress`, `--toAddress` | `--comment`, `--walletSelector` |
| `build_ton_transfer` | `--toAddress`, `--amount` | `--comment`, `--walletSelector` |
| `build_jetton_transfer` | `--toAddress`, `--jettonAddress`, `--amount` | `--comment`, `--walletSelector` |
| `build_nft_transfer` | `--nftAddress`, `--toAddress` | `--comment`, `--walletSelector` |
| `send_raw_transaction` | `--messages` | `--validUntil`, `--fromAddress`, `--walletSelector` |
| `emulate_transaction` | `--messages` | `--validUntil`, `--walletSelector` |

`build_ton_transfer`/`build_jetton_transfer`/`build_nft_transfer` only build a transaction (return `transaction.messages` plus `transaction.fromAddress`); they do not broadcast. Preview with `emulate_transaction`, then broadcast with `send_raw_transaction --messages ... --fromAddress ...`.

### Swaps

| Tool | Required args | Optional args |
Expand Down Expand Up @@ -153,8 +155,10 @@ npx @ton/mcp@alpha get_balance --walletSelector "my-hot-wallet"
# In registry mode: list all registered wallets
npx @ton/mcp@alpha list_wallets

# Send TON (always confirm with user first)
npx @ton/mcp@alpha send_ton --toAddress UQA... --amount 0.5 --comment "payment"
# Send TON — build, preview, then broadcast (confirm with user before the broadcast step)
npx @ton/mcp@alpha build_ton_transfer --toAddress UQA... --amount 0.5 --comment "payment"
npx @ton/mcp@alpha emulate_transaction --messages '<transaction.messages>' # recommended preview
npx @ton/mcp@alpha send_raw_transaction --messages '<transaction.messages>' --fromAddress '<transaction.fromAddress>'

# Swap quote
npx @ton/mcp@alpha get_swap_quote --fromToken TON --toToken EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs --amount 1
Expand All @@ -165,10 +169,11 @@ npx @ton/mcp@alpha generate_ton_proof --domain getgems.io --payload getgems-llm

## Notes

- Use `emulate_transaction` to dry-run any transaction before sending — it returns expected balance changes, fees, and high-level actions
- `build_ton_transfer`/`build_jetton_transfer`/`build_nft_transfer` build a transaction only; `send_raw_transaction` is the tool that signs and broadcasts the prepared `transaction.messages` (pass `transaction.fromAddress` too — jetton/NFT messages are bound to the wallet they were built for)
- Use `emulate_transaction` to preview expected balance changes before broadcasting (fake signature)
- Use `generate_ton_proof` only with the exact domain and payload supplied by the user or verifying service; do not alter the payload before signing
- `generate_ton_proof` requires signing access even though it does not broadcast a transaction
- Always confirm with the user before running `send_ton`, `send_jetton`, `send_nft`, or `send_raw_transaction`;
- `build_ton_transfer`/`build_jetton_transfer`/`build_nft_transfer` and `emulate_transaction` do not sign or broadcast — run them freely. Confirm with the user only before `send_raw_transaction` (the broadcast), after previewing with `emulate_transaction`;
- For confirmations and small option sets, prefer the host client's structured confirmation/choice UI when available; otherwise use a short natural-language yes/no prompt and never require an exact magic word;
- After sending, poll `get_transaction_status --normalizedHash <hash>` until status is `completed` or `failed` (unless the user asks to skip).
- In registry mode the active wallet from `~/.config/ton/config.json` is used by default.
Loading
Loading