Skip to main content
Glama

Bitquery: Crypto & Blockchain Data

Base Transfers Raw Sql

base_transfers_raw_sql
Read-only

LAST RESORT — arbitrary READ-ONLY SQL against the Base transfers database. The Bitquery MCP specialized base_* tools are the PRIORITY; use this ONLY when none of them can answer (e.g. an uncovered table). No query optimizer here — naive SQL full-scans huge tables and JOINs time out. Runs read-only ClickHouse SQL. SQL reference: https://clickhouse.com/docs/reference/home FAST-QUERY RULES: filter on the indexed key tables — base_api.transfers_sender (by sender / outgoing), base_api.transfers_receiver (by receiver / incoming), base_api.transfers_tx (by tx hash); NEVER JOIN big tables — use WHERE col IN (SELECT …) (use GLOBAL IN when the subquery is referenced inside another subquery, otherwise its result is not available where it is used). A subquery that itself reads a transfers table (IN (SELECT Transfer_Sender FROM …transfers_… WHERE …)) is re-run for every shard and rescans that table — run it as its OWN query first, then pass the result back as a literal list (IN (unhex('a'), unhex('b'))). To filter transfers by a specific token, read transfers_currency (keyed by the token contract + Block_Time); transfers_sender / transfers_receiver are keyed by address, so filtering those by a token contract scans the table. Addresses are RAW BYTES FixedString(20) in Transfer_Sender / Transfer_Receiver (there are NO plain string address columns) → Transfer_Sender = unhex(substring(lower('0x…'),3)), output concat('0x',lower(hex(col))). Tx hash is Transaction_Hash FixedString(32) (same unhex/hex pattern). A SET of hashes or addresses must have the column's exact type: Transaction_Hash IN (SELECT toFixedString(unhex(h), 32) FROM …), toFixedString(…, 20) for an address. A plain unhex(…) set, or a JOIN on a String key, silently misses every value ending in 00; = and a literal list IN (unhex('a'), unhex('b')) are safe. Currency symbol + decimals are INLINE columns (no dictionaries): amount = toFloat64(Transfer_Amount) / pow(10, Transfer_Currency_Decimals); symbol = Transfer_Currency_Symbol; token contract = Transfer_Currency_SmartContract — itself RAW BYTES in a String column (not text), so filter it = unhex('<40 hex, no 0x>') and read it back concat('0x',lower(hex(…))); a '0x…' text literal matches nothing. Always add AND Transfer_Success = 1. Transfer_Type: 'token' = a token transfer, 'transaction' = a plain native-coin send, 'call' = native coin moved by a call. A transaction's OWN value transfer is stored either as 'transaction' or as a 'call' with Call_Index = 0; only a 'call' with Call_Index != 0 is an INTERNAL transfer (made by contract code deeper inside the transaction). For top-level transfers filter (Transfer_Type IN ('token','transaction') OR (Transfer_Type = 'call' AND Call_Index = 0)) - Transfer_Type IN ('token','transaction') alone drops a large share of ordinary sends. Time = Block_Time. Date-time values come back as ISO-8601 UTC, e.g. 2026-09-21T15:04:18Z (toString() of a date-time gives 2026-09-21 15:04:18). Other base_api.* tables (calls, transactions, balances) are reachable with an explicit db prefix. Counterparty labels are NOT in this database — use labels_for_addresses. Read-only; always add a LIMIT of at most 10,000 — a larger answer fails with an error, so aggregate (GROUP BY, count) instead. 64-bit integers come back as JSON numbers, exact only up to 2^53: return a hash such as cityHash64(...) or any other 64-bit id as toString(x). Exact table and column names first: chain_list_tables, chain_describe_table and chain_search_columns with database=base_api.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "sql": "<sql>"
    },
    "name": "base_transfers_raw_sql"
  }
}

Input Schema

NameRequiredDescriptionDefault
sqlYesA single read-only SELECT. Filter on the indexed transfers_currency (by token contract) / transfers_sender / transfers_receiver / transfers_tx tables; no JOINs over big tables.
formatNoShape of the returned data. "rows" (the default) returns one item per row. "columnar" returns a single item, {"columns":[...],"rows":[[value,...],...]}, naming the columns once and listing each row's values in that order; it is more compact for large results and carries the same values.rows

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / sql / description
      Previous value: -"A single read-only SELECT. Filter on the indexed transfers_sender / transfers_receiver / transfers_tx tables; no JOINs over big tables."New value: +"A single read-only SELECT. Filter on the indexed transfers_currency (by token contract) / transfers_sender / transfers_receiver / transfers_tx tables; no JOINs over big tables."
  2. Changed1 schema field changed
    • addedInput schema / properties / format
      Added value: +{
      +  "default": "rows",
      +  "description": "Shape of the returned data. \"rows\" (the default) returns one item per row. \"columnar\" returns a single item, {\"columns\":[...],\"rows\":[[value,...],...]}, naming the columns once and listing each row's values in that order; it is more compact for large results and carries the same values.",
      +  "type": "string"
      +}
  3. First observed

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/destructiveHint=false, but the description adds real operational context: no query optimizer, JOINs time out, subqueries rescan per shard, LIMIT over 10,000 errors out, 64-bit ints lose precision past 2^53, and timestamps return as ISO-8601 UTC. This is well beyond the annotation bar; it stops just short of describing result shape (rows vs columnar is left to the schema).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very long, but front-loaded with the critical routing rule ('LAST RESORT') and organized into labeled blocks (FAST-QUERY RULES, type/casting rules, semantics rules). Nearly every sentence carries operational guidance that would otherwise cause a failed query, though some casting details are belabored and repeated across two paragraphs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and a highly complex tool, yet the description covers the query cost model, required WHERE constraints, address/hash encoding, currency/decimals computation, Transfer_Type semantics, success filtering, LIMIT cap and integer precision. An agent has what it needs to write a correct, non-timing-out query.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so baseline is 3, but the description adds substantial meaning about what a valid `sql` value looks like — must be a single read-only SELECT, filter on indexed key tables, no JOINs over big tables. The `format` parameter is only covered by the schema, which is acceptable at full coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb, resource and scope: 'arbitrary READ-ONLY SQL against the Base transfers database', and immediately positions it against the specialized base_* tools ('LAST RESORT... PRIORITY'). An agent can tell without opening a schema that this is the escape hatch, not the default path.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing: use the specialized base_* tools first, this ONLY when none can answer (e.g. an uncovered table). It also names the prerequisite discovery tools (chain_list_tables, chain_describe_table, chain_search_columns with database=base_api) and tells the agent where labels live instead (labels_for_addresses).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.