Skip to main content
Glama
0xwuchuan

Token Info MCP Server

by 0xwuchuan
README.md
# Token Info MCP Server

> **⚠️ DISCLAIMER: AI-Generated Code**
> 
> This entire codebase was generated by AI (Claude) within approximately 2 hours as a proof-of-concept. While functional, it likely contains bugs, edge cases, and security issues that have not been thoroughly tested. 
> 
> **Use with caution and at your own risk.** This code is intended for educational and experimental purposes only. Do not use in production environments without proper code review, testing, and security auditing.

A Model Context Protocol (MCP) server that provides comprehensive token smart contract information by integrating with blockchain tools and APIs. Built in Python following the [official MCP documentation](https://modelcontextprotocol.io/quickstart/server#python).

## Features

### 🔍 Proxy Contract Analysis
- Detect if a contract is a proxy using Foundry's `cast` tool
- Retrieve proxy admin addresses for upgradeable contracts
- Support for multiple proxy types (TransparentUpgradeableProxy, etc.)

### 🔐 AccessControl Role Discovery
- Discover OpenZeppelin AccessControl roles from contract event logs
- Track role grants, revokes, and admin changes
- Support for well-known roles (DEFAULT_ADMIN_ROLE, MINTER_ROLE, etc.)
- Query historical role assignments with block range filtering

### 🌐 Multi-Network Support
- Ethereum Mainnet, Goerli, Sepolia
- Custom RPC endpoints
- Etherscan API integration for all supported networks

## Prerequisites

- **Python 3.10+**
- **Foundry** - Install from [getfoundry.sh](https://getfoundry.sh/)
- **Etherscan API Key** - Get from [etherscan.io](https://etherscan.io/apis)

## Installation

1. **Clone the repository**
   ```bash
   git clone <repository-url>
   cd token-info-mcp
   ```

2. **Install dependencies**
   ```bash
   pip install -r requirements.txt
   ```

3. **Set up environment variables**
   Create a `.env` file:
   ```bash
   # Required
   ETHERSCAN_API_KEY=your_etherscan_api_key_here
   
   # Default RPC URL (used for mainnet)
   DEFAULT_RPC_URL=https://eth.llamarpc.com
   
   # Optional: Network-specific RPC URLs
   MAINNET_RPC_URL=https://eth.llamarpc.com
   GOERLI_RPC_URL=https://eth-goerli.g.alchemy.com/v2/your-api-key
   SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/your-api-key
   POLYGON_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/your-api-key
   ARBITRUM_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/your-api-key
   
   # Rate limiting
   RATE_LIMIT_REQUESTS_PER_SECOND=5
   ```

## Usage

### Running the Server

```bash
python token_info_server.py
```

### Claude Desktop Integration

1. **Install Claude Desktop** from [official website](https://claude.ai/download)

2. **Configure the MCP server** in Claude Desktop:
   
   Edit configuration file:
   - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - Windows: `%APPDATA%\Claude\claude_desktop_config.json`

   ```json
   {
     "mcpServers": {
       "token-info": {
         "command": "python",
         "args": ["/absolute/path/to/token_info_server.py"]
       }
     }
   }
   ```

3. **Restart Claude Desktop** to load the server

### Available Tools

Once configured, Claude Desktop will have access to these tools:

#### 1. `get_proxy_admin`
Get comprehensive proxy admin and ownership analysis for an upgradeable proxy contract.

**Features:**
- Detects proxy admin address
- Identifies if proxy admin is a ProxyAdmin contract
- Discovers ultimate owner of ProxyAdmin contracts  
- Maps complete ownership chain

**Example usage in Claude:**
- "What's the complete ownership structure for 0x259338656198eC7A76c729514D3CB45Dfbf768A1?"
- "Analyze the proxy admin and ownership chain for 0xdAC17F958D2ee523a2206206994597C13D831ec7"
- "Who ultimately controls the proxy at 0x1234... using RPC URL https://eth.llamarpc.com?"
- "Show me the full ownership analysis for 0xABCD... on polygon network"

#### 2. `get_contract_roles`
Discover AccessControl roles and their assignments for a contract.

**Example usage in Claude:**
- "What roles are defined in contract 0x1234...?"
- "Who has the MINTER_ROLE in contract 0xABCD...?"
- "Show me all role assignments for contract 0x5678... from block 18000000 to latest"

## API Reference

### get_proxy_admin

```python
get_proxy_admin(contract_address: str, network: str = "mainnet", rpc_url: str = None) -> str
```

**Parameters:**
- `contract_address`: The contract address to check
- `network`: Network name (mainnet, goerli, sepolia, polygon, arbitrum) or use 'custom' with rpc_url
- `rpc_url`: Custom RPC URL to use (optional, overrides network setting)

**Enhanced Response Format:**
```json
{
  "contract_address": "0x...",
  "network": "mainnet",
  "is_proxy": true,
  "proxy_admin": "0x...",
  "proxy_type": "TransparentUpgradeableProxy",
  "proxy_admin_owner": "0x...",
  "is_proxy_admin_contract": true,
  "ownership_chain": [
    "0x... (proxy contract)",
    "0x... (proxy admin contract)", 
    "0x... (ultimate owner)"
  ]
}
```

### get_contract_roles

```python
get_contract_roles(
    contract_address: str,
    network: str = "mainnet",
    from_block: str = "earliest",
    to_block: str = "latest"
) -> str
```

**Parameters:**
- `contract_address`: The contract address to analyze
- `network`: Network name (mainnet, goerli, sepolia, polygon, arbitrum)
- `from_block`: Starting block number (default: earliest)
- `to_block`: Ending block number (default: latest)

**Returns:**
```json
{
  "contract_address": "0x...",
  "network": "mainnet",
  "roles": [
    {
      "role_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "role_name": "DEFAULT_ADMIN_ROLE",
      "admin_role": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "members": ["0x..."],
      "total_grants": 5,
      "total_revokes": 1
    }
  ],
  "total_roles": 3,
  "block_range": {
    "from": "earliest",
    "to": "latest"
  }
}
```

## Testing

There are several ways to test this MCP server:

### 1. Direct Testing
```bash
# Test the server directly
python token_info_server.py
```

### 2. Claude Desktop Testing
- Configure the server in Claude Desktop
- Ask natural language questions about smart contracts
- Look for the tools icon in Claude Desktop interface

### 3. Unit Testing
```bash
# Install test dependencies
pip install pytest pytest-asyncio

# Run tests
pytest tests/
```

### 4. MCP Client Testing
Use an MCP client library to test the server programmatically:

```python
import asyncio
from mcp.client import Client

async def test_server():
    client = Client()
    # Connect to server via stdio
    # Call tools and verify responses
```

## Troubleshooting

### Common Issues

1. **"Cast command not found"**
   - Install Foundry: `curl -L https://foundry.paradigm.xyz | bash && foundryup`

2. **"Etherscan API rate limit exceeded"**
   - Get an Etherscan API key and set `ETHERSCAN_API_KEY`
   - Reduce `RATE_LIMIT_REQUESTS_PER_SECOND`

3. **"Server not showing up in Claude Desktop"**
   - Check the absolute path in configuration
   - Restart Claude Desktop
   - Check logs: `~/Library/Logs/Claude/mcp*.log`

## License

MIT License

## Resources

- [MCP Documentation](https://modelcontextprotocol.io/)
- [Claude Desktop](https://claude.ai/download)
- [Foundry](https://getfoundry.sh/)
- [Etherscan API](https://etherscan.io/apis)