Skip to main content
Glama

MCP Smart Contract Analyst

by RockYuan
index.ts5.74 kB
/** * MCP Smart Contract Analyst * * @author Ry @RockRockDay * * Implements a Model Context Protocol (MCP) server to interact with the Monad blockchain * for smart contract source code analysis, including functionality and security evaluation. * For unverified contracts, decompilation is used to assist in source code recovery and review. */ // Import necessary dependencies import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { createPublicClient, http } from "viem"; import { monadTestnet } from "viem/chains"; // Create a public client to interact with the Monad testnet const publicClient = createPublicClient({ chain: monadTestnet, transport: http(), }); // Initialize the MCP server with a name, version, and capabilities const server = new McpServer({ name: "mcp-contract-analyst", version: "0.0.1", capabilities: ["analyze-verified-contract", "analyze-unverified-contract"] }); server.tool( "analyze-verified-contract", "Analyze a verified contract from an address on the Monad testnet.", { address: z.string().describe("Monad testnet address to analyze verified contract for"), }, async ({ address }) => { try { const apiUrl = process.env.API_URL const apiKey = process.env.API_KEY; if (!apiUrl) { throw new Error("API_URL not set."); } if (!apiKey) { throw new Error("API_KEY not set."); } const url = `${apiUrl}${address}`; const response = await fetch(url, { method: 'GET', headers: { "accept": "application/json", "x-api-key": apiKey } }); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } const data = await response.json(); if (data.code !== 0) { throw new Error(`API request failed with error: ${data.message}`); } const sourceCodeList = data.result.sourceCode; if (sourceCodeList && sourceCodeList.length > 0) { const allSourceCode = sourceCodeList .map((item: { content: string }) => item.content) .join('\n\n'); return { content: [ { type: "text", text: `Analyze the source code of smart contract, including its core functionalities, main logic flow, and security aspects:\n\`\`\`\n${allSourceCode}\n\`\`\``, }, ], }; } else { throw new Error(`Failed to retrieve source code`); } } catch (error) { console.error("Error getting contract sourceCode:", error); return { content: [ { type: "text", text: `Failed to retrieve contract sourceCode for address: ${address}. Error: ${error instanceof Error ? error.message : String(error) }`, }, ], }; } } ); server.tool( "analyze-unverified-contract", "Analyze a unverified contract from an address on the Monad testnet.", { address: z.string().describe("Monad testnet address to analyze unverified contract for"), }, async ({ address }) => { try { const bytecode = await publicClient.getCode({ address: address as `0x${string}`, }) console.debug("contract bytecode:", bytecode); const decompileUrl = process.env.DECOMPILE_URL; if (!decompileUrl) { throw new Error("DECOMPILE_URL not set."); } const formData = new FormData(); formData.append('bytecode', `${bytecode}`); const response = await fetch(decompileUrl, { method: 'POST', body: formData, }); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } const html = await response.text(); const regex = /<div class="code javascript" style="border: 1px solid gray; padding: 0.5em; white-space: pre; font-family: monospace; line-height: 1.2">([\s\S]*?)<\/div>/; const match = html.match(regex); if (match) { const sourceCodeWithHtml = match[1]; const sourceCode = sourceCodeWithHtml.replace(/<[^>]*>/g, ''); return { content: [ { type: "text", text: `Analyze the decompiled source code of contract ${address}, including its core functionalities, main logic flow, and security aspects:\n\`\`\`\n${sourceCode}\n\`\`\` `, }, ], }; } else { throw new Error(`Failed to retrieve source code: ${html}`); } } catch (error) { console.error("Error getting contract bytecode:", error); return { content: [ { type: "text", text: `Failed to retrieve contract bytecode for address: ${address}. Error: ${error instanceof Error ? error.message : String(error) }`, }, ], }; } } ); /** * Main function to start the MCP server * Uses stdio for communication with LLM clients */ async function main() { // Create a transport layer using standard input/output const transport = new StdioServerTransport(); // Connect the server to the transport await server.connect(transport); console.log("Monad testnet MCP Server running on stdio"); } // Start the server and handle any fatal errors main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RockYuan/mcp-contract-analyst'

If you have feedback or need assistance with the MCP directory API, please join our Discord server