# 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)