Polygon Blockchain Integration
STDIOMCP server providing seamless integration with Polygon blockchain for AI assistants.
MCP server providing seamless integration with Polygon blockchain for AI assistants.
A Model Context Protocol (MCP) server that provides seamless integration with the Polygon blockchain network. This server enables AI assistants to interact with Polygon through a standardized interface, offering comprehensive tools for wallet operations, smart contract deployment, L2 bridging, DeFi interactions, and transaction simulations.
Polygon is a Layer 2 scaling solution for Ethereum that provides faster and cheaper transactions while maintaining Ethereum's security. This MCP server allows AI assistants to interact with the Polygon network, enabling a wide range of blockchain operations through a simple, standardized interface.
The server acts as a bridge between AI systems and the Polygon blockchain, handling the complexities of blockchain interactions and providing a clean, easy-to-use API for common operations.
┌─────────────┐ ┌───────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ AI System ├─────┤ Polygon MCP ├─────┤ Polygon Chain │
│ │ │ Server │ │ │
└─────────────┘ └───────────────┘ └─────────────────┘
cd polygonmcp npm install
.env
file with the following variables:# Network RPC endpoints POLYGON_MAINNET_RPC=https://polygon-rpc.com POLYGON_AMOY_RPC=https://rpc-amoy.polygon.technology ETHEREUM_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_KEY # Sepolia for Amoy's L1 # API Keys POLYGONSCAN_API_KEY=YOUR_EXPLORER_API_KEY # Use OKLink API key for Amoy # Wallet (IMPORTANT: Use secure key management in production) PRIVATE_KEY=your_private_key_here DEFAULT_NETWORK=amoy # Use 'amoy' for testnet # DeFi Configuration (Optional) DEFAULT_SLIPPAGE=0.5 DEFAULT_DEADLINE_MINUTES=20
Start the server:
npm start
For development with auto-restart:
npm run dev
Check your wallet balance:
import { PolygonMCPServer } from './polygon-mcp.js'; const server = new PolygonMCPServer(); async function checkBalance() { // Wallet is connected automatically on server start if PRIVATE_KEY is in .env // await server.connectWallet(process.env.PRIVATE_KEY); const balances = await server.listBalances(); console.log('Wallet balances:', balances); } checkBalance().catch(console.error);
Get testnet POL (Amoy testnet only):
async function getTestPol() { // Wallet is connected automatically on server start if PRIVATE_KEY is in .env // await server.connectWallet(process.env.PRIVATE_KEY); const result = await server.getTestnetPol(); console.log('Faucet result:', result); }
Simulate a transaction:
// Wallet is connected automatically on server start if PRIVATE_KEY is in .env async function simulateTransaction() { const result = await server.simulateTransaction({ to: '0x1234...', // Recipient address value: '0.01', // Amount in MATIC (or native token) }); console.log('Simulation result:', result); }
Tool | Description | Example |
---|---|---|
get-address | Retrieve the current wallet address | const address = await server.getAddress() |
get-testnet-pol | Request testnet POL from a faucet (Amoy testnet only) | await server.getTestnetPol() |
list-balances | List token balances for the connected wallet | const balances = await server.listBalances() |
transfer-funds | Transfer POL or ERC20 tokens to another address | await server.transferFunds('0x1234...', '0.1', 'MATIC') |
The wallet manager provides:
Tool | Description | Example |
---|---|---|
deploy-contract | Deploy a smart contract to Polygon | await server.deployContract(name, code, args) |
verify-contract | Verify a deployed contract on Polygonscan | await server.verifyContract(address, name, code, args) |
list-contract-templates | List available contract templates | const templates = await server.listContractTemplates() |
Supported contract types:
Tool | Description | Example |
---|---|---|
deposit-eth | Deposit ETH from Ethereum to Polygon | await server.mcpServer.callTool('deposit-eth', { amount: '0.1' }) |
withdraw-eth | Withdraw ETH/POL from Polygon to Ethereum | await server.mcpServer.callTool('withdraw-eth', { amount: '0.1' }) |
deposit-token | Deposit ERC20 from Ethereum to Polygon | await server.mcpServer.callTool('deposit-token', { token: 'USDC', amount: '100' }) |
withdraw-token | Withdraw ERC20 from Polygon to Ethereum | await server.mcpServer.callTool('withdraw-token', { token: 'USDC', amount: '100' }) |
check-bridge-status | Check the status of a bridge transaction (Not yet implemented as tool) | N/A |
Features:
PolygonBridge
class.MaticPOSClient
usage within bridge-operations.js
.MaticPOSClient
).Note: The current implementation uses a mock version of MaticPOSClient due to ESM compatibility issues. Bridge operations may not function correctly until a proper ESM-compatible implementation is created.
Tool | Description | Example |
---|---|---|
swap-tokens | Swap tokens using QuickSwap | await server.swapTokens('MATIC', 'USDC', '10') |
get-swap-quote | Get a price quote for a token swap | const quote = await server.getSwapQuote('MATIC', 'USDC', '10') |
add-liquidity | Add liquidity to a QuickSwap pool | await server.addLiquidity('MATIC', 'USDC', '10', '20') |
Tool | Description | Example |
---|---|---|
uniswapV3SwapSingle | Execute single-hop swaps | await server.uniswapV3SwapSingle(tokenIn, tokenOut, amount, fee) |
uniswapV3SwapMulti | Execute multi-hop swaps | await server.uniswapV3SwapMulti(path, amounts) |
getUniswapV3QuoteSingle | Get quotes for single-hop swaps | const quote = await server.getUniswapV3QuoteSingle(tokenIn, tokenOut, amount, fee) |
getUniswapV3QuoteMulti | Get quotes for multi-hop swaps | const quote = await server.getUniswapV3QuoteMulti(path, amount) |
Tool | Description | Example |
---|---|---|
getPolymarketInfo | Get market information | const info = await server.getPolymarketInfo(marketId) |
placePolymarketBet | Place bets by buying position tokens | await server.placePolymarketBet(marketId, outcome, amount) |
getPolymarketPositions | Get user positions for a market | const positions = await server.getPolymarketPositions(marketId) |
Tool | Description | Example |
---|---|---|
simulate-transaction | Simulate a transaction to preview its effects | const result = await server.simulateTransaction(txParams) |
estimate-gas | Estimate gas for a transaction | const gas = await server.estimateGas(txParams) |
Features:
Tool | Description | Example |
---|---|---|
get-gas-price | Get current gas prices on Polygon | const price = await server.getGasPrice() |
switch-network | Switch between Polygon Mainnet and Amoy Testnet | await server.switchNetwork('mainnet') |
The Polygon MCP Server is built with a modular architecture that separates concerns and promotes maintainability:
flowchart TD MCPServer["Polygon MCP Server (polygon-mcp.js)"] subgraph Modules BridgeOps["Bridge Operations (bridge-operations.js)"] ContractOps["Contract Templates (contract-templates.js)"] DeFiOps["DeFi Interactions (defi-interactions.js)"] SimOps["Transaction Simulator (transaction-simulation.js)"] end subgraph Common ["Common Utilities (common/)"] WalletManager["Wallet Manager (Singleton)"] ConfigManager["Configuration Manager"] Utils["Utility Functions (utils.js)"] Constants["Constants"] Logger["Logger (logger.js)"] Errors["Error Handling (errors.js)"] Validation["Validation (validation.js)"] end MCPServer -- instantiates/uses --> Modules MCPServer -- uses --> Common Modules -- use --> Common
polygon-mcp.js
): Main entry point, handles MCP communication, instantiates modules, registers tools, delegates calls.common/
):
getConfig
).resolveTokenAddress
.bridge-operations.js
): Encapsulates MaticPOSClient
and bridge logic.contract-templates.js
): Handles contract compilation, deployment from templates.defi-interactions.js
): Interfaces with DEXs (QuickSwap, Uniswap), Polymarket.transaction-simulation.js
): Simulates transactions using eth_call
.get-address
Gets the address of the connected wallet.
Returns: JSON string { "address": "0x..." }
list-balances
Lists native and known token balances for the connected wallet (or specified address).
Parameters (Optional):
address
(string): Address to check (defaults to connected wallet)Returns: JSON string { "address": "...", "nativeBalance": "...", "tokens": { "USDC": "...", ... } }
transfer-funds
Transfers native token (POL) or ERC20 tokens to another address.
Parameters:
to
(string): Recipient addressamount
(string): Amount to transfertoken
(string, optional): Token symbol or address (omit for native POL)Returns: JSON string { "success": true, "txHash": "0x...", ... }
list-contract-templates
Lists available contract templates.
Returns: JSON string [{ "id": "erc20", "name": "...", ... }, ...]
deploy-contract
Deploys a contract from a template.
Parameters:
templateId
(string): ID of the template (e.g., 'erc20', 'nft')params
(object): Parameters specific to the template (e.g., { "name": "MyToken", ... }
)constructorArgs
(Array, optional): Arguments for the contract constructorReturns: JSON string { "address": "0x...", "transactionHash": "0x...", ... }
verify-contract
(Not currently exposed as an MCP tool)Verifies a contract on Polygonscan.
Parameters:
address
(string): Contract addressname
(string): Contract namecode
(string): Contract source codeconstructorArgs
(Array): Constructor argumentsReturns: Object - Verification result (if implemented as tool)
deposit-eth
Deposits ETH from Ethereum to Polygon.
Parameters:
amount
(string): Amount of ETH to depositReturns: JSON string { "txHash": "0x...", "status": "pending" }
withdraw-eth
Withdraws the native token (POL) from Polygon to Ethereum. Note: Polygon has rebranded from MATIC to POL on both mainnet and testnet.
Parameters:
amount
(string): Amount of native token (POL) to withdrawReturns: JSON string { "txHash": "0x...", "status": "pending" }
deposit-token
Deposits an ERC20 token from Ethereum to Polygon.
Parameters:
token
(string): Token symbol or addressamount
(string): Amount to depositReturns: JSON string { "txHash": "0x...", "status": "pending" }
withdraw-token
Withdraws an ERC20 token from Polygon to Ethereum.
Parameters:
token
(string): Token symbol or addressamount
(string): Amount to withdrawReturns: JSON string { "txHash": "0x...", "status": "pending" }
(Note: check-bridge-status
is implemented in PolygonBridge
but not exposed as an MCP tool yet)
// Example: Swap tokens and then bridge to Ethereum (Conceptual using MCP tools) async function swapAndBridge() { // Assume server is running and wallet connected via env/config // Swap MATIC to USDC (using a hypothetical swap tool - needs implementation) // const swapResult = await server.mcpServer.callTool('swap-tokens', { fromToken: 'MATIC', toToken: 'USDC', amount: '10' }); // console.log('Swap result:', swapResult); // await server.provider.waitForTransaction(swapResult.content[0].text.txHash); // Wait for swap tx // Bridge USDC to Ethereum const bridgeResult = await server.mcpServer.callTool('withdraw-token', { token: 'USDC', amount: '10' }); console.log('Bridge result:', bridgeResult); }
// Deploy a custom ERC20 token using templates (Conceptual using MCP tools) async function deployCustomToken() { // Assume server is running and wallet connected via env/config // Get the ERC20 template info (optional step) // const templates = await server.mcpServer.callTool('list-contract-templates', {}); // console.log(templates); // Define parameters const templateId = 'erc20'; const params = { name: 'MyCustomToken' }; // Name is used in template processing const constructorArgs = ['MyCustomToken', 'MCT', '1000000000000000000000000']; // Name, Symbol, InitialSupply (in wei) // Deploy the contract const deployResult = await server.mcpServer.callTool('deploy-contract', { templateId, params, constructorArgs }); const deployData = JSON.parse(deployResult.content[0].text); console.log('Contract deployed at:', deployData.address); // Verification would need the source code, which isn't directly returned by deploy-contract // Verification might need a separate tool or manual process. } const customizedCode = erc20Template.code .replace('{{name}}', 'MyCustomToken') .replace('initialSupply * 10 ** decimals()', '1000000 * 10 ** 18'); // Deploy the contract const result = await server.deployContract( 'MyCustomToken', customizedCode, ['MyCustomToken', 'MCT', 1000000] );
// Simulate a transaction before executing it (Conceptual using MCP tools) async function safeTransfer() { // Assume server is running and wallet connected via env/config const txParams = { to: '0x1234...', value: '1000000000000000000', // 1 POL in wei // data: '0x' // Optional data }; // Simulate first const simResult = await server.mcpServer.callTool('simulate-transaction', { transaction: txParams }); const simulation = JSON.parse(simResult.content[0].text); // Check for issues if (!simulation.success) { console.error('Transaction would fail:', simulation.errorMessage); return; } // Check gas costs console.log('Estimated gas cost:', simulation.gasCost.ether, 'MATIC'); // Execute if simulation was successful (using transfer-funds tool) const transferResult = await server.mcpServer.callTool('transfer-funds', { to: txParams.to, amount: '1.0' // Amount in POL for the tool }); console.log('Transaction sent:', transferResult); }
Important: The current implementation uses a mock version of MaticPOSClient due to ESM compatibility issues. Bridge operations (deposit/withdraw) may not function correctly until a proper ESM-compatible implementation is created.
Ensure the PRIVATE_KEY
is correctly set in the .env
file or MCP server configuration, as the wallet connects automatically on server start if the key is provided. Manual connectWallet
calls are no longer the primary mechanism.
If you're experiencing RPC connection issues, try:
.env
fileFor operations that require gas fees, ensure your wallet has enough of the native token (POL):
const balances = await server.listBalances(); // Check native token balance (POL) const nativeToken = 'POL'; console.log(`${nativeToken} balance:`, balances.nativeBalance);
Use the transaction simulator to diagnose issues before sending:
const simulation = await server.simulateTransaction(tx); if (!simulation.success) { console.error('Transaction would fail:', simulation.errorMessage); }
Enable debug logging by setting the environment variable:
DEBUG=polygon-mcp:*
Contributions are welcome! Here's how you can contribute:
git checkout -b feature/my-feature
git commit -am 'Add my feature'
git push origin feature/my-feature
npm install
.env.test
file with test credentialsnpm test
npm run lint
This server handles private keys and sensitive blockchain operations. For production use:
To use this server with Claude or other MCP-compatible systems, add it to your MCP settings configuration file:
For Cursor/Claude Dev:
{ "mcpServers": { "polygon": { "command": "node", "args": ["path/to/polygon-mcp.js"], "env": { "POLYGON_MAINNET_RPC": "https://polygon-rpc.com", "POLYGON_AMOY_RPC": "https://rpc-amoy.polygon.technology", "ETHEREUM_RPC_URL": "https://eth-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_KEY", "POLYGONSCAN_API_KEY": "YOUR_EXPLORER_API_KEY", "PRIVATE_KEY": "your_private_key_here", "DEFAULT_NETWORK": "amoy", "DEFAULT_SLIPPAGE": "0.5", "DEFAULT_DEADLINE_MINUTES": "20" }, "disabled": false, "autoApprove": [] } } }
polygon-mcp.js
- Main server implementationbridge-operations.js
- L2 bridge operationscontract-templates.js
- Contract deployment templatesdefi-interactions.js
- DeFi protocol interactionstransaction-simulation.js
- Transaction simulation logic.logger.js
- Structured logging utility.errors.js
- Custom error classes and helpers.validation.js
- Input validation helpers (potentially underutilized).common/
- Shared utilities and constants:
config-manager.js
- Centralized configuration loading (getConfig
).constants.js
- Shared ABIs, addresses.wallet-manager.js
- Singleton wallet manager.utils.js
- Centralized utility functions (e.g., resolveTokenAddress
).This project is licensed under the MIT License - see the LICENSE file for details.