Skip to content

Surface low PRO API credit balance for read_contract #395

Description

@akolotov

Description

Sub-issue of #382 (part 3 of 3). Extend credit awareness (low-credits advisory note + 402 credit-exhaustion handling) to read_contract, which uses a separate transport and is intentionally excluded from parts 1 and 2.

Depends on part 1 (#393) and part 2 (#394), which establish CreditsExhaustedError, the CreditSink/ContextVar mechanism, and the low-credits note on the HTTP transport.

Background

read_contract does not go through _make_blockscout_http_request. It calls smart-contract functions via web3.py over the PRO API RPC endpoint through WEB3_POOL (blockscout_mcp_server/web3_pool.py). As a result:

  • The x-credits-remaining header from the RPC responses is not captured, so read_contract responses never carry the low-credits note.
  • A credit-related 402 on the RPC path would surface as a generic web3 exception, not CreditsExhaustedError.

This means the "applies to every tool" intent of #382 is consciously narrowed in parts 1–2; this issue closes that gap for the web3 transport.

Open questions to resolve

  • Does the PRO API RPC path consume credits and return x-credits-remaining? (Note: /api/eth-rpc was rejected in direct_api_call per Reject on /api/eth-rpc in direct_api_call #389 — clarify how RPC requests are routed/priced for the web3 pool.)
  • How to intercept web3 HTTP response headers (e.g. a custom AsyncHTTPProvider / request middleware on the pooled provider) so the value can be fed into the same CreditSink.
  • How to detect and map an RPC-level credit rejection to CreditsExhaustedError.

Proposed Changes (to be refined after the open questions)

  • Hook the WEB3_POOL provider so successful RPC responses feed x-credits-remaining into the per-invocation CreditSink (reusing the part-2 mechanism), making the low-credits note appear on read_contract responses.
  • Map RPC credit-exhaustion to CreditsExhaustedError so read_contract produces the same distinct error as the HTTP-transport tools.

Tests

  • read_contract populates the CreditSink from RPC responses and surfaces the low-credits note via build_tool_response.
  • RPC credit-exhaustion maps to CreditsExhaustedError (and REST → 402).

Documentation

  • SPEC.md: remove/replace the part-1/2 scope note that excludes the web3 path; document the unified behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions