#
tokens: 3500/50000 4/4 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── index.js
├── LICENSE
├── package-lock.json
├── package.json
└── README.md
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | npm-debug.log
 4 | yarn-debug.log
 5 | yarn-error.log
 6 | 
 7 | # Environment variables
 8 | .env
 9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 | 
14 | # Build outputs
15 | dist/
16 | build/
17 | 
18 | # IDE and editor files
19 | .idea/
20 | .vscode/
21 | *.swp
22 | *.swo
23 | .DS_Store
24 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Ethereum RPC MCP Server
  2 | 
  3 | A Model Context Protocol (MCP) server for interacting with Ethereum blockchain.
  4 | 
  5 | ## Overview
  6 | 
  7 | This MCP server provides tools to query Ethereum blockchain data through standard JSON-RPC methods. It enables AI assistants and applications to interact with the Ethereum blockchain through a standardized protocol.
  8 | 
  9 | ## Features
 10 | 
 11 | This MCP server provides three key Ethereum RPC methods as tools:
 12 | 
 13 | - **eth_getCode**: Retrieve the code at a specific Ethereum address
 14 | - **eth_gasPrice**: Get the current gas price on the Ethereum network
 15 | - **eth_getBalance**: Check the balance of an Ethereum account
 16 | 
 17 | Note: More are coming
 18 | 
 19 | ## Usage
 20 | 
 21 | ### Adding to Cursor
 22 | 
 23 | To add this MCP to Cursor:
 24 | 
 25 | 1. First, clone this repository:
 26 |    ```bash
 27 |    git clone https://github.com/yourusername/eth-mpc.git
 28 |    ```
 29 |    
 30 | 2. Go to Cursor settings → MCP → Add new MCP server
 31 | 3. Enter a name (e.g., "eth-mcp")
 32 | 4. Select "command" as the type
 33 | 5. Input the full path to the script:
 34 |    ```
 35 |    node /path/to/eth-mpc/index.js
 36 |    ```
 37 | 
 38 | ![Adding Ethereum MCP to Cursor](image.png)
 39 | 
 40 | 6. Click "Add" to enable the server
 41 | 
 42 | Once added, the Ethereum RPC tools will be available to use within Cursor.
 43 | 
 44 | 
 45 | The server uses stdio transport, making it compatible with MCP clients like Claude Desktop, Cursor, and others.
 46 | 
 47 | ## Testing with MCP Inspector
 48 | 
 49 | The MCP Inspector is a development tool for testing and debugging MCP servers. It provides an interactive interface to test your MCP server's functionality without needing a full AI client.
 50 | 
 51 | ### Running the Inspector
 52 | 
 53 | To test your Ethereum RPC MCP server with the Inspector:
 54 | 
 55 | To run the Inspector:
 56 |    ```bash
 57 |    npx @modelcontextprotocol/inspector
 58 |    ```
 59 | 
 60 | 2. Input the command and path
 61 | 
 62 | 3. The Inspector will connect to your running MCP server and display available tools.
 63 | 
 64 | ### Testing Tools with Inspector
 65 | 
 66 | The Inspector allows you to:
 67 | 
 68 | - View available tools and their descriptions
 69 | - Test each tool with different parameters
 70 | - See the responses in a structured format
 71 | - Debug any issues with your MCP server implementation
 72 | 
 73 | For example, to test the `eth_getBalance` tool:
 74 | 1. Select the tool in the Inspector interface
 75 | 2. Enter a valid Ethereum address (e.g., `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` - Vitalik's address)
 76 | 3. Use the default block parameter (`latest`)
 77 | 4. Submit the request and view the response
 78 | 
 79 | 
 80 | ## Integration with MCP Clients
 81 | 
 82 | This MCP server can be integrated with any MCP-compatible client, including:
 83 | 
 84 | - Claude Desktop 
 85 | - Claude Code
 86 | - Cursor (instructions above)
 87 | - Cline
 88 | - Other MCP-compatible applications
 89 | 
 90 | When integrated, the client application can use the tools provided by this server to query Ethereum blockchain data directly.
 91 | 
 92 | ## Understanding MCP
 93 | 
 94 | Model Context Protocol (MCP) is an open standard that allows AI models to interact with various tools and services. It provides a standardized way for developers to expose APIs, data sources, and functionality to AI assistants.
 95 | 
 96 | ### Learn More About MCP
 97 | 
 98 | MCP servers like this one form part of an ecosystem that allows AI assistants to perform complex tasks across multiple services without requiring custom integration for each service.
 99 | 
100 | 📚 **Official Documentation**: [Model Context Protocol Overview](https://modelcontextprotocol.io/sdk/java/mcp-overview)
101 | 
102 | ## License
103 | 
104 | MIT
105 | 
106 | ## Contributing
107 | 
108 | Contributions are welcome! Please feel free to submit a Pull Request.
109 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "eth-mcp",
 3 |   "version": "1.0.0",
 4 |   "description": "an mcp to interact with the evm",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "author": "",
10 |   "license": "MIT",
11 |   "dependencies": {
12 |     "@modelcontextprotocol/sdk": "^1.6.1",
13 |     "axios": "^1.8.1",
14 |     "zod": "^3.24.2"
15 |   }
16 | }
17 | 
```

--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | const axios = require('axios');
  2 | const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
  3 | const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
  4 | const { z } = require('zod');
  5 | 
  6 | // Redirect console.log to stderr to avoid breaking the MCP protocol
  7 | const originalConsoleLog = console.log;
  8 | console.log = function() {
  9 |   console.error.apply(console, arguments);
 10 | };
 11 | 
 12 | // Ethereum RPC URL
 13 | const ETH_RPC_URL = 'https://eth.llamarpc.com';
 14 | 
 15 | // Initialize the MCP server
 16 | const server = new McpServer({
 17 |   name: 'ethereum-rpc',
 18 |   version: '1.0.0'
 19 | });
 20 | 
 21 | // Define prompts for common Ethereum interactions
 22 | server.prompt(
 23 |   'check-contract',
 24 |   {
 25 |     address: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('The Ethereum address to check')
 26 |   },
 27 |   ({ address }) => ({
 28 |     messages: [
 29 |       {
 30 |         role: 'user',
 31 |         content: {
 32 |           type: 'text',
 33 |           text: `Please analyze the contract at address ${address}:
 34 | 1. First, get the contract code
 35 | 2. Check if it's a contract or regular address
 36 | 3. If it's a contract, help me understand what type of contract it might be based on the code`
 37 |         }
 38 |       }
 39 |     ]
 40 |   })
 41 | );
 42 | 
 43 | server.prompt(
 44 |   'check-wallet',
 45 |   {
 46 |     address: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('The Ethereum address to check')
 47 |   },
 48 |   ({ address }) => ({
 49 |     messages: [
 50 |       {
 51 |         role: 'user',
 52 |         content: {
 53 |           type: 'text',
 54 |           text: `Please analyze the wallet at address ${address}:
 55 | 1. Get the current balance
 56 | 2. Format the balance in both Wei and ETH
 57 | 3. Provide context about whether this is a significant amount`
 58 |         }
 59 |       }
 60 |     ]
 61 |   })
 62 | );
 63 | 
 64 | server.prompt(
 65 |   'gas-analysis',
 66 |   {},
 67 |   () => ({
 68 |     messages: [
 69 |       {
 70 |         role: 'user',
 71 |         content: {
 72 |           type: 'text',
 73 |           text: `Please analyze the current gas situation:
 74 | 1. Get the current gas price
 75 | 2. Convert it to Gwei for readability
 76 | 3. Suggest whether this is a good time for transactions based on historical averages`
 77 |         }
 78 |       }
 79 |     ]
 80 |   })
 81 | );
 82 | 
 83 | // Helper function to make RPC calls
 84 | async function makeRpcCall(method, params = []) {
 85 |   try {
 86 |     const response = await axios.post(ETH_RPC_URL, {
 87 |       jsonrpc: '2.0',
 88 |       id: 1,
 89 |       method,
 90 |       params
 91 |     });
 92 | 
 93 |     if (response.data.error) {
 94 |       throw new Error(`RPC Error: ${response.data.error.message}`);
 95 |     }
 96 | 
 97 |     return response.data.result;
 98 |   } catch (error) {
 99 |     console.error(`Error making RPC call to ${method}:`, error.message);
100 |     throw error;
101 |   }
102 | }
103 | 
104 | // Tool 1: eth_getCode - Gets the code at a specific address
105 | server.tool(
106 |   'eth_getCode',
107 |   'Retrieves the code at a given Ethereum address',
108 |   {
109 |     address: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('The Ethereum address to get code from'),
110 |     blockParameter: z.string().default('latest').describe('Block parameter (default: "latest")')
111 |   },
112 |   async (args) => {
113 |     try {
114 |       console.error(`Getting code for address: ${args.address} at block: ${args.blockParameter}`);
115 |       
116 |       const code = await makeRpcCall('eth_getCode', [args.address, args.blockParameter]);
117 |       
118 |       return {
119 |         content: [{ 
120 |           type: "text", 
121 |           text: code === '0x' ? 
122 |             `No code found at address ${args.address} (this may be a regular wallet address, not a contract)` : 
123 |             `Contract code at ${args.address}:\n${code}`
124 |         }]
125 |       };
126 |     } catch (error) {
127 |       return {
128 |         content: [{ type: "text", text: `Error: Failed to get code. ${error.message}` }],
129 |         isError: true
130 |       };
131 |     }
132 |   }
133 | );
134 | 
135 | // Tool 2: eth_gasPrice - Gets the current gas price
136 | server.tool(
137 |   'eth_gasPrice',
138 |   'Retrieves the current gas price in wei',
139 |   {},
140 |   async () => {
141 |     try {
142 |       console.error('Getting current gas price');
143 |       
144 |       const gasPrice = await makeRpcCall('eth_gasPrice');
145 |       // Convert hex gas price to decimal and then to Gwei for readability
146 |       const gasPriceWei = parseInt(gasPrice, 16);
147 |       const gasPriceGwei = gasPriceWei / 1e9;
148 |       
149 |       return {
150 |         content: [{ 
151 |           type: "text", 
152 |           text: `Current Gas Price:\n${gasPriceWei} Wei\n${gasPriceGwei.toFixed(2)} Gwei` 
153 |         }]
154 |       };
155 |     } catch (error) {
156 |       return {
157 |         content: [{ type: "text", text: `Error: Failed to get gas price. ${error.message}` }],
158 |         isError: true
159 |       };
160 |     }
161 |   }
162 | );
163 | 
164 | // Tool 3: eth_getBalance - Gets the balance of an account
165 | server.tool(
166 |   'eth_getBalance',
167 |   'Retrieves the balance of a given Ethereum address',
168 |   {
169 |     address: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe('The Ethereum address to check balance'),
170 |     blockParameter: z.string().default('latest').describe('Block parameter (default: "latest")')
171 |   },
172 |   async (args) => {
173 |     try {
174 |       console.error(`Getting balance for address: ${args.address} at block: ${args.blockParameter}`);
175 |       
176 |       const balance = await makeRpcCall('eth_getBalance', [args.address, args.blockParameter]);
177 |       // Convert hex balance to decimal and then to ETH for readability
178 |       const balanceWei = parseInt(balance, 16);
179 |       const balanceEth = balanceWei / 1e18;
180 |       
181 |       return {
182 |         content: [{ 
183 |           type: "text", 
184 |           text: `Balance for ${args.address}:\n${balanceWei} Wei\n${balanceEth.toFixed(6)} ETH` 
185 |         }]
186 |       };
187 |     } catch (error) {
188 |       return {
189 |         content: [{ type: "text", text: `Error: Failed to get balance. ${error.message}` }],
190 |         isError: true
191 |       };
192 |     }
193 |   }
194 | );
195 | 
196 | // Connect to the stdio transport and start the server
197 | server.connect(new StdioServerTransport())
198 |   .then(() => {
199 |     console.error('Ethereum RPC MCP Server is running...');
200 |   })
201 |   .catch((err) => {
202 |     console.error('Failed to start MCP server:', err);
203 |     process.exit(1);
204 |   });
205 | 
```