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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions