MCP Server TronLink
Overview
GitHub: https://github.com/TronLink/mcp-server-tronlink
mcp-server-tronlink is a production-ready Model Context Protocol (MCP) server that enables AI agents (Claude, GPT, etc.) to interact with the TRON blockchain through natural language. Built on @tronlink/tronlink-mcp-core, it provides 55 tools in list_tools — 52 core tools registered by tronlink-mcp-core + 3 wallet management tools registered locally by this server's src/wallet-tools.ts — across two complementary operation modes.
Key Highlights: - Dual-mode architecture: Playwright (browser automation) + Direct API (on-chain operations) - 32 built-in Flow Recipes with pre-checks and dependency resolution - Non-custodial local transaction signing via encrypted agent-wallet - Multi-signature management with real-time WebSocket monitoring - Gas-free TRC20 transfers via GasFree service integration
Architecture
flowchart TD
Agent["AI Agent<br/>(Claude Desktop / Claude Code)"]
Server["TronLink MCP Server"]
PW["Playwright Mode<br/>TronLinkSessionManager<br/>(browser automation + extension UI)"]
API["Direct API Mode"]
OnChain["TronLinkOnChainCapability (14 tools)"]
Multi["TronLinkMultiSigCapability (5 tools)"]
GasFree["TronLinkGasFreeCapability (3 tools)"]
Util["Utility Capabilities<br/>Build · StateSnapshot · TRON Crypto"]
Flow["Flow Recipes<br/>(32 built-in, pre-checked)"]
Ext["TronGrid API / Multi-Sig Service / GasFree Service"]
Chain["TRON Blockchain"]
Agent -- "MCP Protocol — stdio / JSON-RPC 2.0" --> Server
Server --> PW
Server --> API
Server --> Util
Server --> Flow
API --> OnChain
API --> Multi
API --> GasFree
PW --> Ext
OnChain --> Ext
Multi --> Ext
GasFree --> Ext
Ext --> Chain Both modes can run simultaneously and tools are auto-enabled based on configuration.
Dual-Mode Operation
Mode 1: Playwright (Browser Automation)
Controls the TronLink Chrome extension via Playwright Chromium. Ideal for E2E testing, UI validation, and DApp interaction.
Capabilities: - Launch browser with --load-extension flag for TronLink - Auto-detect extension ID from Chrome API - Multi-tab tracking with automatic role classification (extension / notification / dapp / other) - DOM-based state extraction (TRON address, TRX balance, network detection) - Screenshot capture with base64 encoding - Automatic browser dialog handling (alerts, confirms, prompts)
27 Playwright tools include: tl_launch, tl_cleanup, tl_navigate, tl_click, tl_type, tl_screenshot, tl_accessibility_snapshot, tl_describe_screen, etc.
The "27" is
52 core − 22 chain/multisig/gasfree − 3 mode-agnostic (run_steps, list_flows, set_context) = 27.tl_clipboard,tl_keyboard,tl_scroll, etc. are Playwright-mode UI tools and counted in the 27.
Mode 2: Direct API + Wallet Management
Operates directly against TronGrid / multi-sig / GasFree REST APIs — no browser required. Ideal for account queries, transfers, swaps, staking, multi-sig management, and runtime wallet hot-swap.
28 tools = 22 mode-2 API tools (from core) + 3 mode-agnostic core tools + 3 wallet management tools (from this server). Grouping:
| Group | Tools | Source | Description |
|---|---|---|---|
| On-Chain | 14 | core | Transfer, stake, swap, query, multisig setup |
| Multi-Signature | 5 | core | Permission query, tx submit, WebSocket monitoring |
| GasFree | 3 | core | Zero-gas TRC20 transfers |
| Wallet Management | 3 | this server (src/wallet-tools.ts) | List wallets, auto-create a wallet, switch the active wallet |
| Mode-agnostic | 3 | core | tl_run_steps, tl_list_flows, tl_set_context — invoked from either mode |
Why the breakdown differs from the architecture diagram. The architecture node only enumerates capability classes (
OnChainCapability,MultiSigCapability,GasFreeCapability). Wallet management lives outside the capability interface — it's registered bysrc/wallet-tools.tsand hot-swaps wallets into running capabilities via theonWalletSwapcallback insrc/index.ts.
Core Components
1. TronLinkSessionManager
Full browser lifecycle management:
| Method | Description |
|---|---|
launch() | Initialize browser with TronLink extension |
getExtensionState() | Extract wallet state from UI |
navigateToUrl() | Navigate to a specific URL |
navigateToNotification() | Open TronLink notification popup |
screenshot() | Capture current UI state |
getTrackedPages() | List all open browser tabs |
cleanup() | Graceful shutdown of all resources |
Screen Detection: Auto-detects 15 TronLink screens: home, login, settings, send, receive, sign, broadcast, assets, address_book, node_management, dapp_list, create_wallet, import_wallet, notification, unknown.
2. TronLinkOnChainCapability (14 Tools)
Direct API wrapper for TronGrid:
Query Operations: - getAddress() — Get the TRON address from encrypted local agent-wallet - getAccount() — Balance, bandwidth, energy, permissions - getTokens() — TRC10 and TRC20 token balances - getTransaction() — Transaction details by txID - getHistory() — Transaction history with pagination - getStakingInfo() — Staking status (frozen amounts, votes, unfreezing)
Transaction Operations: - send() — Transfer TRX, TRC10, or TRC20 tokens - stake() — Freeze/unfreeze TRX for bandwidth or energy (Stake 2.0) - resource() — Delegate/undelegate bandwidth or energy - swap() — Token swap via SunSwap V2 - swapV3() — Token swap via SunSwap V3 Smart Router
Multi-Sig Operations: - setupMultisig() — Configure multi-sig permissions - createMultisigTx() — Create unsigned multi-sig transaction - signMultisigTx() — Sign multi-sig transaction
3. TronLinkMultiSigCapability (5 Tools)
REST + WebSocket API for TRON multi-signature service:
queryAuth()— Query multi-sig permissions (owner/active, thresholds, weights)submitTransaction()— Submit signed transaction (auto-broadcast when threshold reached)queryTransactionList()— List transactions with filteringconnectWebSocket()— Real-time transaction monitoringdisconnectWebSocket()— Stop monitoring
Implementation: HmacSHA256 signature generation for API auth, UUID-based request signing, supports both Nile testnet and Mainnet credentials.
4. TronLinkGasFreeCapability (3 Tools)
Zero-gas TRC20 transfers via GasFree service:
getAccount()— Query eligibility, supported tokens, daily quotagetTransactions()— Query gas-free transaction historysend()— Send TRC20 with zero gas fee
5. Wallet Management (3 Tools)
Runtime wallet management via @bankofai/agent-wallet (encrypted local_secure storage):
tl_wallet_list— List all wallets with IDs, types, active status, and TRON addressestl_wallet_create— Auto-generate an encrypted wallet and attach it to the running MCP sessiontl_wallet_set_active— Switch the active wallet by ID (hot-swaps into all capabilities)
If no wallet exists at startup, the server prompts two paths: call tl_wallet_create to auto-generate one, or create one manually via CLI and set AGENT_WALLET_PASSWORD. The auto-create path generates a random password, saves it to ~/.agent-wallet/runtime_secrets.json, creates an encrypted main wallet, and enables the running session to use it.
6. TRON Cryptography Utils
Pure cryptographic functions — no external service calls:
signTransaction() raw_data_hex → 65-byte signature (via agent-wallet)
base58CheckEncode() Payload → base58check address
base58CheckDecode() TRON address → 21-byte payload
addressToHex() T-address → 0x41... hex
hexToAddress() 0x41... → T-address
Uses @noble/curves (secp256k1 ECDSA) and @noble/hashes (Keccak-256, SHA256). Private keys are never exposed — all signing is done through the encrypted agent-wallet.
Flow Recipes (32 Built-In)
Pre-configured multi-step workflows with dependency checks and parameter templates.
Playwright Flows
| Flow | Description |
|---|---|
switchNetworkFlow | Switch to Mainnet/Nile/Shasta |
enableTestNetworksFlow | Enable testnet visibility |
transferTrxFlow | TRX transfer via UI |
transferTokenFlow | Token transfer via UI |
On-Chain Flows (11)
| Flow | Description |
|---|---|
chainCheckBalanceFlow | Query balance |
chainTransferTrxFlow | TRX transfer with pre-checks |
chainTransferTrc20Flow | TRC20 transfer with pre-checks |
chainStakeFlow | Stake TRX |
chainUnstakeFlow | Unstake TRX |
chainGetStakingFlow | Query staking info |
chainDelegateResourceFlow | Delegate bandwidth/energy |
chainUndelegateResourceFlow | Undelegate resources |
chainSetupMultisigFlow | Setup multi-sig permissions |
chainCreateMultisigTxFlow | Create unsigned multi-sig tx |
chainSwapV3Flow | SunSwap V3 token swap |
Multi-Sig Flows (6)
| Flow | Description |
|---|---|
multisigQueryAuthFlow | Query permissions |
multisigListTransactionsFlow | List pending transactions |
multisigMonitorFlow | WebSocket real-time monitoring |
multisigStopMonitorFlow | Stop monitoring |
multisigSubmitTxFlow | Submit signed transaction |
multisigCheckFlow | Full status check |
GasFree Flows (3)
| Flow | Description |
|---|---|
gasfreeCheckAccountFlow | Query eligibility |
gasfreeTransactionHistoryFlow | Query history |
gasfreeSendFlow | Gas-free TRC20 transfer |
Configuration
Environment Variables
Playwright Mode:
| Variable | Description |
|---|---|
TRONLINK_EXTENSION_PATH | TronLink extension build directory |
TRONLINK_SOURCE_PATH | Enable build capability |
TL_MODE | e2e (test) or prod (production) |
TL_HEADLESS | Browser headless mode |
TL_SLOW_MO | Playwright slow-motion delay (ms) |
TronGrid API:
| Variable | Description |
|---|---|
TL_TRONGRID_URL | Full-node API URL |
TL_TRONGRID_API_KEY | API key (required for Mainnet). Free tier ≈ 100k requests/day at ~5 QPS; paid tiers raise QPS, daily quota, and add billing. Quotas and headers change over time — see TronGrid Pricing and the dashboard for current values, and inspect X-Ratelimit-* response headers in your own runtime. Hitting the limit returns HTTP 429 (mapped to TL_CHAIN_QUERY_FAILED, retryable). For long-running agents, set up billing alerts at 50% / 80% / 95% of your plan. |
TL_SUNSWAP_ROUTER | SunSwap V2 router address. No built-in default — pin to the current router; the value in the example below is effective as of 2026-05 (Mainnet). Source: docs.sun.io. When SunSwap publishes a new router, set this env var rather than waiting on a docs/code change. |
TL_SUNSWAP_V3_ROUTER | SunSwap V3 smart router address. Same rules as V2. |
TL_WTRX_ADDRESS | WTRX contract address. Mainnet WTRX is TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR. Effective as of 2026-05. |
Wallet (agent-wallet):
| Variable | Description |
|---|---|
AGENT_WALLET_PASSWORD | Encryption password (optional if using tl_wallet_create; required for manual or existing wallets) |
AGENT_WALLET_DIR | Custom wallet storage directory |
TL_OWNER_WALLET_ID | Owner wallet ID for multisig signing |
TL_COSIGNER_WALLET_ID | Co-signer wallet ID for multisig |
Multi-Signature Service:
| Variable | Description |
|---|---|
TL_MULTISIG_BASE_URL | API base URL |
TL_MULTISIG_SECRET_ID | Project credential |
TL_MULTISIG_SECRET_KEY | HmacSHA256 signing key |
TL_MULTISIG_CHANNEL | Channel/project name |
GasFree Service:
| Variable | Description |
|---|---|
TL_GASFREE_BASE_URL | Service URL |
TL_GASFREE_API_KEY | API key |
TL_GASFREE_API_SECRET | API secret |
Integration Options
1. Project-Level MCP Config (.mcp.json)
Auto-detected by Claude Code:
{
"mcpServers": {
"tronlink": {
"command": "node",
"args": ["dist/index.js"],
"cwd": ".",
"env": {
"TL_TRONGRID_URL": "https://nile.trongrid.io"
}
}
}
}
If no wallet exists yet, startup shows two paths:
- Auto-create in the running MCP session: call
tl_wallet_create - Manual setup: create the wallet locally with
agent-wallet start local_secure --generate --wallet-id main, then setAGENT_WALLET_PASSWORDand restart
If you choose auto-create, the server generates a random password, saves it to ~/.agent-wallet/runtime_secrets.json, creates an encrypted main wallet, and continues with the current session.
For a ready-to-use Nile setup with the common fields already filled, you can extend the config like this:
{
"mcpServers": {
"tronlink": {
"command": "node",
"args": ["dist/index.js"],
"cwd": ".",
"env": {
"TRONLINK_EXTENSION_PATH": "/path/to/tronlink-extension/dist",
"TL_MODE": "prod",
"TL_HEADLESS": "false",
"TL_TRONGRID_URL": "https://nile.trongrid.io",
"AGENT_WALLET_PASSWORD": "your-wallet-password",
"TL_SUNSWAP_ROUTER": "TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax",
"TL_SUNSWAP_V3_ROUTER": "TB6xBCixqRPUSKiXb45ky1GhChFJ7qrfFj",
"TL_MULTISIG_BASE_URL": "https://apinile.walletadapter.org",
"TL_MULTISIG_SECRET_ID": "TEST",
"TL_MULTISIG_SECRET_KEY": "TESTTESTTEST",
"TL_MULTISIG_CHANNEL": "test",
"TL_GASFREE_BASE_URL": "https://open-test.gasfree.io/nile/",
"TL_GASFREE_API_KEY": "your_gasfree_api_key",
"TL_GASFREE_API_SECRET": "your_gasfree_api_secret"
}
}
}
}
If you only need direct API tools and do not need browser automation, you can keep the same structure and omit the Playwright-related fields:
{
"mcpServers": {
"tronlink": {
"command": "node",
"args": ["dist/index.js"],
"cwd": ".",
"env": {
"TL_TRONGRID_URL": "https://nile.trongrid.io",
"AGENT_WALLET_PASSWORD": "your-wallet-password",
"TL_MULTISIG_BASE_URL": "https://apinile.walletadapter.org",
"TL_MULTISIG_SECRET_ID": "TEST",
"TL_MULTISIG_SECRET_KEY": "TESTTESTTEST",
"TL_MULTISIG_CHANNEL": "test",
"TL_GASFREE_BASE_URL": "https://open-test.gasfree.io/nile/",
"TL_GASFREE_API_KEY": "your_gasfree_api_key",
"TL_GASFREE_API_SECRET": "your_gasfree_api_secret"
}
}
}
}
2. Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"tronlink": {
"command": "node",
"args": ["/absolute/path/to/dist/index.js"],
"env": { ... }
}
}
}
3. Claude Code Global Settings
Edit ~/.claude/settings.json or .claude/settings.json.
4. Any MCP Client
Supports stdio transport protocol — compatible with any MCP-compliant client.
Project Structure
mcp-server-tronlink/
├── src/
│ ├── index.ts # Server entry, config, capability registration
│ ├── wallet.ts # Encrypted wallet loading and password handling
│ ├── wallet-tools.ts # Wallet list/create/switch tools
│ ├── session-manager.ts # Browser lifecycle (TronLinkSessionManager)
│ ├── capabilities/
│ │ ├── on-chain.ts # 14 on-chain operations (TronGrid)
│ │ ├── multisig.ts # 5 multi-sig operations (REST + WS)
│ │ ├── gasfree.ts # 3 gas-free transfer operations
│ │ ├── build.ts # Extension webpack build
│ │ ├── state-snapshot.ts # UI state extraction
│ │ └── tron-crypto.ts # Address derivation, signing, Base58
│ └── flows/
│ ├── index.ts # Flow registry (32 recipes)
│ ├── switch-network.ts # Network switching flows
│ ├── transfer-trx.ts # Transfer flows
│ ├── multisig.ts # 6 multi-sig flows
│ ├── onchain.ts # 11 on-chain flows
│ └── gasfree.ts # 3 gas-free flows
├── dist/ # Compiled output
├── .mcp.json # MCP configuration
├── .env.example # Environment variable reference
├── package.json
├── tsconfig.json
└── README.md
Dependencies
Pinned to the package.json of mcp-server-tronlink@0.1.1. Re-verify when bumping major versions of the wallet, MCP, or crypto libraries.
| Package | Version | Purpose |
|---|---|---|
@noble/curves | ^2.0.1 | secp256k1 ECDSA signing |
@noble/hashes | ^2.0.1 | Keccak-256, SHA256 |
@tronlink/tronlink-mcp-core | ^0.1.0 | Core MCP server framework |
playwright | ^1.49.0 | Browser automation |
@bankofai/agent-wallet | ^2.3.0 | Encrypted local wallet management (local_secure) — pinned, not latest, to keep wallet behavior reproducible |
ws | ^8.18.0 | WebSocket (multi-sig monitoring) |
Tool Contract & Side Effects
Input/output schemas and error contract. Each tool's input/output schema and the structured error envelope are defined by the underlying framework — see TronLink MCP Core for the SSOT error code table (code / retryable / hint / triggered_by). Every response carries meta.schemaVersion; field meanings are stable within a major version. Agents should branch on error.code and error.retryable, never on the human-readable message.
Per-tool input schemas are discoverable at runtime. Every tool's parameters are Zod-validated in core and exposed as a JSON inputSchema via the MCP list_tools method, so a client can enumerate names, types, and required fields without reading this page. The tables below summarize tools by capability; list_tools is the authoritative, machine-readable source.
Side-effect classification. Classify before calling; never auto-retry a write whose outcome is uncertain.
| Side effect | Examples |
|---|---|
| Read-only (Network Read) | tl_chain_get_account, tl_chain_get_tx, tl_gasfree_get_account, tl_wallet_list, screen/state reads |
| Remote Write (signs / changes remote state) | tl_chain_send, tl_chain_stake, tl_chain_swap_v3, tl_multisig_submit_tx, transfers, delegation |
- Pre-checks: all transaction tools validate (balances, reverts, resource burn) before execution.
- Human-in-the-loop: write tools sign with the encrypted local
agent-wallet; in browser-mode flows the user approves in the TronLink UI. Treat every Remote Write tool as requiring confirmation in production. - Retry: read-only tools are safe to retry; Remote Write tools must not be auto-retried unless proven idempotent.
Selected tool schemas (inline mirror)
These are docs-side mirrors of the most critical tool inputs — useful when an agent is writing a tool-call call site without an MCP session open. Runtime list_tools remains the authoritative source: the schemas there carry full Zod metadata (descriptions, default, etc.) plus meta.schemaVersion. Fields below are derived from @tronlink/tronlink-mcp-core src/mcp-server/schemas.ts and follow JSON Schema Draft 7. The full set of 52 tool schemas is not reproduced here — see core for the SSOT.
Parity is enforced.
scripts/check_doc_schema_parity.py(run on push, PR, and daily viacheck-doc-schema-parity.yml) diffs the top-level field set + required-flag set of every block below against the liveschemas.ts. Upstream rename or required→optional drift fails CI.
tl_chain_send — Remote Write
{
"type": "object",
"required": ["to", "amount"],
"properties": {
"to": { "type": "string", "description": "Recipient TRON address (T-prefix, 34 chars)" },
"amount": { "type": "string", "description": "Amount to send (e.g. \"1.5\" for TRX, or token amount string)" },
"token_type": { "type": "string", "enum": ["TRX", "TRC10", "TRC20"], "description": "Default: TRX" },
"token_id": { "type": "string", "description": "TRC10 token ID (required when token_type=TRC10)" },
"contract_address": { "type": "string", "description": "TRC20 contract address (required when token_type=TRC20)" },
"memo": { "type": "string", "description": "Optional transaction memo" }
}
}
tl_chain_swap_v3 — Remote Write (when action=execute)
{
"type": "object",
"required": ["action", "from_token", "to_token", "amount"],
"properties": {
"action": { "type": "string", "enum": ["estimate", "execute"], "description": "estimate = quote-only (Network Read); execute = sign & broadcast (Remote Write)" },
"from_token": { "type": "string", "description": "Source token address or 'TRX' for native" },
"to_token": { "type": "string", "description": "Target token address or 'TRX' for native" },
"amount": { "type": "string", "description": "Input amount in token units" },
"fee_tier": { "type": "number", "enum": [500, 3000, 10000], "description": "Pool fee tier in bps: 500=0.05%, 3000=0.3%, 10000=1% (default: 3000)" },
"slippage": { "type": "number", "description": "Slippage tolerance percent (default: 0.5). See 'Swap safety' above — never accept an unstated default for production execution." },
"sqrt_price_limit": { "type": "string", "description": "Optional price limit for partial fills (advanced)" }
}
}
tl_chain_stake — Remote Write
{
"type": "object",
"required": ["action", "amount_trx"],
"properties": {
"action": { "type": "string", "enum": ["freeze", "unfreeze"], "description": "freeze locks TRX for resources; unfreeze starts the 14-day withdrawal" },
"amount_trx": { "type": "number", "description": "Amount of TRX to freeze / unfreeze" },
"resource": { "type": "string", "enum": ["BANDWIDTH", "ENERGY"], "description": "Resource type (default: BANDWIDTH)" }
}
}
tl_multisig_submit_tx — Remote Write
{
"type": "object",
"required": ["address", "transaction"],
"properties": {
"address": { "type": "string", "description": "Signer address submitting this transaction" },
"function_selector": { "type": "string", "description": "e.g. 'transfer(address,uint256)' (optional)" },
"expire_time": { "type": "number", "description": "Expiration timestamp in ms (default: now + 24h)" },
"transaction": { "type": "object", "description": "Signed transaction { raw_data, signature[] }. Each contract entry may carry a Permission_id." }
}
}
The full transaction shape (raw_data → contract[] → parameter, etc.) is in tronlink-mcp-core schemas.ts — too verbose to mirror inline.
tl_gasfree_send — Remote Write
{
"type": "object",
"required": ["to", "amount", "contract_address"],
"properties": {
"to": { "type": "string", "description": "Recipient TRON address" },
"amount": { "type": "string", "description": "Token amount in token units (e.g. '10.5')" },
"contract_address": { "type": "string", "description": "TRC20 token contract address" }
}
}
tl_chain_get_account — Network Read
{
"type": "object",
"properties": {
"address": { "type": "string", "description": "TRON address to query (default: configured wallet)" }
}
}
tl_evaluate — High-risk / Destructive (Playwright-only)
{
"type": "object",
"required": ["script"],
"properties": {
"script": { "type": "string", "description": "JavaScript expression to evaluate in the controlled browser page context. Return value is serialized." },
"timeout": { "type": "number", "description": "Timeout in ms (default: 30000)" }
}
}
Reminder: tl_evaluate runs arbitrary JS in the controlled Playwright browser. Disable it from the MCP host's tool allowlist unless strictly needed (see Security Model below).
Security Model
| Aspect | Implementation |
|---|---|
| Key storage | Encrypted local wallet managed by @bankofai/agent-wallet |
| Key exposure | No key material logged to stderr |
| Signing | Local transaction signing via encrypted agent-wallet — plain-text private keys are not supported |
| Pre-checks | All transactions validate before execution |
| Git safety | Config files in .gitignore prevent accidental commits |
| Default network | Nile testnet with safe defaults |
Security Boundaries
| Boundary | Guarantee | Agent / operator obligation |
|---|---|---|
| Prompt injection | Tool inputs are consumed verbatim as call arguments. The server never concatenates tool inputs into a prompt re-sent to an LLM. Strings retrieved from chain or third-party APIs (account memos, contract revert reasons, transaction notes) may contain attacker-controlled text — treat them as untrusted. | Do not let the agent auto-route Remote Write tools off prose returned from a read. Always require structured fields (txId, code, retryable) for branching. |
| Outbound host allowlist (SSRF) | The server only originates HTTPS to the four configured endpoints: TL_TRONGRID_URL (TronGrid), TL_MULTISIG_BASE_URL, TL_GASFREE_BASE_URL, and SunSwap routers via TronWeb. Tools never accept user-supplied URLs that get fetched verbatim. | Pin these env vars to known hosts in production; do not let LLM input populate any *_BASE_URL. |
| API key handling (token passthrough) | TL_TRONGRID_API_KEY, TL_MULTISIG_SECRET_KEY, TL_GASFREE_API_SECRET are read from env at startup and used only on the outbound leg. They are not returned in any tool response, error details, or Knowledge Store record. The server does not accept Authorization headers from MCP clients and forward them upstream. | Audit env capture in your MCP host config (some hosts log env); store secrets in the host's secret manager, not in .mcp.json committed to git. |
| Browser JS execution | tl_evaluate runs arbitrary JavaScript in the controlled Playwright browser context. This is a High-risk / Destructive primitive — it can read DOM, click invisible elements, exfiltrate state, and bypass UI HITL. | Disable tl_evaluate from the MCP host's tool allowlist for any agent that does not strictly require it. Never expose it to a remote/multi-user MCP deployment. |
| HITL bypass | Direct-API tools (tl_chain_send, tl_chain_swap_v3, etc.) sign with the local encrypted agent-wallet and broadcast without a TronLink browser approval. The agent-wallet password is the only barrier. | Hold AGENT_WALLET_PASSWORD outside the agent's reach. For production, prefer mcp-tronlink-signer (browser approval) over Direct-API for any tool that moves funds. |
| Confused deputy | Tools operate under the local agent-wallet identity, not the calling user's identity. There is no per-call authorization scope. | One MCP session = one wallet identity; do not multiplex multiple end users through the same server. |
| Transport | stdio transport; the server does not bind a network listener. | Do not wrap this server behind a public HTTP transport without re-introducing auth and rate limiting. |
Swap safety (tl_chain_swap / tl_chain_swap_v3)
Swaps are Remote Write and execute against a public DEX router, so they are exposed to price slippage and front-running / MEV (e.g. sandwich attacks): the realized output can be worse than quoted if the pool moves between quote and execution.
- Always bound the trade with a minimum-output / slippage limit. Inspect the
tl_chain_swap_v3input schema vialist_tools(theSwapV3Paramsshape) for the exact slippage / minimum-output field names — do not rely on an unstated default, and treat a missing or zero minimum-output as unsafe. - Quote immediately before executing. Get a fresh quote/route (e.g. Skills
tron-swapswap-quote/swap-route), pick a tolerance you accept, and pass it explicitly. - Pin the router.
TL_SUNSWAP_V3_ROUTERhas no built-in default; a stale or wrong router can route funds unexpectedly. Set it to the current SunSwap V3 router (see Environment Variables). - No auto-retry. A failed/uncertain swap is a Remote Write — confirm on-chain before re-issuing (
TL_CHAIN_SWAP_FAILEDis not retryable).
Multi-sig credential hygiene (TL_MULTISIG_SECRET_ID / TL_MULTISIG_SECRET_KEY)
These are HMAC-SHA256 API credentials for the multi-sig service (not on-chain keys), but they authorize transaction submission — treat them as secrets.
- Per-environment isolation. Use distinct credentials for Mainnet vs testnet and per project/channel (
TL_MULTISIG_CHANNEL). Never reuse a Mainnet secret in a test/staging MCP host. - Storage. Keep them in the host's secret manager / env, never in a
.mcp.jsoncommitted to git (see the token-passthrough boundary above). - Rotation. Rotate
TL_MULTISIG_SECRET_KEYperiodically, and immediately if a host or log may have captured it. The server reads credentials from env at startup, so rotation on this side is an env update + server restart; issue/revoke the credential itself through the multi-sig service console. - Revocation. If a secret is suspected leaked, revoke it at the service and rotate before the next signing session — an exposed secret lets an attacker submit transactions to the multi-sig queue.
- Least privilege. Scope each credential to the channel/project it needs; do not share one secret across unrelated agents.
Disabling tl_evaluate
If your workflow does not require running arbitrary JS in the controlled browser, take it off the tool surface explicitly. The exact key depends on the host:
// Claude Code — .claude/settings.json (project) or ~/.claude/settings.json (user)
{
"permissions": {
"deny": ["mcp__tronlink__tl_evaluate"]
}
}
// Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"tronlink": {
"command": "node",
"args": ["dist/index.js"],
"disabledTools": ["tl_evaluate"]
}
}
}
// Generic MCP client: prefer client-side filtering via list_tools.
// Filter the server's announced tools before exposing them to the model;
// drop any tool whose name is "tl_evaluate".
Verify after restart with list_tools — tl_evaluate should not appear. The same pattern works for tl_seed_contract / tl_seed_contracts (e2e-only contract deployment).
Wallet Secret Storage
The Direct-API path signs with a local encrypted wallet managed by @bankofai/agent-wallet. Two paths exist for unlocking it; pick deliberately.
Path A — Manual (recommended for production). Create the wallet out-of-band, set AGENT_WALLET_PASSWORD via the MCP host's secret manager, and start the server. The password lives only in process memory; nothing is written by this server.
Path B — Auto-create (convenience for local dev). If no wallet exists at startup and the agent calls tl_wallet_create, the server:
- Generates a random password.
- Writes it in plaintext to
~/.agent-wallet/runtime_secrets.jsonso a restart can reuse the wallet. - Creates an encrypted
mainwallet at~/.agent-wallet/(override withAGENT_WALLET_DIR).
| Aspect | Behavior |
|---|---|
| File | ~/.agent-wallet/runtime_secrets.json (plaintext JSON containing the password) |
| Recommended permissions | chmod 600 — the file is created under the user's $HOME, but no umask hardening is enforced. Verify after first run. |
| Git safety | ~/.agent-wallet/ is outside any repo by default. If you point AGENT_WALLET_DIR inside a repo, add it to .gitignore explicitly. |
| Knowledge Store redaction | The Knowledge Store auto-redacts password, mnemonic, private_key, seed fields in tool inputs / outputs. It does not read or sanitize runtime_secrets.json. The file is independent of the Knowledge Store. |
| Logs / stderr | The auto-generated password is not logged. The file path may appear in startup output. |
| Backups | Backing up ~/.agent-wallet/ without also protecting runtime_secrets.json defeats encryption-at-rest. Either back up both encrypted, or back up the encrypted wallet and re-set the password by hand on restore. |
Production guidance.
- Prefer Path A. Source
AGENT_WALLET_PASSWORDfrom the host's secret manager (Claude Desktop env, vault, etc.). - If you must use Path B (e.g., ephemeral CI), set
AGENT_WALLET_DIRto a tmpfs path that is destroyed at job end. - For any tool that moves real funds, prefer
mcp-tronlink-signer(browser approval, no on-disk password) over Direct-API.
How to enforce Path A (doc-side, today).
-
Provision the wallet before the server boots. From a separate shell:
agent-wallet start local_secure --generate --wallet-id main # take note of the password you supply here — it is the only copy -
Inject the password via the MCP host's secret manager so it lands in the server's
envat launch:// .mcp.json — secret comes from host env, not from this file { "mcpServers": { "tronlink": { "command": "node", "args": ["dist/index.js"], "env": { "AGENT_WALLET_PASSWORD": "${AGENT_WALLET_PASSWORD}" } } } } -
Do not let the agent call
tl_wallet_create. Disable it the same way astl_evaluateabove (Claude Codepermissions.deny, Claude DesktopdisabledTools, or client-sidelist_toolsfiltering on the nametl_wallet_create). -
Verify on first launch:
list_toolsshould not includetl_wallet_create, and the absence of~/.agent-wallet/runtime_secrets.jsonconfirms Path B did not run.
Tracking issue (code-side). A --no-auto-create / AGENT_WALLET_DISABLE_AUTOCREATE=1 flag that makes the server fail-loud at startup when no wallet exists is the proper long-term fix; until that ships upstream, the doc-side enforcement above is the defense in depth.
Typical Usage Scenarios
- Wallet Operations — List wallets, auto-create or switch the active wallet, check balance, send transfers
- DApp Testing — Launch browser, connect wallet, sign transactions, verify state
- On-Chain Trading — Direct API swaps, staking, token transfers without browser
- Multi-Sig Workflows — Set up permissions, submit/monitor transactions
- Gas-Free Operations — TRC20 transfers without TRX balance requirements
- Infrastructure Testing — Contract deployment, fixture management, mock servers
Quick Start
# 1. Build
npm install && npm run build
# 2. Configure .mcp.json (Nile testnet example)
# Add:
# TL_TRONGRID_URL=https://nile.trongrid.io
#
# 3. If no wallet exists, choose one path:
# Option A: call tl_wallet_create after startup
# Option B: create one locally, then set AGENT_WALLET_PASSWORD
# 4. Use with Claude Code
# "Check my TRX balance"
# "Send 10 TRX to TAddress..."
# "Swap 100 TRX for USDT on SunSwap V3"
Version & License
- Package:
@tronlink/mcp-server-tronlinkv0.1.1 - License: MIT —
SPDX-License-Identifier: MIT - Changelog / releases: https://github.com/TronLink/mcp-server-tronlink/releases — no GitHub-tagged releases yet; pre-1.0 ships via
package.jsonversion bumps. Track changes by commit until the first tag.
Compatibility & migration policy
- Semver. Pre-1.0: a minor bump (0.x → 0.y) may introduce breaking changes; a patch bump (0.1.x → 0.1.y) will not change tool names, input schemas,
error.codevalues, ormeta.schemaVersionsemantics. Post-1.0: standard semver — major-only breaking changes. - Stable contracts (won't change in a patch):
- Tool names (
tl_chain_send,tl_chain_swap_v3,tl_multisig_*,tl_gasfree_*,tl_evaluate, etc.) error.codeenum (SSOT: TronLink MCP Core — Error Codes)error.retryablesemanticsmeta.schemaVersionmajor component- Required env var names (
TL_TRONGRID_URL,TL_MULTISIG_SECRET_KEY,AGENT_WALLET_PASSWORD, …)
- Tool names (
- Volatile contracts (may change at any time):
- Prose
messagetext, log line formats, stderr output - Internal Knowledge Store keys (consumers should not parse them)
- Pre-check error detail strings (branch on
code, not ondetails.reason)
- Prose
- Deprecation window. When a tool or input field is deprecated, the next minor release retains the old form alongside the new one for at least one minor cycle, with a
meta.deprecatedflag exposed vialist_tools; removal lands no earlier than the cycle after that. - Verifying after upgrade. Re-call
list_toolsand confirm the tool names +inputSchemayou depend on are still present before resuming the workflow. Comparemeta.schemaVersionagainst the value cached at session start.