sui-mcp-server
Provides tools to query the Sui blockchain via gRPC, GraphQL, and Archival Service, enabling agents to read ledger data, inspect live state, introspect Move packages, perform relational queries, stream checkpoints, and simulate or execute transactions.
Click on "Deploy 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., "@sui-mcp-server What's the latest checkpoint?"
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.
sui-mcp-server
A local-first MCP server that lets any AI agent — Claude Desktop, Claude Code, a custom Anthropic SDK loop, or anything else that speaks the Model Context Protocol — query the Sui blockchain through its new data stack: gRPC, GraphQL, and the Archival Service.
Plug it into your agent and you can ask plain-English questions about Sui:
"What's happening on Sui mainnet right now?"
"Walk me through the recent activity for address 0x…"
"Fetch object 0x5 at version 100 — which endpoint had to answer?"
"What public functions does the sui_system package expose?"
The server handles transport selection, retention boundaries, schema introspection, and response shaping. The agent just answers the question.
What this actually is
The Model Context Protocol (MCP) is a standard way for AI agents to call external tools. An MCP server exposes a catalog of tools (think: REST endpoints with rich descriptions); an MCP client — usually an LLM-driven agent — picks which tools to call to satisfy a user's request.
This repo is an MCP server for Sui data. It runs locally as a Node subprocess, speaks MCP over stdio, and exposes 29 tools mapped to the new Sui APIs. The example agent at examples/agent.ts is a thin Anthropic-SDK loop that connects to the server, lets Claude pick tools, and runs the conversation. You can use that agent as-is, or swap in any other MCP client.
Related MCP server: sui-trader-mcp
Why this exists
Sui's JSON-RPC sunsets on 2026-07-31. The replacement is a three-layer data stack — gRPC (low-latency point reads), GraphQL RPC (relational reads), and the Archival Service (deep history) — that's well-shaped for production indexers and SDKs.
It's not yet shaped for agents. Agents want:
A small set of task-shaped tools that map to common questions ("balance of address X", "what happened in tx Y").
An escape hatch when the curated tools don't fit, with schema discovery so the agent can navigate without prior knowledge.
Auto-routing across endpoints so the agent doesn't need to know about retention boundaries.
Responses pre-shaped for an LLM context window — no
BigIntserialization errors, no rawUint8Arrays, no proto-style empty wrappers.
This server provides exactly that. It's a thin layer — the heavy lifting still happens on the Sui side — but the layer is what makes Sui usable from a one-shot LLM prompt instead of a multi-week SDK integration.
What you get
A hybrid surface combining curated intent tools with a schema-introspective dispatcher:
Category | Tools | What they're for |
Ledger reads (gRPC) |
| Single-entity lookups; defaults to live → archive auto-routing |
Live state (gRPC) |
| Address-level live state |
Move packages (gRPC) |
| Contract introspection |
Relational reads (GraphQL) |
| Cross-entity queries in one round-trip |
Streaming (gRPC) |
| Tail of chain — bounded window per call |
Execution (gRPC) |
| Dry-run always; submit only when explicitly enabled |
Introspection |
| "What can I do?" — feeds the dispatcher pattern |
Escape hatches |
| Raw passthrough when no curated tool fits |
Every response includes a routing trace — source, endpoint, network, latency — so both the agent and a human watching the terminal can see exactly which transport answered.
Quick start
Requires Node 22+.
git clone <this repo> sui-mcp-server
cd sui-mcp-server
npm install
npm run buildSanity check (no API key, no network):
node scripts/smoke.mjsYou should see 29 tools register and one offline call succeed.
Talk to it interactively (needs an Anthropic API key):
export ANTHROPIC_API_KEY=sk-ant-...
npm run agentYou'll get a sui[mainnet]> prompt. Try asking "What's the latest checkpoint?" and follow up with "and how does that compare to testnet?" — the conversation persists across turns, so Claude builds context. Use /network testnet to flip networks mid-session, /help for the full command list, and Ctrl-D to exit.
Example prompts to try
These exercise different paths through the server. Each one is the kind of thing an agent should be able to answer without the user knowing anything about gRPC vs GraphQL.
Tip-of-chain reads (gRPC + GraphQL relational):
"What's the latest checkpoint on Sui mainnet? Include the timestamp and network total transactions."
"Compare the reference gas prices on mainnet and testnet right now."
Address profiling (GraphQL — one query for many things):
"Give me a profile of address 0x… — balance, top owned objects, recent transactions."
Move package introspection:
"What public functions does the package at 0x3 (sui_system) expose? Pick one and show me its full signature."
Auto-routing across live and archive:
"Fetch object 0x5 at version 100 and tell me which endpoint had to answer." — Live full nodes typically don't retain versions that old; the trace will show the live attempt returning empty before the call falls back to the Archival Service.
Streaming + cadence:
"Stream 5 checkpoints and tell me the average time between them."
Simulation (safe — never touches live state):
"Simulate this BCS-encoded transaction and tell me whether it would succeed and how much gas it would burn." (Pass the bytes inline.)
When you ask follow-ups, Claude reuses what it already learned — no redundant tool calls.
Under the hood
The Sui data stack in 30 seconds
The new stack has three pieces, served behind public-good URLs:
gRPC fullnode (
fullnode.<network>.sui.io): the canonical low-latency reads. Five services —LedgerService(objects, transactions, checkpoints, epochs),StateService(live balances and owned objects),MovePackageService(contract introspection),SubscriptionService(server-streaming),TransactionExecutionService(submit + simulate).GraphQL RPC (
graphql.<network>.sui.io/graphql): an indexer-backed relational layer. Best for cross-entity queries — "address X's balance + owned objects + last 10 transactions" in one round-trip.Archival Service (
archive.<network>.sui.io): the sameLedgerServiceinterface as the live full node, but backed by long-retention storage. Use it when an object/transaction/checkpoint is older than the live full node still holds.
That last point is the architectural keystone: the Archival Service implements the same gRPC interface as the live full node. Same client code, same response shapes — only the URL differs. This server takes advantage of that symmetry to do live → archive auto-fallback transparently.
How a tool call flows
agent ──MCP─▶ sui-mcp-server ──┬─▶ SuiGrpcClient ──▶ live full node (gRPC)
│ ╰──▶ Archival Service (gRPC, fallback)
╰─▶ fetch() ────▶ GraphQL endpointEach curated tool wraps a service-specific call shape (the right read_mask, the right oneofKind variant, the right BigInt coercion) so the agent doesn't have to know proto-ts conventions. The escape-hatch tools (sui_grpc_call, sui_graphql_query) bypass the wrappers when a request doesn't fit a curated shape.
Auto-routing across live and archive
For Ledger reads, the default source: "auto" means: try the live full node first, inspect the response with a per-shape "is this empty?" predicate, fall back to archive if live errored or returned an empty payload. The trace records both attempts so it's clear what happened:
{
"source": "archival",
"label": "ledger.GetObject (after live: empty)",
"rationale": "...auto-route: live returned empty payload (likely past retention) → fell back to Archival Service",
"endpoint": "https://archive.mainnet.sui.io",
"latencyMs": 142
}Override with source: "live" or source: "archive" only when you have a specific reason (benchmarking, you already know the version is old, etc.).
Why GraphQL doesn't auto-fall-back to archive
Sui's GraphQL RPC is indexer-backed and already composes the Archival Service as one of its data sources. So an empty GraphQL result usually means the indexer doesn't have the entity at the requested level — running a parallel archive query rarely helps and adds noise.
The right escalation when GraphQL returns null for a specific id/digest/checkpoint is to drop to the gRPC LedgerService curated tool with source: "auto". That covers retention-boundary cases the indexer hasn't materialized, without doing redundant work for cases the indexer does cover. The tool descriptions and sui_describe_grpc_services notes both encode this policy so the agent inherits it for free.
LLM-friendly response shaping
Proto responses contain things JSON.stringify can't handle: BigInt for uint64/int64 fields, Uint8Array for digests and BCS bytes, and google.protobuf.Timestamp { seconds, nanos } blobs. The jsonSafe walker in src/util/json.ts produces a clean view: bigints become strings, byte arrays become 0x-hex, timestamps become { epochMs, iso }. The agent sees something it can read and quote back to the user without serializer errors.
Surviving SDK drift
@mysten/sui v2 is still iterating. Method paths drift between minor releases (client.ledgerService.getObject vs client.core.getObject vs client.getObject). The curated tools use a callFirst fallback chain so they keep working across releases; when something does break, error messages are tagged with hints about which arg shape the SDK is expecting. All SDK-specific knowledge is concentrated in one or two files, so adjustments are localized.
Using it locally
Interactive REPL (recommended)
npm run agent # mainnet, REPL
npm run agent -- --network testnet # testnet, REPL
npm run agent -- --max-rounds 60 # raise the per-turn tool-call budgetThe REPL preserves conversation context across turns, so follow-ups reuse what was already fetched instead of re-querying. Tool calls render as [tool 3/25] sui_chain_tip {...} on stderr — /trace off silences them.
One-shot CLI
npm run agent -- "What's the latest checkpoint on mainnet?"
npm run agent -- --network testnet "Show me a recent transaction digest"
npm run agent -- tip address tx recent # canned examples (one at a time)Slash commands inside the REPL
Command | What it does |
| Switch network mid-session — takes effect immediately, no restart |
| Adjust the per-turn tool-call budget (default 25) |
| Reset conversation history |
| Show conversation length and session settings |
| List the MCP tools the server exposed |
| Show or hide tool-call traces |
| Slash-command reference |
| Exit (Ctrl-D works too) |
For deeper testing recipes — auto-routing fallback verification, MCP Inspector usage, troubleshooting the cap-hit case — see TESTING.md.
Using it in production
From Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) and add:
{
"mcpServers": {
"sui": {
"command": "node",
"args": ["/absolute/path/to/sui-mcp-server/dist/server.js"],
"env": {
"SUI_MCP_DEFAULT_NETWORK": "mainnet"
}
}
}
}Restart Claude Desktop. The Sui tools appear in the tool palette automatically.
From Claude Code
Drop the same JSON into .claude/mcp.json at your project root.
As a hosted service
The current build speaks MCP over stdio — the canonical local-process transport. To deploy it as a remote service, wrap with one of the supported MCP HTTP/SSE transports. The server logic is transport-agnostic; the swap happens in two lines of src/server.ts. See the MCP TypeScript SDK README for the latest transport options.
For a multi-tenant deployment, run one server process per concurrent agent (cheap — it's a Node subprocess that reaches out to public-good Sui endpoints) and pass per-tenant config via env vars.
Configuration
All via env vars. Per-network overrides take precedence over global ones; both take precedence over the public-good defaults.
Variable | Default | Purpose |
|
| Network used when a tool call doesn't specify one |
| public-good URL | Per-network gRPC endpoint override |
| public-good URL | Per-network GraphQL endpoint override |
| public-good URL | Per-network Archival Service endpoint override |
| — | Global fall-throughs |
|
| Expose |
|
| Expose |
|
| Per-call cap on streamed frames |
|
| Per-call wall-clock cap on streaming |
Default endpoints:
Mainnet:
fullnode.mainnet.sui.io/graphql.mainnet.sui.io/graphql/archive.mainnet.sui.ioTestnet:
fullnode.testnet.sui.io/graphql.testnet.sui.io/graphql/archive.testnet.sui.io
Safety model
Reads are unrestricted. Anything LedgerService / StateService / MovePackageService / GraphQL exposes is fair game.
Simulation (sui_simulate_transaction) is always available — it's a dry-run, no state changes, no fees.
Execution is gated behind SUI_MCP_ENABLE_EXECUTION=true. Even when on, the server never accepts private keys — it only forwards opaque, pre-signed transaction bytes. Signing happens in the user's wallet/SDK; the MCP server is a transport, not a wallet.
Subscriptions are bounded per-call (max frames + max seconds) so a misbehaving agent can't tie up the connection. Tail the chain by calling repeatedly with the returned cursor.
Raw gRPC (sui_grpc_call) is read-only. It explicitly blocks executeTransaction and subscribeCheckpoints — those have their own dedicated tools with safety wrappers.
Project layout
src/
├── server.ts # MCP entry point — stdio transport + tool registration
├── config.ts # network + endpoint resolution + feature flags
├── clients/
│ ├── grpc.ts # SuiGrpcClient wrapper, callFirst, grpcAutoCall, looksEmpty
│ └── graphql.ts # plain fetch-based GraphQL client
├── util/
│ ├── json.ts # bigint + Uint8Array + Timestamp → JSON-safe walker
│ ├── format.ts # ok() / fail() — MCP content shape with routing trace
│ └── validate.ts # input validators (object_id, digest, address, etc.)
└── tools/
├── ledger.ts # gRPC LedgerService — auto-routed
├── state.ts # gRPC StateService
├── move_package.ts # gRPC MovePackageService
├── graphql.ts # GraphQL curated tools + escape hatch
├── subscription.ts # gRPC SubscriptionService — bounded window
├── execution.ts # Simulate (always) + Execute (gated)
├── grpc_raw.ts # sui_grpc_call escape hatch
└── introspect.ts # service catalog + endpoint listing
examples/
└── agent.ts # ~250-line interactive CLI agent
scripts/
└── smoke.mjs # offline sanity checkA few quirks the wrappers smooth over (learned the hard way):
SuiGrpcClientconstructor takes{ network, baseUrl }. Calling the URL fieldurlproduces an opaque error insideGrpcWebFetchTransport.makeUrl.Without an explicit
read_mask, gRPC responses contain only identifying digests. The curated tools pass sensible default paths.Method access drifts between SDK minors. The
callFirstfallback chain handles this transparently.Object versions are Lamport timestamps, not a +1 counter.
sui_object_history_stepencapsulates the canonicalpreviousTransaction → effects.changedObjects.inputVersionwalk.
Further reading
TESTING.md — five ways to drive the server, six prompts that exercise specific behaviors, full troubleshooting guide.
Sui gRPC fullnode protocol — the upstream spec.
Sui GraphQL docs — schema and examples.
sui-apis— the canonical proto definitions.Model Context Protocol — what MCP is and how to build clients.
License
Apache-2.0.
Available Tools
29 toolssui_address_overviewA
One-shot relational read for an address — balance + owned objects (first 12) + recent transactions (first 10). Replaces 4–5 separate gRPC calls. Use as the default 'tell me about this address' tool.
Inputs: address (required), network.
sui_batch_get_objectsA
Fetch up to 50 objects in one round-trip. Returns per-object results (each may succeed or fail individually). Prefer this over a loop of sui_get_object when you have a known list of ids.
Inputs: object_ids (required), source, network.
sui_batch_get_transactionsA
Fetch up to 50 transactions in one round-trip. Per-item errors do not fail the batch.
Inputs: digests (required), source, network.
sui_chain_tipA
Lightweight 'about this network' read — chain identifier, latest checkpoint, current epoch + reference gas price. One query.
Inputs: network.
sui_describe_grpc_servicesA
Return the catalog of gRPC services and methods this MCP server can reach (with which curated tool, if any, wraps each one). Use this when deciding whether to call a curated tool or fall back to sui_grpc_call.
Inputs: no named parameters.
sui_execute_transactionC
(disabled) Submit a pre-signed transaction. Set SUI_MCP_ENABLE_EXECUTION=true on the server to enable.
Inputs: no named parameters.
sui_get_balanceA
Get the aggregated coin balance for an address, optionally for a specific coin type (defaults to 0x2::sui::SUI).
Inputs: address (required), coin_type, network.
sui_get_checkpointA
Fetch a checkpoint by sequence number, digest, or 'latest'. Returns the checkpoint header, summary (timestamp, networkTotalTransactions), and digest. Defaults to 'auto' routing — live first, archive fallback. For latest=true the live node is always authoritative; auto still works (archive returns its latest as a fallback if live is unreachable).
Inputs: sequence_number, digest, latest, source, +1 more.
sui_get_coin_infoA
Get coin metadata (decimals, symbol, name, icon) for a coin type. Cacheable; metadata rarely changes.
Inputs: coin_type (required), network.
sui_get_datatypeA
Get a Move datatype (struct or enum) definition — its fields, abilities, and type parameters.
Inputs: package_id (required), module_name (required), datatype_name (required), network.
sui_get_epochA
Fetch metadata for an epoch — committee, system state, first/last checkpoint, reference gas price. Use epoch='current' for the live epoch.
Inputs: epoch (required), network.
sui_get_functionA
Get the signature of a specific Move entry/public function — type parameters, argument types, return types, visibility. Use this before calling sui_simulate_transaction or constructing a PTB.
Inputs: package_id (required), module_name (required), function_name (required), network.
sui_get_objectA
Fetch a Sui object's current state by object id. Returns the object's owner, type, version, digest, previous-transaction pointer, and Move contents (BCS). Use for any 'what is object 0x...' question — bypass GraphQL for single-object reads. By default routes 'auto': tries the live full node, falls back to the Archival Service if live has expired this version. The trace records the fallback chain.
Inputs: object_id (required), version, source, network.
sui_get_packageA
Get a Move package by id — its modules, ABI, dependencies, and on-chain bytecode pointer. The starting point for any 'what does this contract expose?' question.
Inputs: package_id (required), network.
sui_get_service_infoA
Probe a gRPC endpoint for its chain identifier, latest checkpoint, and the lowest checkpoint it still has. Useful for picking between live and archive when you don't know which side has the data you need.
Inputs: source, network.
sui_get_transactionA
Fetch a transaction by its base58 digest. Returns the transaction body, effects (status, gas summary, changed objects), events, and signatures. The right tool for 'what happened in tx '. Defaults to 'auto' routing — live first, falls back to archive on retention boundary.
Inputs: digest (required), source, network.
sui_graphql_introspectA
Introspect the Sui GraphQL schema. Returns the type system so an agent can construct a valid sui_graphql_query.
Inputs: type_name, network.
sui_graphql_queryA
Run an arbitrary GraphQL query against the Sui GraphQL endpoint. The escape hatch for the agentic dispatcher pattern: when no curated tool fits, the agent crafts its own query. Use sui_graphql_introspect first if you don't know the schema. NOTE: Sui's GraphQL RPC is indexer-backed and already composes the Archival Service under the hood, so an empty/null GraphQL result usually means the indexer doesn't have the entity at the requested level — running a parallel archive query is rarely useful. The right escalation when GraphQL returns null for a known id/digest/checkpoint is to drop to sui_get_object / sui_get_transaction / sui_get_checkpoint with source='auto' (the live→archive fallback covers retention boundary cases the indexer hasn't materialized).
Inputs: query (required), variables, network.
sui_grpc_callA
Escape hatch: call any READ method on the LedgerService / StateService / MovePackageService directly. Args are forwarded as-is to the @mysten/sui SuiGrpcClient. Pass read_mask_paths if you want fields populated. Use sui_describe_grpc_services first to discover what's available. ExecuteTransaction and SubscribeCheckpoints are blocked here — they have their own gated tools. For LedgerService methods, source='auto' (default) tries live then falls back to archive on retention boundary.
Inputs: service (required), method (required), args (required), read_mask_paths, +2 more.
sui_list_balancesB
List all coin-type balances held by an address. Paginated.
Inputs: address (required), page_size, page_token, network.
sui_list_dynamic_fieldsB
List dynamic fields attached to a parent object. Useful when crawling tables/bags/dynamic object fields.
Inputs: parent (required), page_size, page_token, network.
sui_list_endpointsA
Return the gRPC, GraphQL, and Archival URLs in use for a given network, after env-override resolution. Useful when deploying behind a self-hosted full node.
Inputs: network.
sui_list_owned_objectsA
List the objects an address owns, paginated. Each item carries object_id + version + type — fetch full bodies via sui_get_object or sui_batch_get_objects.
Inputs: address (required), page_size, page_token, network.
sui_list_package_versionsA
List historical versions of a Move package — the upgrade chain. Useful when an address points at an older snapshot of a contract.
Inputs: package_id (required), page_size, page_token, network.
sui_object_history_stepA
Walk one step backward through an object's history. Returns the prior valid version + the digest of the transaction that produced this version. Object versions are NOT a +1 monotonic counter — this tool encapsulates the canonical 'previousTransaction → effects.changedObjects.inputVersion' walk so agents don't re-implement it.
Inputs: object_id (required), network.
sui_recent_checkpointsA
Recent checkpoint feed with digests, timestamps, and per-checkpoint transaction counts.
Inputs: last, network.
sui_simulate_transactionA
Dry-run a transaction. Always safe — no state changes, no fees. Returns effects, command outputs, and a suggested_gas_price. Use this before any real execution to check that the tx will succeed and to size gas. Accepts BCS-encoded transaction bytes (base64).
Inputs: transaction_bcs_b64 (required), network.
sui_stream_checkpointsA
Subscribe to new checkpoints and return a window of up to 10 frames (or until 30s elapse, whichever comes first). Each frame carries the cursor + checkpoint summary. Call repeatedly to tail the chain — pass the last cursor back as 'after_cursor' for resumable reads.
Inputs: max_frames, max_seconds, after_cursor, read_mask_paths, +1 more.
sui_transaction_richA
Pull transaction effects, gas summary, balance changes, and the checkpoint pointer in one GraphQL round-trip — relational reads gRPC isn't shaped for.
Inputs: digest (required), network.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 29 tools
Each tool has a clearly distinct purpose, with no overlapping functionality. For example, sui_get_object and sui_batch_get_objects are separate for single vs batch, and sui_graphql_query and sui_grpc_call are differentiated as escape hatches with clear descriptions.
Most tools follow a consistent verb_noun pattern prefixed with 'sui_', such as sui_get_object, sui_list_owned_objects. However, a few like sui_transaction_rich and sui_address_overview deviate slightly, but overall the pattern is clear and predictable.
With 29 tools, the server covers a wide range of operations for the Sui blockchain. While somewhat large, each tool serves a specific need and the count is justified by the complexity of the domain, though it borders on being heavy.
The tool set provides comprehensive coverage of Sui operations, including object retrieval, transactions, checkpoints, epochs, packages, dynamic fields, balances, streaming, simulation, and escape hatches via GraphQL and gRPC. No obvious gaps exist for common use cases.
Maintenance
Related MCP Connectors
MCP server connecting AI agents to non-custodial staking data across 130+ networks.
MCP server for building and testing AI agents with multi-model experimentation and insights.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA lightweight, fast MCP server that provides onchain capabilities for the LLMs and Agents.37 npm255MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server designed for AI agents to perform optimal token swaps on the Sui blockchain.6MIT
- AlicenseNot gradedqualityFmaintenanceAn MCP server for the Sui blockchain that enables AI agents to manage accounts, execute token swaps, and perform smart contract development using the Sui CLI. It supports over 30 tools for DeFi operations, staking, and market data via Pyth price oracles.25 npm2MIT
- AlicenseAqualityDmaintenanceAn MCP server that powers AI agents with indexed blockchain data from The Graph.3MIT