AGENTS.md•27.1 kB
# Blockscout MCP Server
## Project Structure
```text
mcp-server/
├── blockscout_mcp_server/      # Main Python package for the server
│   ├── __init__.py             # Makes the directory a Python package
│   ├── llms.txt                # Machine-readable guidance file for AI crawlers
│   ├── api/                    # REST API implementation
│   │   ├── __init__.py         # Initializes the api sub-package
│   │   ├── dependencies.py     # Dependency providers for the REST API
│   │   ├── helpers.py          # Shared utilities for REST API handlers
│   │   └── routes.py           # REST API route definitions
│   ├── __main__.py             # Entry point for `python -m blockscout_mcp_server`
│   ├── server.py               # Core server logic: FastMCP instance, tool registration, CLI
│   ├── templates/              # Static HTML templates for the web interface
│   │   └── index.html          # Landing page for the REST API
│   ├── config.py               # Configuration management (e.g., API keys, timeouts, cache settings)
│   ├── constants.py            # Centralized constants used throughout the application, including data truncation limits
│   ├── logging_utils.py        # Logging utilities for production-ready log formatting
│   ├── analytics.py            # Centralized Mixpanel analytics for tool invocations (HTTP mode only)
│   ├── telemetry.py            # Fire-and-forget community telemetry reporting
│   ├── client_meta.py          # Shared client metadata extraction helpers and defaults
│   ├── cache.py                # Simple in-memory cache for chain data
│   ├── web3_pool.py            # Async Web3 connection pool manager
│   ├── models.py               # Defines standardized Pydantic models for all tool responses
│   └── tools/                  # Sub-package for tool implementations
│       ├── __init__.py         # Initializes the tools sub-package
│       ├── common.py           # Shared utilities and common functionality for all tools
│       ├── decorators.py       # Logging decorators like @log_tool_invocation
│       ├── address/            # Address-related tools grouped by functionality
│       │   ├── __init__.py
│       │   ├── get_address_info.py
│       │   ├── get_tokens_by_address.py
│       │   └── nft_tokens_by_address.py
│       ├── block/
│       │   ├── __init__.py
│       │   ├── get_block_info.py
│       │   └── get_latest_block.py
│       ├── chains/
│       │   ├── __init__.py
│       │   └── get_chains_list.py
│       ├── contract/
│       │   ├── __init__.py
│       │   ├── _shared.py              # Shared helpers for contract tools
│       │   ├── get_contract_abi.py
│       │   ├── inspect_contract_code.py
│       │   └── read_contract.py
│       ├── direct_api/
│       │   ├── __init__.py
│       │   ├── direct_api_call.py
│       │   ├── dispatcher.py
│       │   └── handlers/
│       │       ├── __init__.py
│       │       └── address_logs_handler.py
│       ├── ens/
│       │   ├── __init__.py
│       │   └── get_address_by_ens_name.py
│       ├── initialization/
│       │   ├── __init__.py
│       │   └── unlock_blockchain_analysis.py
│       ├── search/
│       │   ├── __init__.py
│       │   └── lookup_token_by_symbol.py
│       └── transaction/
│           ├── __init__.py
│           ├── _shared.py             # Shared helpers for transaction tools
│           ├── get_token_transfers_by_address.py
│           ├── get_transaction_info.py
│           ├── get_transaction_logs.py
│           ├── get_transactions_by_address.py
│           └── transaction_summary.py
├── tests/                      # Test suite for all MCP tools
│   ├── integration/            # Integration tests that make real network calls
│   │   ├── __init__.py         # Marks integration as a sub-package
│   │   ├── helpers.py          # Shared utilities for integration assertions
│   │   ├── test_common_helpers.py  # Helper-level integration tests for API helpers
│   │   ├── address/            # Address tool integration tests (one file per tool)
│   │   │   ├── test_get_address_info_real.py
│   │   │   ├── test_get_tokens_by_address_real.py
│   │   │   └── test_nft_tokens_by_address_real.py
│   │   ├── block/
│   │   │   ├── test_get_block_info_real.py
│   │   │   └── test_get_latest_block_real.py
│   │   ├── chains/
│   │   │   └── test_get_chains_list_real.py
│   │   ├── contract/
│   │   │   ├── Web3PyTestContract.sol          # Fixture contract for live calls
│   │   │   ├── test_get_contract_abi_real.py
│   │   │   ├── test_inspect_contract_code_real.py
│   │   │   ├── test_read_contract_real.py
│   │   │   └── web3py_test_contract_abi.json   # ABI fixture for Web3Py tests
│   │   ├── direct_api/
│   │   │   ├── test_address_logs_handler_real.py
│   │   │   └── test_direct_api_call_real.py
│   │   ├── ens/
│   │   │   └── test_get_address_by_ens_name_real.py
│   │   ├── search/
│   │   │   └── test_lookup_token_by_symbol_real.py
│   │   └── transaction/
│   │       ├── test_get_token_transfers_by_address_real.py
│   │       ├── test_get_transaction_info_real.py
│   │       ├── test_get_transaction_logs_real.py
│   │       ├── test_get_transactions_by_address_real.py
│   │       └── test_transaction_summary_real.py
│   ├── api/                      # Unit tests for the REST API
│   │   └── test_routes.py        # Tests for static API route definitions
│   ├── test_server.py            # Tests for server CLI and startup logic
│   ├── test_models.py            # Tests for Pydantic response models
│   └── tools/                  # Unit test modules for each tool implementation
│       ├── address/            # Tests for address-related MCP tools
│       │   ├── test_get_address_info.py        # Tests for get_address_info
│       │   ├── test_get_tokens_by_address.py         # Tests for get_tokens_by_address
│       │   ├── test_nft_tokens_by_address.py         # Tests for nft_tokens_by_address
│       │   └── test_nft_tokens_by_address_pagination.py  # Pagination scenarios for nft_tokens_by_address
│       ├── block/              # Tests for block-related MCP tools
│       │   ├── test_get_block_info.py          # Tests for get_block_info
│       │   └── test_get_latest_block.py        # Tests for get_latest_block
│       ├── chains/             # Tests for chain-related MCP tools
│       │   └── test_get_chains_list.py         # Tests for get_chains_list
│       ├── contract/           # Tests for contract-related MCP tools
│       │   ├── test_fetch_and_process_contract.py  # Tests for fetch_and_process_contract
│       │   ├── test_get_contract_abi.py        # Tests for get_contract_abi
│       │   ├── test_inspect_contract_code.py   # Tests for inspect_contract_code
│       │   └── test_read_contract.py           # Tests for read_contract
│       ├── transaction/        # Tests for transaction-related MCP tools
│       │   ├── test_get_token_transfers_by_address.py      # Tests for get_token_transfers_by_address
│       │   ├── test_get_transaction_info.py        # Tests for get_transaction_info
│       │   ├── test_get_transaction_logs.py        # Tests for get_transaction_logs
│       │   ├── test_get_transaction_logs_pagination.py  # Pagination-focused logs tests
│       │   ├── test_get_transactions_by_address.py      # Tests for get_transactions_by_address
│       │   ├── test_get_transactions_by_address_pagination.py  # Pagination-focused transaction tests
│       │   ├── test_helpers.py                     # Tests for transaction helper utilities
│       │   └── test_transaction_summary.py         # Tests for transaction_summary
│       ├── direct_api/         # Tests for the direct API MCP tool
│       │   ├── handlers/
│       │   │   └── test_address_logs_handler.py
│       │   ├── test_dispatcher.py
│       │   └── test_direct_api_call.py  # Tests for direct_api_call
│       ├── ens/                # Tests for ENS-related MCP tools
│       │   └── test_get_address_by_ens_name.py  # Tests for get_address_by_ens_name
│       ├── initialization/     # Tests for initialization MCP tools
│       │   └── test___unlock_blockchain_analysis__.py  # Tests for __unlock_blockchain_analysis__
│       ├── search/             # Tests for search-related MCP tools
│       │   └── test_lookup_token_by_symbol.py  # Tests for lookup_token_by_symbol
│       ├── test_common.py            # Tests for shared utility functions
│       ├── test_common_truncate.py   # Tests for truncation helpers
│       └── test_decorators.py        # Tests for logging decorators
├── dxt/                        # Desktop Extension (.dxt) package for Claude Desktop
│   ├── README.md               # DXT-specific documentation and packaging instructions
│   ├── manifest.json           # Extension manifest with metadata and tool definitions
│   └── blockscout.png          # Extension icon file
├── gpt/                        # ChatGPT GPT integration package for "Blockscout X-Ray"
│   ├── README.md               # GPT-specific documentation and configuration instructions
│   ├── instructions.md         # Core GPT instructions incorporating `__unlock_blockchain_analysis__` content
│   ├── action_tool_descriptions.md # Detailed descriptions of all MCP tools (due to GPT 8k char limit)
│   └── openapi.yaml            # OpenAPI 3.1.0 specification for REST API endpoints used by GPT actions
├── Dockerfile                  # For building the Docker image
├── pytest.ini                  # Pytest configuration (excludes integration tests by default)
├── API.md                      # Detailed documentation for the REST API
├── README.md                   # Project overview, setup, and usage instructions
├── SPEC.md                     # Technical specification and architecture documentation
├── TESTING.md                  # Testing instructions for HTTP mode with curl commands
├── pyproject.toml              # Project metadata and dependencies (PEP 517/518)
└── .env.example                # Example environment variables
```
## Overview of Components
1. **`mcp-server/` (Root Directory)**
    * **`README.md`**:
        * Provides a comprehensive overview of the project.
        * Includes detailed instructions for local setup (installing dependencies, setting environment variables) and running the server.
        * Contains instructions for building and running the server using Docker.
        * Lists all available tools and their functionalities.
    * **`API.md`**:
        * Provides detailed documentation for all REST API endpoints.
        * Includes usage examples, parameter descriptions, and information on the standard response structure.
    * **`SPEC.md`**:
        * Contains technical specifications and detailed architecture documentation.
        * Outlines the system design, components interaction, and data flow.
        * Describes key architectural decisions and their rationales.
    * **`TESTING.md`**:
        * Provides comprehensive instructions for testing the MCP server locally using HTTP mode.
        * Contains curl command examples for testing all major tools and functionality.
        * Serves as a practical guide for developers to understand and test the server's capabilities.
    * **`pyproject.toml`**:
        * Manages project metadata (name, version, authors, etc.).
        * Lists project dependencies, which will include:
            * `mcp[cli]`: The Model Context Protocol SDK for Python with CLI support.
            * `httpx`: For making asynchronous HTTP requests to Blockscout APIs.
            * `pydantic`: For data validation and settings management (used by `mcp` and `config.py`).
            * `pydantic-settings`: For loading configuration from environment variables.
            * `anyio`: For async task management and progress reporting.
            * `uvicorn`: For HTTP Streamable mode ASGI server.
            * `typer`: For CLI argument parsing (included in `mcp[cli]`).
        * Lists optional test dependencies:
            * `pytest`: Main testing framework for unit tests.
            * `pytest-asyncio`: Support for async test functions.
            * `pytest-cov`: For code coverage reporting.
        * Configures the build system (e.g., Hatchling).
    * **`Dockerfile`**:
        * Defines the steps to create a Docker image for the MCP server.
        * Specifies the base Python image.
        * Copies the application code into the image.
        * Installs Python dependencies listed in `pyproject.toml`.
        * Sets up necessary environment variables (can be overridden at runtime).
        * Defines the `CMD` to run the MCP server in stdio mode by default (`python -m blockscout_mcp_server`).
    * **`.env.example`**:
        * Provides a template for users to create their own `.env` file for local development.
        * Lists all required environment variables, such as:
            * `BLOCKSCOUT_BS_API_KEY`: API key for Blockscout API access (if required).
            * `BLOCKSCOUT_BS_TIMEOUT`: Timeout for Blockscout API requests.
            * `BLOCKSCOUT_BENS_URL`: Base URL for the BENS (Blockscout ENS) API.
            * `BLOCKSCOUT_BENS_TIMEOUT`: Timeout for BENS API requests.
            * `BLOCKSCOUT_METADATA_URL`: Base URL for the Blockscout Metadata API.
            * `BLOCKSCOUT_METADATA_TIMEOUT`: Timeout for Metadata API requests.
            * `BLOCKSCOUT_CHAINSCOUT_URL`: URL for the Chainscout API (for chain resolution).
            * `BLOCKSCOUT_CHAINSCOUT_TIMEOUT`: Timeout for Chainscout API requests.
            * `BLOCKSCOUT_CHAIN_CACHE_TTL_SECONDS`: Time-to-live for chain resolution cache.
            * `BLOCKSCOUT_CHAINS_LIST_TTL_SECONDS`: Time-to-live for the Chains List cache.
            * `BLOCKSCOUT_PROGRESS_INTERVAL_SECONDS`: Interval for periodic progress updates in long-running operations.
            * `BLOCKSCOUT_NFT_PAGE_SIZE`: Page size for NFT token queries (default: 10).
            * `BLOCKSCOUT_LOGS_PAGE_SIZE`: Page size for address logs queries (default: 10).
            * `BLOCKSCOUT_ADVANCED_FILTERS_PAGE_SIZE`: Page size for advanced filter queries (default: 10).
2. **`dxt/` (Desktop Extension Package)**
    * This directory contains the Desktop Extension (.dxt) package for Claude Desktop integration.
    * **`README.md`**:
        * Provides comprehensive documentation for the DXT specification and architecture.
        * Contains detailed packaging instructions for building the extension.
    * **`manifest.json`**:
        * Defines the extension manifest with metadata including name, version, description, and author information.
        * Specifies the server configuration using Node.js with mcp-remote proxy.
        * Lists all available tools with their names and descriptions for Claude Desktop integration.
        * Includes keywords, license, and repository information.
3. **`gpt/` (ChatGPT GPT Integration Package)**
    * This directory contains files required to create the "Blockscout X-Ray" GPT in ChatGPT that integrates with the Blockscout MCP server via REST API.
    * **`README.md`**:
        * Provides comprehensive documentation for GPT creation and configuration.
        * Includes maintenance instructions and known issues with GPT behavior.
        * Specifies recommended GPT configuration (GPT-5 model, web search, code interpreter).
    * **`instructions.md`**:
        * Contains the core instructions for the GPT built following OpenAI GPT-5 prompting guide recommendations.
        * Incorporates content from the `__unlock_blockchain_analysis__` tool for enhanced reasoning.
        * Must be updated if the `__unlock_blockchain_analysis__` tool output changes.
    * **`action_tool_descriptions.md`**:
        * Contains detailed descriptions of all MCP tools available to the GPT.
        * Required due to GPT's 8,000 character limit for instructions.
        * Must be maintained and updated whenever MCP tools are modified or new ones are created.
    * **`openapi.yaml`**:
        * OpenAPI 3.1.0 specification for REST API endpoints used by GPT actions.
        * Contains modified tool descriptions to comply with OpenAPI standards (under 300 characters).
        * Excludes the `__unlock_blockchain_analysis__` endpoint since its data is embedded in GPT instructions.
        * Includes parameter modifications for OpenAPI compliance, particularly for `read_contract` tool.
4. **`tests/` (Test Suite)**
    * This directory contains the complete test suite for the project, divided into two categories:
    * **`tests/tools/`**: Contains the comprehensive **unit test** suite. All external API calls are mocked, allowing these tests to run quickly and offline. Tool-specific tests live in dedicated modules under category folders (for example, `tests/tools/address/test_get_address_info.py`), and shared utilities are covered by modules like `test_common.py`.
        * Each test file corresponds to a single MCP tool and provides comprehensive test coverage:
            * **Success scenarios**: Testing normal operation with valid inputs and API responses.
            * **Error handling**: Testing API errors, chain lookup failures, timeout errors, and invalid responses.
            * **Edge cases**: Testing empty responses, missing fields, malformed data, and boundary conditions.
            * **Progress tracking**: Verifying correct MCP progress reporting behavior for all tools.
            * **Parameter validation**: Testing optional parameters, pagination, and parameter combinations.
        * Uses `pytest` and `pytest-asyncio` for async testing with comprehensive mocking strategies.
        * All tests maintain full isolation using `unittest.mock.patch` to mock external API calls.
    * **`tests/integration/`**: Contains the **integration test** suite. These tests make real network calls and are divided into two categories:
        * **Helper-level tests** in `test_common_helpers.py` verify basic connectivity and API availability.
        * **Tool-level tests** live in domain-specific folders (for example, `tests/integration/address/`). Each `test_*_real.py`
          module exercises exactly one MCP tool to keep test contexts focused for coding agents.
      All integration tests are marked with `@pytest.mark.integration` and are excluded from the default test run.
5. **`blockscout_mcp_server/` (Main Python Package)**
    * **`__init__.py`**: Standard file to mark the directory as a Python package.
    * **`llms.txt`**: Machine-readable guidance file for AI crawlers.
    * **`__main__.py`**:
        * Serves as the entry point when the package is run as a script (`python -m blockscout_mcp_server`).
        * Imports the main execution function (e.g., `run_server()`) from `server.py` and calls it.
    * **`models.py`**:
        * Defines a standardized, structured `ToolResponse` model using Pydantic.
        * Ensures all tools return data in a consistent, machine-readable format, separating the data payload from metadata like pagination and notes.
        * Includes specific data models for complex payloads, like the response from `__unlock_blockchain_analysis__`.
    * **`server.py`**:
        * The heart of the MCP server.
        * Initializes a `FastMCP` instance using constants from `constants.py`.
        * Imports all tool functions from the modules in the `tools/` sub-package.
        * Registers each tool with the `FastMCP` instance using the `@mcp.tool()` decorator. This includes:
            * Tool name (if different from the function name).
            * Tool description (from the function's docstring or explicitly provided).
            * Argument type hints and descriptions (using `typing.Annotated` and `pydantic.Field` for descriptions), which `FastMCP` uses to generate the input schema.
        * Implements CLI argument parsing using `typer` with support for:
            * `--http`: Enable HTTP Streamable mode
            * `--http-host`: Host for HTTP server (default: 127.0.0.1)
            * `--http-port`: Port for HTTP server (default: 8000)
        * Defines `run_server_cli()` function that:
            * Parses CLI arguments and determines the mode (stdio or HTTP)
            * For stdio mode: calls `mcp.run()` for stdin/stdout communication
            * For HTTP mode: configures stateless HTTP with JSON responses and runs uvicorn server
    * **`templates/`**:
        * **`index.html`**: Landing page for the REST API.
    * **`config.py`**:
        * Defines a Pydantic `BaseSettings` class to manage server configuration.
        * Loads configuration values (e.g., API keys, timeouts, cache settings) from environment variables.
        * Provides a singleton configuration object that can be imported and used by other modules, especially by `tools/common.py` for API calls.
    * **`constants.py`**:
        * Defines centralized constants used throughout the application, including data truncation limits.
        * Contains server instructions and other configuration strings.
        * Ensures consistency between different parts of the application.
        * Used by both server.py and tools like `tools/initialization/unlock_blockchain_analysis.py` to maintain a single source of truth.
    * **`logging_utils.py`**:
        * Provides utilities for configuring production-ready logging.
        * Contains the `replace_rich_handlers_with_standard()` function that eliminates multi-line Rich formatting from MCP SDK logs.
    * **`analytics.py`**:
        * Centralized Mixpanel analytics for MCP tool invocations.
        * Enabled only in HTTP mode when `BLOCKSCOUT_MIXPANEL_TOKEN` is set.
        * Generates deterministic `distinct_id` based on client IP, name, and version fingerprint.
        * Tracks tool invocations with client metadata, protocol version, and call source (MCP vs REST).
        * Includes IP geolocation metadata for Mixpanel and graceful error handling to avoid breaking tool execution.
    * **`telemetry.py`**:
        * Sends anonymous usage reports from self-hosted servers when direct analytics are disabled.
        * Designed as fire-and-forget and never disrupts tool execution.
    * **`client_meta.py`**:
        * Shared utilities for extracting client metadata (name, version, protocol, user_agent) from MCP Context.
        * Provides `ClientMeta` dataclass and `extract_client_meta_from_ctx()` function.
        * Falls back to User-Agent header when MCP client name is unavailable.
        * Ensures consistent sentinel defaults ("N/A", "Unknown") across logging and analytics modules.
    * **`cache.py`**:
        * Encapsulates in-memory caching of chain data with TTL management.
    * **`web3_pool.py`**:
        * Manages pooled `AsyncWeb3` instances with shared `aiohttp` sessions.
        * Provides a custom provider to ensure Blockscout RPC compatibility and connection reuse.
    * **`api/` (API layer)**:
        * **`helpers.py`**: Shared utilities for REST API handlers, including parameter extraction and error handling.
        * **`routes.py`**: Defines all REST API endpoints that wrap MCP tools.
        * **`dependencies.py`**: Dependency providers for the REST API, such as a mock context for stateless calls.
    * **`tools/` (Sub-package for Tool Implementations)**
        * **`__init__.py`**: Marks `tools` as a sub-package. May re-export tool functions for easier import into `server.py`.
        * **`common.py`**:
            * Provides shared utilities and common functionality for all MCP tools.
            * Handles API communication, chain resolution, pagination, data processing, and error handling.
            * Implements standardized patterns used across the tool ecosystem.
            * Includes logging helpers such as the `@log_tool_invocation` decorator.
        * **`decorators.py`**:
            * Contains the `log_tool_invocation` decorator and other logging helpers.
        * **Individual Tool Modules** (e.g., `address/get_address_info.py`, `transaction/get_transaction_info.py`):
            * Each MCP tool lives in its own module named after the tool function.
            * Modules are organized by domain (`address/`, `block/`, `contract/`, `transaction/`, etc.) to keep related tools together while preserving a 1:1 mapping.
            * Shared helpers used by multiple tools in the same domain live in `_shared.py` modules alongside the individual tool files.
            * Tool functions remain `async`, accept a `Context` argument for progress reporting, and use `typing.Annotated`/`pydantic.Field` for argument descriptions.
            * The function docstring provides the description surfaced to FastMCP clients.
            * Example modules:
                * `initialization/unlock_blockchain_analysis.py`: Implements `__unlock_blockchain_analysis__`, returning special server instructions and recommended chains.
                * `chains/get_chains_list.py`: Implements `get_chains_list`, returning a formatted list of blockchain chains with their IDs.
                * `ens/get_address_by_ens_name.py`: Implements `get_address_by_ens_name` via the BENS API.
                * `search/lookup_token_by_symbol.py`: Implements `lookup_token_by_symbol(chain_id, symbol)` with a strict result cap.
                * `contract/inspect_contract_code.py`: Uses helpers from `contract/_shared.py` to return metadata or source files for verified contracts.
                * `address/get_tokens_by_address.py`: Implements paginated ERC-20 holdings responses with `NextCallInfo` for follow-up requests.
                * `transaction/get_transactions_by_address.py`: Uses `_shared.py` helpers for smart pagination and filtering of advanced transactions.