DEV Community

fino
fino

Posted on

I Built an MCP Tool That Scans Smart Contracts for Security Risks

TL;DR: I deployed a contract security scanner on Base L2, then wrapped it as an MCP server so any AI assistant (Claude, Cursor, Cline) can scan contracts on demand. Free, open, permissionless.

The problem

Before interacting with a smart contract — approving a token, depositing in a DeFi protocol, buying an NFT — you should check if it's safe. But most devs just... don't. It's too slow to manually check Etherscan, read the ABI, look for rug patterns.

I wanted to make this a one-liner inside my AI assistant.

What I built

An MCP (Model Context Protocol) server that exposes a contract scanner as a tool.

Once installed, you just ask:

"Is this token safe to buy? 0x4ed4e862860bed51a9570b96d89af5e1b0efefed"
Enter fullscreen mode Exit fullscreen mode

And your AI assistant calls the tool automatically and returns:

## 🟡 Risk Score: 30/100 — MEDIUM

Contract: 0x4ed4e862...
Name: DEGEN
Age: 412 days
Source verified: ✅ Yes

### 🟠 HIGH (1)
- mint(address,uint256): Selector 0x40c10f19 found in bytecode

### ✅ GOOD (3)
- Source code verified
- ERC20 compliant
- Active contract (100+ recent txs)
Enter fullscreen mode Exit fullscreen mode

How it works

The scanner analyzes a contract address on Base L2:

  1. Fetches bytecode via free RPC (https://mainnet.base.org)
  2. Checks source verification via BaseScan API (free tier)
  3. Scans for risky function selectors in bytecode:
    • 🔴 Critical: rescueTokens(), withdrawAll() (backdoors)
    • 🟠 High: mint(), blacklist()
    • 🟡 Medium: pause(), setFee(), upgradeable proxies
  4. Checks contract age and transaction activity
  5. Returns a risk score 0–100

The MCP layer wraps this as 3 tools:

  • scan_contract(address) — full scan with findings
  • batch_scan([addr1, addr2, ...]) — compare up to 5 contracts
  • interpret_risk(score, findings) — get SAFE / CAUTION / HIGH_RISK / DO_NOT_USE

Install in Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "contract-scanner": {
      "command": "node",
      "args": ["/path/to/p8/mcp/server.js"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Same config works for Cursor (~/.cursor/mcp.json) and Cline.

The architecture

AI Assistant (Claude/Cursor/Cline)
    ↓ MCP protocol (stdio)
server.js  ←  McpServer + StdioTransport
    ↓
scanner.js  ←  ethers.js + BaseScan API
    ↓
Base L2 RPC (free) + BaseScan (free tier)
Enter fullscreen mode Exit fullscreen mode

No server. No API key required for basic scans. No wallet needed — read-only.

What's next

The scanner results can also be posted on-chain via the AgentEscrow.sol contract I deployed on Base:

Client sends 0.5 USDC → AgentEscrow → JobCreated event
Scanner analyzes → posts result hash on-chain
24h dispute window → USDC released to scanner wallet
Enter fullscreen mode Exit fullscreen mode

This makes the scanner a trustless on-chain service: pay-per-scan, verifiable, no middleman.


The code is on Base mainnet. Scanner wallet: 0x804dd2cE4aA3296831c880139040e4326df13c6e

If you find it useful, try it. If you find a bug, open an issue.

Top comments (0)