To obtain blockchain data with Testril, discover a supported metric, bind the requested scope, check coverage, materialize missing blocks, read values, and verify provenance. Materialization and reading have separate payment gates; confirm spending before settlement. First connect and discover the live contract.

1. Discover the chain and template

Call inspect with subject: "chains", then subject: "functions". Confirm the requested chain is configured. Select a template whose semantics match the operator's request.

For example, if advertised:

{"tool":"inspect","arguments":{"subject":"function","function_slug":"erc20.token_balance"}}

Read its params and row schemas, descriptions, and defaults. The catalog's Function names are metric templates; they are not MCP tools.

2. Bind the scope

The following addresses and chain are placeholders. Substitute operator-supplied values, and use exactly the parameter names advertised by the selected template.

{"tool":"bind","arguments":{"function_slug":"erc20.token_balance","chain_id":1,"params":{"reads":{"tokens":["<TOKEN_ADDRESS>"],"owners":["<WALLET_ADDRESS>"]}}}}

Proceed only on outcome: "success". Save the returned bound_function_id. Binding creates an identity and scope, not an indexed dataset. created: false does not prove the requested window is covered.

3. Check coverage and choose the window

{"tool":"inspect","arguments":{"subject":"bound_function","bound_function_id":"<BOUND_FUNCTION_ID>"}}

Read materialized, materializing, and active_jobs. Choose a requested half-open block interval [from_block, to_block) using the correct chain's head and the operator's intended period. The head is not a finality guarantee. Example block numbers below illustrate syntax; they do not prescribe a useful query window.

4. Materialize missing blocks

{"tool":"materialize","arguments":{"bound_function_id":"<BOUND_FUNCTION_ID>","from_block":100,"to_block":110}}

If payment is required, read x402 PaymentRequired from structuredContent/content[0] and the quote {quote_id, amount, lines} from content[1] of the MCP error result. Inspect lines, amount, and accepts, obtain spending authorization, and prepare the signed PaymentPayload for an offered rail. Read exact quote values from amount.atoms and line-item atom values; use each money object's usd only for display. The x402 accepts[].amount field remains a bare atom string and must equal the quoted charge.

{"tool":"materialize","arguments":{"bound_function_id":"<BOUND_FUNCTION_ID>","from_block":100,"to_block":110},"_meta":{"x402/payment":{"x402Version":2,"scheme":"<OFFERED_SCHEME>","accepted":"<ACCEPTS_ROW>","payload":"<SIGNED_FIELDS>"}}}

The host attaches _meta; do not put a private key in tool arguments. Preserve the returned _meta["x402/payment-response"] receipt.

A successful accepted job can still be running. Inspect the returned job.job_id and the bound function's coverage before reading. Start paid execution within the quote's 120-second lifetime.

5. Read values

{"tool":"read","arguments":{"bound_function_id":"<BOUND_FUNCTION_ID>","from_block":100,"to_block":110}}

Reading has its own pay gate. If payment is required, retry the same read arguments with the signed PaymentPayload attached in MCP transport metadata.

A successful read returns bare values, one row per block and key with all its attributes, typed by the Function’s row schema from inspect. Within fully covered blocks, absent rows follow the Function's declared emission rules; an unavailable window is not a zero balance.

6. Verify the source window

Use the same bound identity and exact half-open window; there is no attribute selector:

{"tool":"provenance","arguments":{"bound_function_id":"<BOUND_FUNCTION_ID>","from_block":100,"to_block":110}}

Keep the result identity, exact window, values, source block hashes, and applicable digest together. See provenance verification for limits and interpretation.