arbitrum-mcp-tools
Version:
A comprehensive collection of Model Context Protocol (MCP) tools for interacting with the Arbitrum blockchain. Enables AI assistants like Claude, Cursor, Windsurf, VS Code, Gemini CLI, and OpenAI Codex to perform blockchain operations including account an
154 lines (153 loc) • 6.07 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { z } from "zod";
import { handleError } from "../common.js";
import { alchemy } from "../../server.js";
export function registerDevelopmentTools(server) {
// 1. Transaction Simulation
server.tool("simulateTransaction", "Simulate Arbitrum transaction with basic parameters", {
from: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid address format")
.describe("From address"),
to: z
.string()
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid address format")
.describe("To address"),
data: z.string().optional().describe("Transaction data (optional)"),
value: z
.string()
.optional()
.describe("Value in wei as hex string (optional)"),
gas: z.string().optional().describe("Gas limit as hex string (optional)"),
}, (_a) => __awaiter(this, [_a], void 0, function* ({ from, to, data, value, gas }) {
try {
// Build simple transaction object
const tx = { from, to };
if (data)
tx.data = data;
if (value)
tx.value = value;
if (gas)
tx.gas = gas;
// Simulate the transaction
const result = yield alchemy.transact.simulateAssetChanges(tx);
// Handle errors
if (result.error) {
return {
content: [
{
type: "text",
text: `❌ Error: ${result.error.message}`,
},
],
};
}
// Format simple response
let response = "✅ Simulation Success\n\n";
// Basic transaction info
response += `From: ${from}\n`;
response += `To: ${to}\n`;
if (value) {
const ethValue = (parseInt(value, 16) / 1e18).toFixed(4);
response += `Value: ${ethValue} ETH\n`;
}
// Gas usage
if (result.gasUsed) {
const gasUsed = parseInt(result.gasUsed, 16).toLocaleString();
response += `Gas Used: ${gasUsed}\n`;
}
// Asset changes
if (result.changes && result.changes.length > 0) {
response += `\nAsset Changes: ${result.changes.length} detected\n`;
result.changes.forEach((change, i) => {
response += `\nChange ${i + 1}:\n`;
response += JSON.stringify(change, null, 2);
});
}
else {
response += "\nNo asset changes detected";
}
return {
content: [{ type: "text", text: response }],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `❌ Failed: ${handleError(error)}`,
},
],
};
}
}));
// 2. Gas Estimation
server.tool("estimateGas", "Estimate gas usage for a transaction", {
to: z.string().describe("Destination address"),
from: z.string().optional().describe("Optional sender address"),
data: z
.string()
.optional()
.describe("Optional transaction data (hex string)"),
value: z
.string()
.optional()
.describe("Optional value in wei as a string (e.g., '1000000000000000000')"),
gasPrice: z
.string()
.optional()
.describe("Optional gas price in wei as a string (e.g., '20000000000')"),
nonce: z
.string()
.optional()
.describe("Optional transaction nonce as a string (e.g., '0', '1')"),
type: z
.number()
.optional()
.describe("Optional EIP-2718 transaction type (e.g., 0 for legacy, 2 for EIP-1559)"),
}, (_a) => __awaiter(this, [_a], void 0, function* ({ to, from, data, value, gasPrice, nonce, type }) {
try {
const transactionToEstimate = { to };
if (from)
transactionToEstimate.from = from;
if (data)
transactionToEstimate.data = data;
if (value)
transactionToEstimate.value = value;
if (gasPrice)
transactionToEstimate.gasPrice = gasPrice;
if (nonce)
transactionToEstimate.nonce = parseInt(nonce, 10);
if (type !== undefined)
transactionToEstimate.type = type; // Check for undefined as 0 is a valid type
const estimate = yield alchemy.core.estimateGas(transactionToEstimate);
return {
content: [
{
type: "text",
text: `Estimated gas: ${estimate.toString()}`,
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${handleError(error)}`,
},
],
};
}
}));
}