Mantle Network MCP Server (mantle-mcp)
A highly optimized Model Context Protocol (MCP) server built with Python and FastMCP. This server exposes a suite of tools that enable agentic frameworks and LLM interfaces (like KinetiFi) to interact with the Mantle Network (Layer 2 on Ethereum) for querying native and ERC-20 balances, checking allowances, retrieving DEX swap quotes (V2 and V3 architectures), estimating L2 gas costs, and managing on-chain Real World Assets (RWA) and ERC-8004 Agent Identities/Reputations.
Features
- Asynchronous Architecture: Built from the ground up using
asyncioandweb3[async]to minimize latency and maximize performance when handling multiple requests. - Dynamic Token Resolution: Resolves token symbols (e.g.,
USDC,WETH) dynamically by checking a local registry first, then falling back to Blockscout Explorer APIs for both mainnet and testnet. - Uniswap V3 / Merchant Moe / Agni Finance Integration: Computes exact, real-time swap quotes (
quoteExactInputSingle) using standard Uniswap V3 QuoterV2 logic. - ERC-8004 Identity & Reputation: Implements the proposed ERC-8004 standard on Mantle to register agent ownership and verify reputation scores on-chain.
- RWA Yield Optimization: Integrates Mantle Staked Ether (
mETH) yield index queries and OndoUSDYtransaction generators. - Zero-Trust & Stateless: Exposes read-only queries and generates unsigned EVM transaction payloads (to, data, value). Never requests, handles, or stores private keys.
- Offline Test Suite: A robust and comprehensive test suite using
pytestandunittest.mockfor fully offline, fast, and deterministic verification of all L2 RPC and API interactions.
Repository Structure
mantle-mcp/
├── .env # Environment configurations for L2 RPC endpoints
├── README.md # Server documentation
├── requirements.txt # Project Python dependencies
├── server.py # Main entrypoint initializing FastMCP and registering tools
├── tools/ # Sub-modules implementing individual blockchain queries
│ ├── __init__.py # Web3 client initializer and network constant definitions
│ ├── balance.py # Native MNT balance lookup
│ ├── dex.py # V2 and V3 DEX swap quotes (Uniswap V2 Router & V3 QuoterV2)
│ ├── erc20.py # ERC-20 balanceOf and allowance query functions
│ ├── gas.py # L2 gas units and gas price estimation
│ ├── identity.py # ERC-8004 Agent Identity registry & Reputation metrics
│ ├── network.py # Network metadata and connection health checker
│ ├── rwa.py # Ondo USDY and mETH yield rate query & wrap tools
│ └── tokens.py # Dynamic token symbol-to-address resolution
└── tests/ # Deterministic async offline tests
├── test_dex.py # V2 & V3 Swap quote mocks & assertions
├── test_erc20.py # ERC-20 allowance and balance mocks
├── test_identity.py # ERC-8004 Identity & Reputation mock tests
├── test_rwa.py # mETH yields and USDY wrap payload mock tests
├── test_server.py # Native balance, gas, network info, and server endpoints
└── test_tokens.py # Local registry and API fallback tests
Prerequisites
Before setting up the project, ensure you have the following installed:
- Python 3.10+ (tested and verified on Python 3.14)
- Virtual Environment Tool (
venv) - MCP Host (e.g., Claude Desktop, Cursor, Roo-Code, or any custom client)
Installation & Setup
Follow these steps to set up the Mantle MCP server locally:
1. Clone & Navigate to Directory
cd /home/tmalone1250/KinetiFi_local/mantle-mcp
2. Create and Activate Virtual Environment
python3 -m venv .venv
source .venv/bin/activate
3. Install Dependencies
pip install --upgrade pip
pip install -r requirements.txt
Configuration
Environment variables are managed using a .env file in the project root. Create or update .env as follows:
# Mantle Network MCP Server Environment Variables
# Leave blank to use the official public RPC endpoints, or override them below.
# Mainnet RPC Endpoint (Default: https://rpc.mantle.xyz)
MANTLE_RPC_URL=
# Sepolia Testnet RPC Endpoint (Default: https://rpc.sepolia.mantle.xyz)
MANTLE_SEPOLIA_RPC_URL=
Fallback Network Constants
If the environment variables are left blank, the server automatically falls back to these defaults:
| Parameter | Mainnet | Testnet (Sepolia) |
|---|---|---|
| RPC URL | https://rpc.mantle.xyz |
https://rpc.sepolia.mantle.xyz |
| Block Explorer | https://explorer.mantle.xyz |
https://explorer.sepolia.mantle.xyz |
| Chain ID | 5000 |
5003 |
| Native Currency | MNT |
MNT |
Running the Server
You can run the Mantle MCP server in two modes:
Development Mode (with Live Reload)
To inspect tools, test outputs, and log streams via a graphical web interface, run:
fastmcp dev server.py
Production Mode
Run the server to handle MCP JSON-RPC standard input/output streams:
python server.py
Integrating with MCP Clients
To link mantle-mcp to your favorite LLM assistant client, register it under the custom MCP servers config file:
For Claude Desktop
Add this to your Claude Desktop configuration (typically at ~/.config/Claude/claude_desktop_config.json):
{
"mcpServers": {
"mantle-mcp": {
"command": "/home/tmalone1250/KinetiFi_local/mantle-mcp/.venv/bin/python",
"args": [
"/home/tmalone1250/KinetiFi_local/mantle-mcp/server.py"
],
"env": {
"MANTLE_RPC_URL": "https://rpc.mantle.xyz",
"MANTLE_SEPOLIA_RPC_URL": "https://rpc.sepolia.mantle.xyz"
}
}
}
}
MCP Tool Reference
mantle-mcp exposes 13 native blockchain tools to clients:
1. get_native_balance
Retrieves the native MNT balance of an address on the Mantle Network.
- Arguments:
address(string, required): The EVM address to query.network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
strrepresenting a human-readable balance (e.g.,"12.3450 MNT").
2. get_erc20_balance
Retrieves the ERC-20 token balance for a specific wallet address. Automatically resolves token symbols to addresses and formats the balance using the token's decimals.
- Arguments:
wallet_address(string, required): The EVM wallet address to query.token_symbol(string, required): The token symbol (e.g.,'USDC','WETH','USDT').network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "wallet": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "token": "USDC", "balance": 150.5, "network": "testnet" }
3. get_erc20_allowance
Retrieves the ERC-20 token allowance granted by a wallet to a specific spender.
- Arguments:
wallet_address(string, required): The EVM wallet address that owns the tokens.spender_address(string, required): The EVM address authorized to spend the tokens.token_symbol(string, required): The token symbol (e.g.,'USDC','WETH').network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "wallet": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "spender": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "token": "USDC", "allowance": 500.0, "network": "testnet" }
4. get_swap_quote (Uniswap V2)
Gets a swap quote (expected output) for a given trade pair on the FusionX DEX router using Uniswap V2 Router logic.
- Arguments:
sell_symbol(string, required): The token symbol to sell (e.g.,'USDC').buy_symbol(string, required): The token symbol to buy (e.g.,'WETH').amount_in(float, required): The human-readable amount ofsell_symbolto swap.network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "sell_token": "USDC", "buy_token": "WETH", "amount_in": 100.0, "expected_output": 0.05, "network": "testnet" }
5. get_dex_quote (Uniswap V3)
Gets a V3 swap quote (exact input) from specific DEXes like merchant_moe or agni_finance on Mantle.
- Arguments:
dex_name(string, required): The DEX name to query ('merchant_moe'or'agni_finance').token_in(string, required): EVM contract address of the incoming token.token_out(string, required): EVM contract address of the outgoing token.amount_in_wei(integer, required): The amount of input token, in raw wei.fee_tier(integer, optional): The pool fee tier (e.g.,3000representing0.30%). Defaults to3000.network(string, optional): The network to query ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "dex": "merchant_moe", "amount_out_wei": 50000000000000000, "estimated_gas_from_quoter": 150000, "status": "success" }
6. estimate_l2_gas
Estimates the gas units and total cost required to execute a transaction on Mantle L2.
- Arguments:
to_address(string, required): The target EVM address of the recipient or contract.data(string, optional): The hex data payload of the transaction. Defaults to'0x'.value_wei(integer, optional): The native currency value to send, in wei. Defaults to0.network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "success": true, "network": "testnet", "estimated_gas_units": 21000, "gas_price_gwei": 1.0, "estimated_cost_mnt": 0.000021, "estimated_cost_wei": 21000000000000 }
7. get_token_address
Dynamically resolves a token symbol to its smart contract address on Mantle. If the token is not cached in the local registry, it falls back to querying the Blockscout explorer API.
- Arguments:
symbol(string, required): The token symbol (e.g.,'USDC','WETH','WMNT').network(string, optional): The network to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "symbol": "USDC", "address": "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", "network": "mainnet", "source": "local_registry" }
8. get_mantle_network_info
Returns the network metadata and connection parameters (including connectivity check) for the requested Mantle Network.
- Arguments:
network(string, optional): The network name to query ('testnet'or'mainnet'). Defaults to'testnet'.
- Response Format:
{ "success": true, "network": "testnet", "chain_id": 5003, "rpc_url": "https://rpc.sepolia.mantle.xyz", "explorer_url": "https://explorer.sepolia.mantle.xyz", "native_currency": "MNT", "rpc_connection_active": true }
9. fetch_meth_yield
Fetches the current mETH (Mantle Staked Ether) yield exchange rate from the on-chain contract.
- Arguments:
network(string, optional): The network name to query ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "asset": "mETH", "exchange_rate_raw": 1052000000000000000, "exchange_rate_formatted": 1.052, "status": "success" }
10. prepare_usdy_wrap
Generates an unsigned transaction payload to wrap USDC into Ondo USDY.
- Arguments:
amount_wei(integer, required): The raw amount of USDC in wei to wrap.usdy_address(string, optional): The USDY target wrap contract address. Defaults to Ondo USDY Mainnet.network(string, optional): The network ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "chainId": 5000, "to": "0x5bE26527e817998A7206475496fDE1E68957c5A6", "data": "0xwrap...", "value": "0x0", "readModel": { "protocol": "Ondo USDY", "method": "wrap(uint256)", "params": [1000000] } }
11. verify_erc8004_identity
Checks the owner address of an ERC-8004 Agent Identity on the Mantle Network.
- Arguments:
identity_id(integer, required): The ID of the agent identity NFT to query.network(string, optional): The network to query ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "identity_id": 42, "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "network": "mainnet", "status": "registered" }
12. query_erc8004_reputation
Queries an agent's on-chain trust reputation score on the Mantle Network.
- Arguments:
identity_id(integer, required): The ID of the agent identity NFT to query.network(string, optional): The network to query ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "identity_id": 42, "score": 95, "total_updates": 5, "network": "mainnet" }
13. prepare_agent_registration
Returns an unsigned payload to register and mint an ERC-8004 Identity NFT on the Mantle Network.
- Arguments:
owner_address(string, required): The EVM address that will own the agent NFT.metadata_uri(string, required): The IPFS/HTTPS metadata link for the agent identity.network(string, optional): The network to query ('mainnet'or'testnet'). Defaults to'mainnet'.
- Response Format:
{ "chainId": 5000, "to": "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432", "data": "0xregister...", "value": "0x0", "readModel": { "protocol": "ERC-8004 Identity", "method": "register(address,string)", "params": ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "ipfs://QmMock"] } }
Token Registry Details
The server includes a built-in fast local registry for common assets. If a token is queried that does not exist in the local registry, the server issues an asynchronous HTTP query to the Blockscout Explorer Search API to resolve the address dynamically.
Local Registry Addresses
Mainnet
- MNT:
native - WMNT:
0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8 - WETH:
0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111 - USDC:
0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9 - USDT:
0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE
Testnet (Sepolia)
- MNT:
native - WMNT:
0x1404c04fE52478546D869Ff94119DF37eAA6e1c4 - WETH:
0x7383D62D50E7dF82c6114dDF603952a2DE549B8a - USDC:
0x2D4a161f36402E8d4234baC5aC6f12e873aC1A62 - USDT:
0xC216f40A3Ceb03F4f03936F76E296e8346cbDE6e
Testing
The project has a 100% mocked, deterministic test suite, meaning you can run all tests offline without needing live RPC access or internet connectivity.
Run all tests using the virtual environment pytest executable:
.venv/bin/pytest -v
Security & Architectural Standards
- Explicit Type Hints: Every function signature specifies types for input parameters and return shapes.
- Robust Error Handling: System calls catch RPC connection failures, contract reverts, and invalid address validation errors, returning structured error messages rather than crashing.
- Zero State Modification: The MCP server tools are read-only (
viewand gas estimation). They do not store private keys, hold funds, or initiate state-changing transactions directly, rendering the server highly secure.