Skip to main content
Glama

List account balances

well_list_account_balances
Read-only

List every account on the workspace with its stored balance. Rows only — this tool holds no definition of cash, and returns no figure the app renders.

Use it when you are computing a cash figure whose RULES you are stating yourself: which accounts belong to the business, which account types count as cash, which stored field is "the balance", what each currency converts at. The server derives no cash position of its own from this call, so a cash figure starts here: state the rules, keep exactly the rows they admit, then put the result on a card with well_render_cash_position — or, when the answer is cash month by month rather than one total, with well_render_cash_forecast.

It applies no scope. Every active account comes back, including ones you will almost certainly exclude. ownership is workspace, counterparty or unknown, and it decides membership together with company_id:

  • workspace — the business's own, EXCEPT when own_company_id is set AND the row names a different company. A row with no company_id is trusted, because a connector tags a row before any holder is known; so is a row naming a company while own_company_id is still null, because nothing has disproved the pairing yet. Only a tag contradicting a resolved anchor is stale, and counting that one widens the owned scope and overstates the figure.

  • counterparty — not the business's, unconditionally.

  • unknown — unsettled, and settled ONLY by the anchor: own when company_id equals own_company_id, a counterparty's when it names a different one.

own_company_id is null when the workspace has not set one. Nothing is settled against it then — no unknown row, and no workspace row's company pairing either — so say so rather than counting or dropping on a guess. This is the same three-way rule the app's own canvas account scope applies, and a figure that departs from it disagrees with the number the product shows.

It applies no type filter. account_type is one of deposit, credit, loan, investment, payroll, other. A credit or loan account is a liability, so its balance normally nets out of cash rather than adding to it — but that is your decision to state, not a fact about the row, and the sign stored is the sign the provider sent.

It chooses no amount. closing_booked is SETTLED cash; closing_value includes pending and uncleared movements. The two differ by every initiated-but-unsettled payment, so which one you total is the single most consequential choice a cash figure makes: state it. opening_booked is the fallback for a freshly-opened balance with no settled activity yet. Any of them is null when the stored value was absent or not a finite number, which is not a zero balance.

It converts nothing. Each reading carries its own currency, which can differ from the account's own account_currency. Convert per row at a rate you can state, then total — a sum across currencies is denominated in nothing and no field here would say it happened.

It lists each copy of an account. One physical account can arrive once per connector that syncs it. duplicate_of_account_id names the account a row is a second copy of, and is null on every other row. Leave a marked row out of every total and every count: the balance that counts is the named account's, which is the one the app's own figure reads, and the transactions of both copies are counted once. Total both copies and the figure holds that money twice. When the named account has no readable balance, report it as having none rather than taking the copy's reading in its place, or the figure departs from the app's. Marking follows the ownership rule above: only the business's own accounts are marked, and an unknown row only once own_company_id settles it.

balance is null when no row was selected for that account. Two different situations produce it and they must not be reported the same way: verification_rejected: true means the newest balance failed verification and the bounded walk back found no verified one, so the data is repudiated; false means the account simply has no history yet.

months_back adds month_ends to every row: one reading per complete month end, oldest first, keyed YYYY-MM, ending on the last COMPLETE month. This series is where a cash forecast starts — "what will our cash look like", "project our cash forward", "when do we hit zero" — and it is the settled half of well_render_cash_forecast; the projected half is that series' last settled month minus the burn you measure with well_sum_transactions. A null reading is a month no stored row covered — not a zero balance, so never plot it as one and never interpolate between two real points. Omit months_back for the current reading alone; the series is a second query and is not free.

partial: true means the read was cut short BEFORE RETURNING ANYTHING, so it always arrives with an empty rows — it is a fact about the call, never a coverage figure over rows you received. Nothing is known about what is there, so derive no figure from it: say the read was cut short and offer to try again. unreadable_rows is the separate case and the only one that continues: the read finished, and that many rows carried a stored balance that could not be parsed. They hold a null balance, sit in no figure, and make any total a floor, by up to their count: the count covers every row, whatever its owner or type.

When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
months_backNoHow many complete month ends to carry per account, oldest first. Omit for the current reading alone.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.
conversation_idNoThe conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
rowsYes
errorNo
partialYes
successYes
base_currencyYes
own_company_idYes
conversation_idNoThe conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.
unreadable_rowsYes
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
conversation_id_noteNoPresent only when the server opened a fresh lane, stating that no choice recorded earlier was read.
conversation_id_sourceNoWhere the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • addedInput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.",
      +  "type": "string"
      +}
    • changedInput schema / properties / months_back / description
      Previous value: -"How many closed month ends to carry per account, oldest first. Omit for the current reading alone."New value: +"How many complete month ends to carry per account, oldest first. Omit for the current reading alone."
    • addedOutput schema / properties / conversation_id
      Added value: +{
      +  "description": "The conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_note
      Added value: +{
      +  "description": "Present only when the server opened a fresh lane, stating that no choice recorded earlier was read.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / conversation_id_source
      Added value: +{
      +  "description": "Where the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.",
      +  "enum": [
      +    "host_meta",
      +    "argument",
      +    "minted"
      +  ],
      +  "type": "string"
      +}
  2. Changed2 schema fields changed
    • addedOutput schema / properties / rows / items / properties / duplicate_of_account_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • changedOutput schema / properties / rows / items / required
      Previous value: -[
      -  "account_id",
      -  "account_name",
      -  "account_type",
      -  "account_subtype",
      -  "ownership",
      -  "company_id",
      -  "company_name",
      -  "account_currency",
      -  "institution_name",
      -  "masked_account_number",
      -  "balance",
      -  "verification_rejected"
      -]New value: +[
      +  "account_id",
      +  "account_name",
      +  "account_type",
      +  "account_subtype",
      +  "ownership",
      +  "company_id",
      +  "company_name",
      +  "account_currency",
      +  "institution_name",
      +  "masked_account_number",
      +  "duplicate_of_account_id",
      +  "balance",
      +  "verification_rejected"
      +]
  3. Added

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the readOnlyHint/destructiveHint annotations, the description discloses numerous behavioral traits: it applies no scope, no type filter, no amount selection, and no currency conversion. It explains partial reads, unreadable_rows, null balance meanings, verification_rejected, duplicate handling, and the months_back series, all of which materially affect the output. No contradiction exists with annotations.

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?

The description is front-loaded with the core purpose and then organized into clear thematic paragraphs (scope, type, amount, currency, duplicates, nulls, partial reads, months_back, workspace). It is long, but each paragraph earns its place by addressing a distinct misinterpretation an agent could make; only slight trimming could improve it.

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?

For a tool with this much behavioral nuance, the description is remarkably complete: it covers ownership rules, account type implications, amount selection, currency conversion, duplicates, null semantics, partial reads, unreadable_rows, and workspace selection. Since an output schema exists, the description doesn't need to explain return fields, and every call-relevant aspect is addressed.

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?

Input schema covers 100% of parameters, so baseline is 3. The description adds semantic depth: it explains that months_back is a second query that returns one reading per complete month end, that workspace_id must be passed when multiple workspaces are authorized, and that conversation_id must be passed back on every call. This goes beyond the schema descriptions.

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?

The opening sentence states a specific verb and resource: 'List every account on the workspace with its stored balance.' It immediately distinguishes itself from rendering tools by saying 'Rows only — this tool holds no definition of cash, and returns no figure the app renders,' which separates it from siblings like well_render_cash_position and well_render_cash_forecast.

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?

It explicitly instructs when to use this tool: 'Use it when you are computing a cash figure whose RULES you are stating yourself...' and routes to well_render_cash_position or well_render_cash_forecast for presentation. It also clarifies the relationship with well_sum_transactions and explains workspace authorization conditions, so an agent knows exactly how to choose it over alternatives.

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.

Resources