Skip to main content
Glama
README.md
# chainlens

chainlens looks into EVM blockchains through Blockscout: what an
address holds and has done, what is in a block or a transaction, which
tokens and NFTs sit in a wallet, and what a verified contract's ABI and
source say. Six chains are built in — Ethereum, Optimism, Gnosis,
Polygon, Base, and Arbitrum One — and every answer comes from that
chain's public Blockscout API v2 instance.

This package is a clean-room rebuild of the 16 tools documented in the
README of the original Blockscout MCP server. The full documented set
is covered; the wire mapping is described below, including the parts
that are reconstructions.

## How it talks to the service

No API key is required — public Blockscout instances are keyless:

```bash
# Optional: send a key as an x-api-key header
export BLOCKSCOUT_API_KEY="your key"
# Optional: override the per-chain base URL for any chain
export BLOCKSCOUT_API_URL="https://eth.blockscout.com/api/v2"
```

The base URL is chosen per `chain_id` from a built-in map:
`1` Ethereum, `10` Optimism, `100` Gnosis, `137` Polygon, `8453` Base,
`42161` Arbitrum One. An unknown `chain_id` is an error naming the
known chains (unless `BLOCKSCOUT_API_URL` is set, in which case the
override wins for any chain).

**Wire-format notes.** The original server routes most data tools
through its PRO gateway; this rebuild maps them onto the public
Blockscout API v2 (`/addresses/...`, `/blocks/...`,
`/transactions/...`, `/smart-contracts/...`, `/search`). A few shapings
are documented reconstructions and first live-smoke checks:

- ENS resolution uses mainnet `/search?q=<name>` and picks the first
  result carrying an address.
- `read_contract` POSTs `{function_name, args, abi}` to
  `/smart-contracts/{address}/methods/read` — the least-proven mapping.
- `cursor` arguments are forwarded as a `cursor` query parameter;
  Blockscout v2 paging normally uses `next_page_params`, so cursor
  support is a drift risk.
- `age_from` / `age_to` (and `methods` / `token`) filters are applied
  client-side over the first fetched page, not forwarded upstream.

Two tools never touch the network: `__unlock_blockchain_analysis__`
returns local guidance plus the chain list, and `get_chains_list`
filters that list locally by name, chain id, or currency substring.

## Install

```bash
npx @reneturcios/chainlens get_block_number '{"chain_id":"1"}'
```

Or run the container image:

```bash
docker run -i ghcr.io/cloudcorprecords/chainlens
```

The container defaults to the MCP server. Pass CLI arguments to use
it as a CLI instead.

## CLI

The CLI mirrors the tools: one subcommand per tool, taking its
arguments as a single JSON object.

```bash
chainlens get_chains_list '{"query":"base"}'
chainlens get_address_info '{"chain_id":"1","address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}'
chainlens get_transactions_by_address '{"chain_id":"1","address":"0x...","age_from":"2026-10-01T00:00:00Z","age_to":"2026-10-26T23:59:59Z"}'
chainlens get_block_info '{"chain_id":"8453","number_or_hash":"latest"}'
chainlens --version
```

Exit codes: `0` on success, `1` on an API or validation error (the
error names the problem), `2` for usage errors.

## MCP server

One bin serves both faces. The `mcp` subcommand starts a stdio MCP
server:

```bash
npx -y @reneturcios/chainlens mcp
```

MCP client configuration:

```json
{
  "mcpServers": {
    "chainlens": {
      "command": "npx",
      "args": ["-y", "@reneturcios/chainlens", "mcp"]
    }
  }
}
```

### Tools

| Tool | Input | What it does |
| --- | --- | --- |
| `__unlock_blockchain_analysis__` | — | Local: returns status, guidance, and the supported chain list. |
| `get_chains_list` | `query` | Local: the 6-chain list filtered by a name/id/currency substring. |
| `get_address_by_ens_name` | `name` (required) | Resolve an ENS name via mainnet search; returns the first result with an address. |
| `lookup_token_by_symbol` | `chain_id`, `symbol` (required) | Search a chain; returns token-type items (fallback: all items). |
| `get_contract_abi` | `chain_id`, `address` (required) | The ABI of a verified contract. |
| `inspect_contract_code` | `chain_id`, `address` (required), `file_name` | Source code and creation status of a verified contract. |
| `get_address_info` | `chain_id`, `address` (required) | Address balance, type, and metadata. |
| `get_tokens_by_address` | `chain_id`, `address` (required), `cursor` | Token balances held by an address. |
| `get_block_number` | `chain_id` (required), `datetime` | Latest block number and timestamp; echoes the requested datetime. |
| `get_transactions_by_address` | `chain_id`, `address`, `age_from`, `age_to` (required), `methods`, `cursor` | Address transactions; age and method filters applied client-side over the first page. |
| `get_token_transfers_by_address` | `chain_id`, `address`, `age_from`, `age_to` (required), `token`, `cursor` | ERC-20 transfers; age and token filters applied client-side over the first page. |
| `nft_tokens_by_address` | `chain_id`, `address` (required), `cursor` | NFT tokens (ERC-721, ERC-1155) held by an address. |
| `get_block_info` | `chain_id`, `number_or_hash` (required), `include_transactions` | Block details by number or hash. |
| `get_transaction_info` | `chain_id`, `hash` (required), `include_raw_input` | Transaction details by hash. |
| `read_contract` | `chain_id`, `address`, `abi`, `function_name` (required), `args` (JSON string, default `[]`), `block` | Read a contract function (reconstructed wire mapping, see notes). |
| `direct_api_call` | `chain_id`, `endpoint_path` (required), `query_params`, `method`, `json_body`, `cursor` | Call any Blockscout API v2 endpoint path directly. |

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # node test runner over test/*.test.ts, fake fetch only, no network
npm run dev     # run the CLI from source via tsx
```

## License

MIT — see `LICENSE`.