Skip to content

get_all_balances and get_spendable_balances return empty for populated addresses (silently wrong) #2

@glandua

Description

@glandua

Summary

The get_all_balances and get_spendable_balances MCP tools return empty balances + total=0 for addresses that provably hold multiple denominations on-chain. The denom-specific get_balance tool works correctly for the same addresses. The aggregate queries return a valid-shaped JSON response ({"balances":[], "pagination":{"total":"0"}}) rather than an error, making the failure silent.

Surfaced via the regen-python-mcp submodule inside glandua/regen-mcps during a 2026-04-17/18 claims-engine dogfooding session while querying two different mainnet addresses.

Reproduction

Address (primary wallet, mainnet regen-1): regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct

A. MCP calls (this repo, via Claude Code)

get_all_balances(address="regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct")
→ {"result":{"balances":[],"pagination":{"next_key":null,"total":"0"}}}

get_spendable_balances(address="regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct")
→ {"result":{"balances":[],"pagination":{"next_key":null,"total":"0"}}}

get_balance(address="regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct", denom="uregen")
→ {"result":{"balance":{"denom":"uregen","amount":"31632387289"}}}

B. Ground-truth CLI (same RPC endpoint)

$ regen query bank balances regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct \
    --node https://regen-rpc.polkachu.com:443 --output json

{
  "balances": [
    {"denom": "ibc/334740505537E9894A64E8561030695016481830D7B36E6A9B6D13C608B55653", "amount": "7400000"},
    {"denom": "uregen", "amount": "31632387289"}
  ],
  "pagination": {"total": "2"}
}

Spendable balances via CLI returns the same two denoms (nothing is locked/staked for this address at query time).

C. Direct REST call to an endpoint the MCP uses

$ curl -s "https://regen-rest.publicnode.com/cosmos/bank/v1beta1/balances/regen1tumh45fsagtstswtfwhm0fypka0p7s5x6n2fct"
{"balances":[{"denom":"ibc/334740505537E9894A64E8561030695016481830D7B36E6A9B6D13C608B55653","amount":"7400000"},{"denom":"uregen","amount":"31632387289"}],"pagination":{"next_key":null,"total":"2"}}

So the on-chain state is populated, the CLI sees it, the REST endpoint this MCP lists in its fallback chain (regen-rest.publicnode.com) returns the populated response, and the per-denom MCP tool surfaces the right value. Only the MCP aggregate wrappers (get_all_balances, get_spendable_balances) return empty.

Suspected location

  • src/mcp_server/tools/bank_tools.pyget_all_balances (≈L58), get_spendable_balances (≈L119)
  • Both delegate to RegenClient.query_all_balances / query_spendable_balances in src/mcp_server/client/regen_client.py (≈L1103, L1132), which hit /cosmos/bank/v1beta1/balances/{address} and /cosmos/bank/v1beta1/spendable_balances/{address}.

Suspected root causes worth checking (in order of likelihood):

  1. The regen_rest_endpoints default list in src/mcp_server/config/settings.py has https://api.regen.network first. That host returns a 404 HTML body (Cannot GET /cosmos/bank/v1beta1/balances/...) for both aggregate endpoints and for the /by_denom endpoint — yet get_balance clearly succeeds in the same session. So the two code paths appear to resolve different endpoints. Worth confirming whether the settings list is actually read (the RegenClient.__init__ hardcodes a different list starting with public-rpc.regen.vitwit.com:1317).
  2. If api.regen.network IS being hit first and returning HTML for the aggregate path specifically, and the fallback logic silently swallows a parse error and returns {"balances": []}, that would match the observed symptom exactly.
  3. Less likely, but — Pagination.to_query_params() emits pagination.limit=100&pagination.offset=0&pagination.count_total=true&pagination.reverse=false. Those are the correct Cosmos SDK v1beta1 param names; I verified the upstream REST accepts them and returns the populated response. So the param encoding itself is not the bug.

Workaround (current)

Use get_balance(address=..., denom="uregen") for each denom of interest. Not ergonomic when you don't know the denom list in advance, but it works.

Impact

Silently-wrong aggregate balance queries are a footgun for:

  • Portfolio-style tools that iterate balances
  • Pre-broadcast affordability checks (balance-of-0 → "insufficient funds" on a funded address)
  • Any LLM-driven flow that branches on "is this address empty?"

Not a critical blocker (denom-specific query works), but it was observed during two separate sessions and produced misleading prompts during an on-chain anchoring run. Filing so it doesn't rot.

Context

  • Session journal where this was first noticed: 2026-04-17 claims-engine dogfood + first mainnet MsgAnchor run.
  • Second confirmation: 2026-04-18, new session, same two addresses, same behavior.
  • Filed as an issue (not a PR) — I'm not the maintainer of this code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions