quai-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@quai-mcp-serverWhat's the QUAI balance of 0x1234567890abcdef"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
quai-mcp-server
An MCP (Model Context Protocol) server that exposes Quai Network chain data and read-only interaction tools to AI clients like Claude Desktop and Claude Code. Built with the official @modelcontextprotocol/sdk and quais, Quai's ethers-like SDK.
What is Quai Network, in plain terms
Quai is a proof-of-work, EVM-compatible Layer 1 that scales by sharding: instead of one chain doing all the work, it splits into many chains arranged in a hierarchy.
Prime chain (1)
/ | \
Region Region Region <- "Cyprus", "Paxos", "Hydra"
/ | \ / | \ / | \
Zone Zone Zone ... 9 Zone chains totalPrime is the single top-level chain. Every miner mines Prime; it settles state across the whole network but doesn't process user transactions directly.
Region chains (currently Cyprus, Paxos, Hydra) sit beneath Prime, aggregating their Zones.
Zone chains (Cyprus1/2/3, Paxos1/2/3, Hydra1/2/3 — 9 today, more can be added as the network grows) are where the actual EVM lives: user transactions, contracts, balances, everything.
Unlike sharding designs that split security along with data, Quai keeps security unified across the whole hierarchy while only the data/throughput is split — Prime and Region chains merge-mine with the Zones beneath them.
The part that matters most for tooling: every Quai address is location-aware. The address's own bytes encode which single Zone it lives in (and whether it's on the QUAI ledger, account-based like Ethereum, or the Qi ledger, UTXO-based like Bitcoin). An address on Cyprus1 only exists on Cyprus1 — you can't ask Paxos2 about it. That's why several tools below either resolve the zone for you automatically, or ask you to specify one explicitly.
Tools
Read-only
Tool | What it does |
| QUAI balance for an address. Zone is resolved automatically from the address. |
| Block details by number/hash/tag. Requires a shard/zone, since block numbers aren't globally unique across chains. |
| Transaction + receipt by hash, including which zone it landed on. |
| Given an address, report its zone, region, and ledger (Quai vs Qi) — no network call. |
| Read-only |
| Search a small curated offline index of Quai docs and get back snippets + links. |
| Quote a conversion between QUAI and Qi, Quai's own two native ledgers — this is Quai's built-in "swap," not a third-party DEX (none is known to be confirmed on Quai). |
None of these can move funds, sign anything, or change on-chain state.
Wallets (custodial: encrypted, named, password-protected)
Tool | What it does |
| Generates a new QUAI-ledger private key + address, ground to land in a chosen zone (default |
| Same encrypted storage, for a QUAI-ledger private key you already have. |
| Generates a new Qi-ledger (UTXO-based) wallet — an HD wallet with a mnemonic, since Qi needs address derivation and UTXO scanning, not a single keypair. Encrypted the same way. |
| Same encrypted storage, for a Qi mnemonic phrase you already have. |
| Lists stored wallets of both kinds (name, ledger, address, zone). No password needed — only spending or checking a Qi balance needs it. |
| Signs and sends QUAI from a stored QUAI wallet. Two-step confirmation (see below). Sender/recipient can be in different zones — that's an external transaction (ETX), handled automatically by the network. If the recipient is a Qi address, this doubles as the QUAI→Qi conversion path (see below). |
| Total and spendable Qi balance for a Qi wallet. Needs the password — see "Why Qi needs the password" below. |
| Converts Qi held in a Qi wallet into QUAI, sent to a QUAI address. Two-step confirmation, same pattern as |
| Gets a Qi wallet's reusable BIP-47 payment code — what you hand someone so they can |
| Sends Qi from a Qi wallet to a recipient's payment code (not a plain address) — see "Qi → Qi sending" below. Two-step confirmation, same pattern as the other write tools. |
This server holds keys on your behalf once you create or import a wallet — it's custodial in that narrow, local sense, the same way a geth keystore or MetaMask's local vault is. It does not operate as a hosted service for other people's funds; everything lives in a directory on the machine running the server, encrypted with a password only you know.
How the encryption works: each wallet is a private key in the standard Web3 Secret Storage (V3 keystore) format — the same format geth and MetaMask use — via quais' encryptKeystoreJson. Concretely: the password is stretched with scrypt (N=2^17, r=8, p=1, the standard "expensive" cost parameters — this deliberately makes each password guess slow), the private key is encrypted with AES-128-CTR, and a MAC over the ciphertext detects a wrong password (or a tampered file) before any key material is derived from it. This is a well-reviewed, widely-deployed scheme; nothing here is custom cryptography.
Where wallets live: ~/.quai-mcp-server/wallets/ by default (override with QUAI_WALLET_DIR) — QUAI wallets as <name>.json, Qi wallets as <name>.qi.json. The directory is created 0700 and each keystore file 0600 (owner-read/write only, best-effort on non-POSIX platforms) — enforced explicitly after creation, not just left to the process umask. The address is stored in the clear in both cases (it's public information; that's how list_wallets and QUAI-side previews work without a password), but the private key (or mnemonic, for Qi) is never written, logged, or returned in plaintext by any tool.
Naming: a name identifies at most one QUAI wallet and at most one Qi wallet — they're independent keystores (different files, different secrets, entirely unrelated key material) that happen to share a label. You can't create two QUAI wallets (or two Qi wallets) with the same name, but reusing a QUAI wallet's name for a Qi wallet is exactly how create_wallet's pairing works, and create_qi_wallet/import_qi_wallet allow it deliberately for the same reason.
Qi wallets are HD wallets under the hood, but this server only ever stores the mnemonic — never the derived address tree or any UTXO/scan state. create_qi_wallet/import_qi_wallet encrypt {address, privateKey, mnemonic} via the exact same encryptKeystoreJson call as the QUAI side (the address/privateKey fields there are just the wallet's first derived address, present so the file is a normal, valid V3 keystore); the meaningful secret is the mnemonic. Every later operation (get_qi_balance, convert_qi_to_quai) reconstructs a fresh QiHDWallet from that mnemonic and re-derives the same receiving address on demand -- deterministically, since HD derivation for a fixed account/zone always produces the same address. This was verified directly: exporting a wallet's mnemonic and re-importing it under a different name reproduced the identical address. The tradeoff is that every Qi operation re-derives from scratch rather than reading a cache, which is simpler to reason about and can't drift from what the mnemonic actually implies, at the cost of needing the password more often than the QUAI side does (see below).
Why Qi needs the password more often: QUAI's get_balance reads a public account balance straight from the chain -- no secret needed. Qi has no such thing: a "balance" is the sum of unspent transaction outputs (UTXOs) that belong to addresses only the wallet's mnemonic can derive, so computing it at all means reconstructing the wallet first. That's why get_qi_balance takes a password (QUAI's get_balance doesn't), and why convert_qi_to_quai's preview step can quote a conversion rate but can't confirm you actually have enough Qi to spend -- that check only happens once the password arrives at the confirm step.
Password rules: minimum 8 characters, checked before anything is encrypted. There's no separate rate-limiting on wrong-password attempts — scrypt's cost parameters already make each guess computationally expensive, which is the standard defense for this kind of local keystore.
Confirmation flow for send_transaction, convert_qi_to_quai, and send_qi: all three always require two calls, and only the second one needs the password.
Call with the destination and amount (
walletName/to/amountforsend_transaction;walletName/recipientPaymentCode/amount/destinationZoneforsend_qi; theto-shaped version forconvert_qi_to_quai) — no password required yet. Nothing is broadcast. You get back a preview — resolved zones, an estimate where one exists (gas for a send, converted amount for a conversion;send_qihas none, since it's a 1:1 transfer), and aconfirmationTokenvalid for 2 minutes.Call again with the same parameters, plus
confirm: true, thatconfirmationToken, and the wallet'spassword. Only then is the key/mnemonic decrypted and the transaction actually signed and sent.
A token is single-use and tied to the exact parameters previewed — if anything changes, the token expired, or it was already used, step 2 fails with a clear error and you preview again. This works the same way regardless of whether the MCP client itself has a tool-approval UI, so it's a real gate rather than relying on the client to provide one. A wrong password fails cleanly (Incorrect password for wallet "...") without leaking whether the token/params were otherwise valid.
There is intentionally no export_wallet/"show private key or mnemonic" tool — once a secret is in the store, the only way out through this server is to sign with it.
QUAI ↔ Qi conversion ("swap"): Quai has a native, protocol-level conversion between its two ledgers — QUAI (account-based) and Qi (UTXO-based, like Bitcoin) — with an on-chain exchange rate, not a third-party DEX. get_conversion_rate quotes either direction, with no wallet needed. Both execution directions are now implemented:
QUAI → Qi: just a normal
send_transactionto a Qi-ledger address (e.g. one fromcreate_qi_wallet). The tool detects this automatically (isConversion: truein the preview) and shows the estimated Qi received alongside the usual gas/balance info.Qi → QUAI:
convert_qi_to_quai, usingquais'QiHDWallet.convertToQuaiunder the hood, following the same preview/confirm/password pattern assend_transaction.
Qi → Qi sending: Qi wallets don't send to each other's addresses directly. Instead, each Qi wallet has a reusable BIP-47 payment code (get_qi_payment_code) — share that the way you'd share an address, but a fresh one-time address is derived from it for every payment, for privacy. To send, the sender "opens a channel" with the recipient's payment code (send_qi does this automatically) — this is pure local ECDH between the two payment codes, deterministic and reproducible, no on-chain action or persisted state involved. The catch is on the receiving end: those pairwise-derived addresses aren't part of the wallet's normal deterministic address sequence, so nothing will find funds sent that way unless you tell it to look. Concretely: after someone pays your Qi wallet via payment code, pass their payment code into get_qi_balance's counterpartyPaymentCodes — it opens that same channel and includes it in the balance. There's no notification mechanism (on-chain or otherwise) that tells the receiver a payment-code payment arrived; the two sides have to already know about each other out of band, the same way you'd need to know an address before checking its balance. send_qi also supports cross-zone sends (a destinationZone separate from the sender's own zone), the same way send_transaction's ETX and QiHDWallet's own zone model do.
One known rough edge: send_qi's preview step doesn't validate the payment code's format up front (there's no exported validator to check it against), so a malformed code will preview fine and only fail once you confirm — safely (nothing is sent, no funds are at risk), just later than ideal.
Not yet implemented: deploy_contract, request_faucet.
Honesty about what's tested here, updated: the full send_qi / payment-code loop was verified live against mainnet with two real wallets — a real, correctly-formatted BIP-47 payment code (PM8T...) was generated and confirmed deterministic across calls, a preview correctly detected cross-zone vs. same-zone, a confirm against an empty wallet failed with a genuine SDK error (No Qi available in zone) rather than crashing, and get_qi_balance correctly isolated an invalid counterparty payment code into rejectedPaymentCodes without failing the whole call. What's still unverified, for the same reason as everywhere else in this doc: an actual payment-code send completing between two funded wallets, since that needs real Qi and wasn't done without being asked.
Honesty about what's tested here: everything above was exercised against live mainnet, including a determinism check (exporting a Qi wallet's mnemonic and reimporting it under a different name reproduced the identical address) and real error paths (wrong password, insufficient QUAI gas, and a real QiHDWallet error -- No Qi available in zone -- when attempting to convert from an empty Qi wallet). What has not been exercised is a convert_qi_to_quai or QUAI→Qi conversion actually completing against a wallet that holds real funds, since that requires spending real money and wasn't done without being asked to.
Install
npm install
npm run buildOr run directly without installing, once published:
npx quai-mcp-serverRequirements
Node.js 18+
Configuration (environment variables)
All optional — sensible defaults point at Quai mainnet.
Variable | Default | Purpose |
|
| Mainnet RPC gateway used by tools when |
|
| Orchard testnet RPC gateway used when |
|
| Where encrypted wallet keystore files are stored. |
Every tool also accepts a network argument ("mainnet" or "testnet") per call, so a client can query either network without restarting the server.
On keys: see "Wallets" above. Keys only exist as plaintext in memory for the duration of a create_wallet/import_wallet/send_transaction call that needs them — never on disk, never logged. Treat QUAI_WALLET_DIR (and whatever machine runs this server) as you would any other local secret store: anyone with filesystem access to that directory and enough compute to brute-force a weak password can eventually decrypt a wallet, same as a local geth keystore or MetaMask vault.
Register with Claude Desktop
Add this to your Claude Desktop MCP config (claude_desktop_config.json — on macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"quai": {
"command": "npx",
"args": ["quai-mcp-server"]
}
}
}Or, if you've cloned and built this repo locally instead of using a published package:
{
"mcpServers": {
"quai": {
"command": "node",
"args": ["/absolute/path/to/quai-mcp-server/dist/index.js"]
}
}
}To point it at testnet by default, add an env block:
{
"mcpServers": {
"quai": {
"command": "npx",
"args": ["quai-mcp-server"],
"env": {
"QUAI_TESTNET_RPC_URL": "https://orchard.rpc.quai.network"
}
}
}
}(then pass "network": "testnet" in individual tool calls — the env vars set the endpoint, not the default network per call).
Register with Claude Code
claude mcp add quai -- npx quai-mcp-serveror, for a local build:
claude mcp add quai -- node /absolute/path/to/quai-mcp-server/dist/index.jsDevelopment
npm run dev # tsc --watch
npm run build # one-shot build to dist/
npm start # run the built server directly (stdio) -- mainly useful for manual smoke testsThe server speaks MCP over stdio only in v1; there is no HTTP transport.
Design notes
quais over raw RPC: every tool goes through the
quaisSDK'sJsonRpcProvider,Contract, and address utilities rather than hand-rolledeth_/quai_JSON-RPC calls, so zone resolution, response formatting, and error shapes stay consistent with the rest of the Quai ecosystem.One provider, many zones: a single
JsonRpcProviderpointed at a base gateway URL (e.g.https://rpc.quai.network) auto-discovers active zones from the Prime chain and routes each call to the right one — most tools never construct a per-zone URL.Custody, done with standard tools, not custom crypto: wallets are stored using
quais' implementation of the Ethereum V3 keystore format (scrypt + AES-128-CTR + MAC) — the same well-reviewed schemegethand MetaMask use — rather than anything hand-rolled. See "Wallets" above for the full model.Errors are text, not stack traces: RPC/contract errors are caught and rewritten into short, specific messages (e.g. "Contract call reverted: ...", "Insufficient funds: ...", "Incorrect password for wallet...", "not a validly checksummed Quai address") instead of leaking raw exception objects to the model.
Confirmation is a real gate, not just a client hint: write tools are annotated
readOnlyHint: false(anddestructiveHint: truefor sending) so MCP clients with their own approval UI show one, butsend_transactionadditionally enforces its own preview → token → password handshake server-side (src/confirmations.tsfor the token,src/walletStore.ts+decryptKeystoreJsonfor the password), so it's still safe to call from a client with no approval UI at all.Password only needed once, at the last moment: previewing a send resolves the wallet's address straight from the unencrypted part of its keystore file and uses a
VoidSigner(a quais signer that can estimate gas but not sign) to estimate cost — no decryption, no password. Only the finalconfirm: truecall decrypts the key, and only for the duration of that one call.ETX is not a separate code path: sending to an address in a different zone uses the exact same
send_transactioncall as a same-zone send — Quai's network handles the cross-zone routing (as an external transaction) transparently once the signed transaction reaches the sender's zone. The tool just detects and reports the zones involved so the caller knows what to expect.Qi wallets are stateless between calls, on purpose:
create_qi_wallet/import_qi_walletonly ever encrypt a mnemonic.get_qi_balanceandconvert_qi_to_quaireconstruct theQiHDWalletfrom scratch each call and re-derive its address (src/qiWallet.ts) rather than reading any cached address/UTXO state -- there isn't any to read. This traded a little performance (every Qi operation re-derives and re-queries rather than hitting a cache) for a simpler, harder-to-get-wrong security story: the only thing ever at rest is the one secret that matters.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Provide AI agents and automation tools with contextual access to blockchain data including balance…
Read-only on-chain intelligence for AI agents on Base: balances, tokens, gas, tx status.
Read-only on-chain intel for AI agents on Base: balances, tokens, gas, tx status. No API keys.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Intellihackz/quai-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server