Skip to main content
Glama
bankstatemently

bankstatemently

Official

bankstatemently/plugins

plugins MCP server

Marketplace plugins for Bankstatemently — convert bank statements.

Install via Claude Code marketplace

/plugin marketplace add bankstatemently/plugins
/plugin install bankstatemently@bankstatemently

After installing, enable the plugin. The first tool call opens your browser to sign in; the plugin asks for no settings.

For a headless setup (CI, scripts), skip the plugin and add the server directly with an API key — see below. Get a key at bankstatemently.com/developer.

Related MCP server: CapyParse MCP Server

Plugins

  • bankstatemently — MCP server for converting bank statements. Convert PDFs, list statements, check credits, run benchmark evaluations.

Claude Code direct install (no plugin)

Add the hosted MCP server directly and sign in with your browser:

claude mcp add --transport http bankstatemently https://api.bankstatemently.com/mcp

For a headless setup, pass an API key in the X-API-Key header instead (the server rejects Authorization: Bearer):

claude mcp add --transport http bankstatemently https://api.bankstatemently.com/mcp \
  --header "X-API-Key: <your-bsk_live_key>"

Codex

Codex has native OAuth support. This one command detects our server's discovery metadata and opens your browser to sign in — no key is ever stored:

codex mcp add bankstatemently --url https://api.bankstatemently.com/mcp

For headless or CI setups where a browser sign-in isn't possible, use an API key via the mcp-remote bridge instead. Export the key in the shell that launches Codex, before it starts:

export BANKSTATEMENTLY_API_KEY=bsk_live_...

codex mcp add bankstatemently -- npx -y mcp-remote@latest https://api.bankstatemently.com/mcp --header "X-API-Key: ${BANKSTATEMENTLY_API_KEY}"

Codex doesn't yet surface plugin-declared MCP servers into sessions, so the plugin install above (and its bundled skill) isn't available in Codex today — use the commands above instead.

Credential managers & sandboxed clients: never fetch a secret from Keychain, 1Password, or another credential manager inside the MCP server command itself — Codex runs that command sandboxed at tool discovery, so a credential-manager lookup dies silently and the server's tools never appear. Export the key in the shell that launches Codex instead. Also note that mcp-remote logs its resolved header values to stderr, so a wrapper-resolved key can end up in your client logs.

Run over stdio

For stdio-only clients (Claude Desktop's config file, Cursor, headless setups) or a directory scanner that launches the server locally, clone the public repo and run the self-contained mcp-stdio server directly — no Docker, no bridge process:

git clone https://github.com/bankstatemently/plugins.git
cd plugins/mcp-stdio
npm install --omit=dev
BANKSTATEMENTLY_API_KEY=bsk_live_... node dist/stdio.js

BANKSTATEMENTLY_API_KEY is optional at startup: initialize/tools/list answer with no network call and no key either way, so an uncredentialed directory probe still sees the full tool list. A tools/call with no key returns the same auth-required result the hosted server returns. Export the key in the shell or runtime environment that launches the process — never resolve it inside the MCP command (a credential-manager lookup inside a sandboxed client's command dies silently, same caveat as the Codex section above).

Available Tools

18 tools
adjudicate_transfersAdjudicate TransfersA
Destructive
Inspect

Decide whether ambiguous pairs from list_transfers are transfers. Pass "verdict" when the user has told you; leave it out to let the AI judge decide. Returns the updated list_transfers answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
pairsNoPairs as list_transfers returned them. Required with verdict; omit to judge every open pair.
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
verdictNoThe user's verdict. Omit to let the judge decide.
amountMinNoSame floor as list_transfers.

TDQS

A3.9/5.0
Behavior3/5

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

Annotations declare destructiveHint=true and readOnlyHint=false, so the agent already knows this mutates state; the description adds that the result is 'the updated list_transfers answer,' implying persistence of verdicts. However it never states what the adjudication actually changes, whether verdicts are reversible, or whether omitting pairs silently judges everything — gaps that matter for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core action, then the verdict rule, then the return value. No filler or restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, nested-schema tool with no output schema, the description covers the verdict branch and return shape but omits the consequences of adjudication (what is written, whether rejected pairs are removed) and the pairs-omitted behavior. Adequate to invoke, thin on consequences.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents pairs, scope, verdict and amountMin, making 3 the baseline. The description restates the verdict omission rule already present in the schema and does not explain that omitting pairs judges every open pair, nor what amountMin/scope interact with beyond the schema text.

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?

States a specific verb and resource ('Decide whether ambiguous pairs ... are transfers') and ties the input to the sibling tool that produced it ('pairs from list_transfers'), so an agent can distinguish it from list_transfers without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear conditional for the key decision: 'Pass "verdict" when the user has told you; leave it out to let the AI judge decide.' It implies the tool is used after list_transfers surfaces ambiguity, but it never explicitly says when not to call it or names an alternative path for resolving pairs manually.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

aggregateAggregate TransactionsA
Read-only
Inspect

Compute a single metric (sum/average/count/max/min) over a filtered set of transactions across your converted statements. Results are per-currency — never sum across currencies yourself. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range. For "how many credits do I have" / processing quota / remaining pages, use get_credits instead — that is not a transaction.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
filterNoSubset of transactions to operate on. All fields are optional and combined with AND logic.
metricYesAggregation metric.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint/destructiveHint=false, so safety is covered. The description adds real behavioral context the annotations cannot: results are per-currency and must never be summed across currencies, and the default scope is all completed statements. It stops short of describing result shape or pagination.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with what is computed, followed by the per-currency caveat and then scope semantics and the get_credits routing. No sentence is filler and the most failure-prone caveat is placed early.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-param tool with nested scope/filter objects and no output schema, the description covers metric choice, scope defaults, filter purpose (via the schema) and the per-currency result contract. It does not describe the returned shape or how per-currency groups are keyed, which is a minor residual gap given no output schema exists.

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?

Schema description coverage is 100%, so the baseline is 3; the description still adds meaning beyond the schema by characterizing scope as 'WHO × WHEN', stating that omitting it searches all completed statements, and noting the accounts chips are account/product ids returned by other tools. The per-currency constraint also qualifies how metric results should be read.

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?

States a specific verb (compute) plus the exact metric set (sum/average/count/max/min) over a named resource (transactions across converted statements). The 'single metric' phrasing implicitly separates it from group_by, top_n, time_series and compare, which are the aggregation siblings that would otherwise be ambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent away for one class of question ('how many credits do I have' / quota / remaining pages → use get_credits), and states the default scope plus how to narrow it. It gives clear context but does not explicitly distinguish itself from sibling aggregators like group_by or top_n, leaving that to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

categorize_statementCategorize TransactionsAInspect

Run AI transaction categorization on a previously processed document, then return its category mappings. Returns cached categories with no charge if this document was already categorized. Consumes credits (pooled per page, same rate as the categorize toggle on the website) the first time — free on every re-fetch after. Every response includes a "summary" field: use it as the single source of truth for what happened.

ParametersJSON Schema
NameRequiredDescriptionDefault
document_idYesDocument ID (from convert_statement or list_statements)

TDQS

A4.2/5.0
Behavior5/5

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

The description discloses important behavioral details beyond the annotations, such as credit consumption on first use, caching with free re-fetches, and the presence of a 'summary' field as the source of truth. This is valuable for an agent deciding whether to call the tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, with two sentences that lead with the primary action and then provide key follow-up details about caching and the summary field. There is no redundant or vague wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core function, credit behavior, and response hint about the summary field. However, it does not specify the format of the category mappings or elaborate on error cases (e.g., document not found). Given the tool's simplicity, this is acceptable but not fully exhaustive.

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?

The single parameter document_id has a description that explains it comes from convert_statement or list_statements, providing useful provenance. This goes beyond the basic type declaration and helps the agent know exactly what value to supply.

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 description clearly states the tool's function: running AI transaction categorization on a previously processed document and returning category mappings. It distinguishes itself from sibling tools like convert_statement and list_transactions by focusing on categorization.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives. It implies it should be used after convert_statement (since it requires a processed document), but it does not mention when not to use it or how it compares to list_transactions or other analysis tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compareCompare Transaction GroupsA
Read-only
Inspect

Side-by-side metric comparison for two filtered groups of transactions (e.g. one category vs another, one month vs another). Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
metricYesMetric for both groups.
filterAYesSubset of transactions to operate on. All fields are optional and combined with AND logic.
filterBYesSubset of transactions to operate on. All fields are optional and combined with AND logic.

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered elsewhere. The description usefully adds the default-scope behavior (all completed statements unless narrowed), but says nothing about currency handling, how groups of differing size/period are normalized, or rate/size limits on the comparison.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the comparison purpose and examples come first, the scope default/narrowing second. No filler and nothing buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description should carry more of the return-shape burden — it implies a side-by-side metric result but never states what is returned (two values, a delta, sample sizes). For a nested-scope, 3-required-parameter analytical tool this leaves a real gap, though the core invocation is unambiguous.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so filterA/filterB field semantics, scope.accounts chips, dateRange and the metric enum are all already documented in the schema. The description adds only the framing that filterA and filterB are the two compared groups and that scope narrows WHO×WHEN, which is marginal added meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb+resource ('side-by-side metric comparison for two filtered groups of transactions') and anchors it with concrete examples ('one category vs another, one month vs another'). It is readily distinguishable from aggregate/group_by/top_n in spirit, but never names a sibling to draw the boundary explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the default behavior ('Scope defaults to all your completed statements') and when to supply 'scope' to narrow. However, it gives no guidance on when to prefer this over the closely related analytical siblings (aggregate, group_by, top_n) that could plausibly answer similar questions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

convert_statementConvert Bank StatementAInspect

Convert a bank statement PDF into structured data or a spreadsheet. When the user attaches a PDF in the conversation, it arrives automatically as pdf_file — never encode it yourself. Otherwise, pass pdf_url for a public HTTPS link. If your host has no way to reference the attached file at all (no pdf_file/pdf_url equivalent), call request_upload first and pass its upload_id here instead. The base64 pdf parameter is a last resort only, for a caller with no other way to reference the file. To convert several statements in one call, pass upload_ids (the array from a single request_upload call made with count set) instead of pdf/pdf_url/pdf_file/upload_id — mutually exclusive with those four. This batch form only ADMITS each file (queues it, or reports an already-completed duplicate) and returns immediately with a compact per-file status list plus a summary — it never waits for conversion, so call get_statement per document_id once ready rather than expecting inline results here. Returns accounts, transactions, and metadata. output_format "json" (default) returns the data inline, renderable in chat. The other formats (csv, xlsx, qbo, xero) return a time-limited download link instead: present it as a normal link. Every response includes a "summary" field: use it as the single source of truth for what happened. If the conversation is not in English, translate it faithfully into the conversation language; never add details it doesn't contain. Never echo raw status values (e.g. "completed") or field names. Consumes credits (1 per page). Page limit depends on your plan.

ParametersJSON Schema
NameRequiredDescriptionDefault
pdfNoBase64-encoded PDF content — last resort only; prefer pdf_file for an attachment or pdf_url for a link
pdf_urlNoHTTPS URL to fetch the PDF from
passwordNoPassword for encrypted PDFs
pdf_fileNoAn attached PDF (populated automatically by ChatGPT — do not construct this yourself).
upload_idNoAn upload_id from request_upload, after PUTting the file to its upload_url. Use this only when your host has no other way to reference the attached file (no pdf_file/pdf_url equivalent).
upload_idsNoBatch of upload_ids from a single request_upload(count) call, each already PUT to its own upload_url — converts many statements in one call. Mutually exclusive with pdf, pdf_url, pdf_file, and upload_id. Admission only: the response reports per-file status immediately, never waiting for conversion — fetch results per document_id via get_statement.
output_formatNoOutput formatjson

TDQS

A5/5.0
Behavior5/5

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

Annotations only indicate readOnlyHint=false, openWorldHint=true, destructiveHint=false. The description adds substantial behavioral disclosure: credits consumed per page, page limit depends on plan, batch mode is admission-only and returns immediately without waiting, output format differences (json inline vs download link), the presence of a summary field as ground truth, language translation rule, and instruction to never echo raw statuses. This goes far beyond what annotations imply and fully informs the agent of side effects and response semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although long, every sentence carries load-bearing information. It is logically structured: purpose → file reference options (ordered by preference) → batch behavior → output format handling → summary instruction → credits. There is no repetition or filler. The most decision-critical constraints (auto-attachment, batch no-wait) are front-loaded. This is dense but appropriately so for a complex tool.

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?

The tool has 7 parameters, nested objects, multiple output formats, batch mode, credit consumption, and no output schema. The description covers every operational aspect: how to reference files (single and batch), what the response contains (accounts/transactions/metadata + summary), how to interpret format-specific returns, when to call get_statement, credit costs, and page-limit caveats. Nothing an agent needs to correctly invoke and interpret the tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, yet the description enriches every parameter beyond its schema entry. For pdf_file it explains 'do not construct this yourself'; for pdf_url it clarifies 'public HTTPS'; for upload_id it ties it to request_upload; for upload_ids it explains batch admission and mutual exclusivity; for output_format it details that json is inline while others yield time-limited links; for pdf it marks it as last resort. This added meaning is critical for correct usage and is not present in the schema.

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?

Description opens with a specific verb and resource: 'Convert a bank statement PDF into structured data or a spreadsheet.' It clearly distinguishes from siblings like get_statement (fetching conversion results) and list_statements (listing), and the batch/duplicate admission behavior further differentiates it from single-file conversion. No ambiguity about what the tool accomplishes.

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?

Provides explicit, nuanced guidance on when to use each file reference method: pdf_file arrives automatically (never encode), pdf_url for public HTTPS, upload_id only when no attachment reference exists, pdf as last resort, and upload_ids for batch (with mutual exclusivity stated). It also tells the agent how to handle results (use get_statement per document_id for batch, present download links normally) and instructs to rely on the summary field as source of truth. This is comprehensive routing and alternative selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dismiss_statementDismiss StatementA
Destructive
Inspect

Hide a failed, rejected, or cancelled document from future list_statements results. Use this only when the user asks to clear a terminal failed/rejected/cancelled conversion from their history. This is not a delete: it marks the document dismissed and leaves stored data/artifacts untouched.

ParametersJSON Schema
NameRequiredDescriptionDefault
document_idYesDocument ID from list_statements, convert_statement, or get_statement

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and readOnlyHint=false, so the mutation risk is known. The description adds valuable context beyond annotations: it clarifies that the operation is non-destructive to stored data/artifacts, marking the document as dismissed rather than deleting it. This is a meaningful behavioral disclosure that prevents an agent from overestimating the destructiveness.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: the action and scope, the exact usage condition, and the critical non-delete clarification. The most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with full schema coverage and annotations indicating destructiveness, the description is nearly complete. It explains the effect on list_statements results and clarifies data preservation. It could mention whether the dismissal is reversible, but that is a minor gap given the simplicity of the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single parameter document_id is already fully documented in the schema. The description adds no additional parameter-level detail, but with full coverage, the baseline of 3 is appropriate.

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 description clearly states the verb ('Hide'), the resource (failed/rejected/cancelled documents), and the effect (excluded from future list_statements results). It also explicitly distinguishes itself from a delete operation, which differentiates it from sibling tools like convert_statement or get_statement.

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?

The description gives explicit when-to-use guidance: 'Use this only when the user asks to clear a terminal failed/rejected/cancelled conversion from their history.' It also states what it is not ('This is not a delete'), which helps an agent avoid misusing it as a deletion tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

evaluate_benchmarkEvaluate BenchmarkA
Read-only
Inspect

Score parsed bank statement transactions against the Bankstatemently benchmark ground truth. Accepts a statement_id (e.g. "bsb-001") or content_hash, plus your parsed transactions. Returns extraction accuracy, integrity score, and an overall score. Only statements marked published: true in the catalog can be evaluated — held-out statements return an error. transactions[].originalData is optional but strongly recommended: fetch it via get_statement with data_mode: "original" and pass it through verbatim — an absent originalData scores that transaction's raw-fidelity (parsed) dimension 0; never fabricate a value. Free to use — no credits consumed. Read the benchmark://catalog resource first to see available statements and their published status.

ParametersJSON Schema
NameRequiredDescriptionDefault
accountsNoOptional account roster for multi-account statements. Each transaction references one via accountId.
content_hashNoSHA-256 hex digest of the PDF. Use statement_id instead if you know it.
statement_idNoBenchmark statement ID (e.g. "bsb-001"). Preferred over content_hash.
transactionsYesParsed transactions (1-2000)

TDQS

A5/5.0
Behavior5/5

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

Beyond the annotations (readOnly, non-destructive), the description discloses additional behavioral aspects: it is free (no credits consumed), held-out statements return an error, and omitting originalData scores that dimension 0 rather than fabricating values. These details make the tool's side effects and scoring behavior explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is substantial but every sentence serves a purpose: stating the function, identifying inputs, specifying constraints, and giving warnings. No redundant filler or repetition. It is information-dense while remaining readable and well-structured.

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?

Given the tool's complexity (multiple parameters, nested objects, and nuanced scoring rules), the description covers all essential aspects: the need for published status, the role of originalData, the error behavior, and the free usage. It provides enough context for an agent to call the tool correctly without additional information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already covers all parameters (100% coverage), the description adds meaningful semantics: it explains the preference order between statement_id and content_hash, and elaborates on the originalData parameter's purpose and consequences of absence. This goes beyond the schema's basic field descriptions and clarifies the intent behind each key parameter.

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 description uses the specific verb 'Score' and clearly states the resource (parsed bank statement transactions against the benchmark ground truth). It also distinguishes itself by mentioning the accepted identifiers (statement_id or content_hash) and the required transactions, making the tool's purpose unmistakable even without the name.

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?

The description provides explicit guidance on when to use the tool: only for statements marked published:true in the catalog, and it instructs to read the benchmark://catalog resource first. It also advises preferring statement_id over content_hash and recommends fetching originalData via get_statement, giving clear directions for correct usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_creditsGet Credit BalanceA
Read-only
Inspect

Your remaining Bankstatemently credits — the processing quota, NOT credit/debit transactions. Use for: how many credits do I have, remaining pages, plan limits, quota, how many pages can I upload. 1 credit = 1 page of bank statement processing. Also reports your plan's operational limits (max pages per upload, max upload size, daily spend cap) so you can size a multi-file batch correctly before starting it.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds useful behavioral context beyond that: it reports not just the quota but also operational limits (max pages per upload, max upload size, daily spend cap), clarifying what the query returns for batch sizing. No contradictions 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 key distinction and purpose are front-loaded in the first sentence. The 'Use for' enumeration and operational-limit details add value for an agent handling natural-language queries, though a couple of phrases could be tightened. No wasted or redundant sentences.

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 zero-input, read-only tool with no output schema, the description fully covers the concept (credits = pages), the exact resource (quota, not transactions), and common use cases. An agent can confidently decide when to invoke this tool and what to expect from it.

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?

The schema has zero parameters, so there is nothing to document. Per the baseline for 0-parameter tools, the description did its job by explaining the semantics of the returned data (credits, limits, conversion to pages) rather than any input fields.

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 description states a specific resource ('remaining Bankstatemently credits — the processing quota') and explicitly disambiguates it from 'credit/debit transactions'. The '1 credit = 1 page' exchange rate and the mention of plan operational limits make the tool's scope unmistakable, even distinguishing it from sibling tools like list_transactions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit natural-language triggers ('Use for: how many credits do I have, remaining pages, plan limits, quota, how many pages can I upload') and a clear when-not ('NOT credit/debit transactions'). It stops short of naming an alternative sibling tool for transaction queries, but the exclusion is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_statementGet Statement DataA
Read-only
Inspect

Fetch the full converted data for a previously processed document. Use this after convert_statement returns a "processing" status, or to re-fetch results. output_format "json" (default) returns the data inline, renderable in chat. The other formats (csv, xlsx, qbo, xero) return a time-limited download link instead: present it as a normal link. data_mode selects which projection of the data you get: omit it for each output_format's existing default behavior. "normalized" is the cleaned, interpreted view; "original" includes each transaction's raw column values exactly as printed on the source PDF (originalData); "enhanced" is a reformatted view of the original columns (csv/xlsx only for now). Fetch data_mode: "original" when you plan to submit results to evaluate_benchmark — pass its originalData through verbatim; an absent originalData scores that benchmark's raw-fidelity dimension 0 for this document. Every response includes a "summary" field: use it as the single source of truth for what happened. If the conversation is not in English, translate it faithfully into the conversation language; never add details it doesn't contain. Never echo raw status values (e.g. "completed") or field names.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNooutput_format "json" only. Max transactions to return (default 500, capped at 2000, or 500 with data_mode "original").
offsetNooutput_format "json" only. Number of transactions to skip. Omit to start from the beginning.
data_modeNoOmit for each output_format's existing default behavior (json: normalized; csv/xlsx: the export route's own default). "normalized": the cleaned, interpreted data. "original": includes each transaction's raw column values as printed on the source PDF (originalData) — fetch this before submitting to evaluate_benchmark. "enhanced": a reformatted view of the original columns; only available for output_format csv/xlsx today. qbo/xero always export normalized data — omit data_mode (or pass "normalized" explicitly) for those formats.
document_idYesDocument ID (from convert_statement or list_statements)
output_formatNoOutput formatjson

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already mark readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral context: json returns inline data, other formats return time-limited links, the summary field is the source of truth, translation rules, and data_mode projections. No contradictions 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 long but every sentence carries essential information. It front-loads the primary purpose and usage context, then details format and data_mode behaviors. While it could be tightened, the complexity of the tool justifies the length, and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain return values. It does: json returns inline data, others return download links, summary is always present. It covers data_mode projections and pagination parameters are in the schema. However, it doesn't explicitly discuss pagination behavior (e.g., when to use offset), relying on the schema's limit/offset descriptions, which is a minor gap.

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?

Schema description coverage is 100%, so the baseline is 3. The description adds beyond schema: limit defaults (500, capped at 2000, 500 for original), offset usage, data_mode defaults per format, and the interaction with output_format. It clarifies the 'original' mode's role in evaluate_benchmark, which the schema hints at but doesn't fully explain.

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 description clearly states the tool fetches 'full converted data for a previously processed document,' distinguishing it from convert_statement (which processes) and list_statements (which lists). It also explicitly positions it as the follow-up after a processing status, giving a precise verb and resource.

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 provides explicit when-to-use guidance: 'Use this after convert_statement returns a processing status, or to re-fetch results.' It also details the workflow for evaluate_benchmark (fetch original data) and explains format-specific behavior, giving the agent clear context for choosing this tool over siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

group_byGroup TransactionsA
Read-only
Inspect

Group transactions by a dimension (month/category/counterparty/account/currency) and apply a metric to each group. Results are per-currency. The "counterparty" dimension keys on the printed counterparty, else a printed account mask (••1234), else the description's name tokens, so a rail word or reference number never splits one payee; a line with no key groups under "unknown". Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
filterNoSubset of transactions to operate on. All fields are optional and combined with AND logic.
metricYesMetric per group.
dimensionYesGrouping dimension.

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already establish a safe read (readOnlyHint=true, destructiveHint=false), so the bar is lower, and the description still adds real behavior: results are computed per-currency, the counterparty keying fallback chain (printed counterparty → account mask → name tokens), and the 'unknown' bucket for unkeyable lines. That is meaningful edge-case disclosure beyond the structured fields.

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?

Front-loads the core operation and dimension list, then layers scope and edge-case behavior. The counterparty sentence is long and dense, but every clause carries distinct information (fallback order, rail-word guard, unknown bucket), so it earns its length rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, dimensions, metric, default scope, and key edge cases, which is substantial for a nested-schema tool. Since there is no output schema, the only real gap is the result shape beyond 'per-currency' (group keys and metric values), so it is near-complete but not fully self-sufficient.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds semantics the schema does not: the default scope behavior and, critically, the keying logic behind the 'counterparty' dimension enum value, which the schema documents only as 'Grouping dimension'. It doesn't extend the filter fields, but the dimension and scope clarification lift it above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (group) and resource (transactions), then enumerates the exact dimensions and the per-group metric application. It is far more specific than a tautology, but it never distinguishes itself from close siblings like aggregate or time_series, so an agent still has to infer which grouping tool applies.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the default scope (all completed statements) and how to narrow it, and clarifies what the counterparty dimension keys on, which is genuine usage guidance. However, it offers no when-to-use/when-not-to-use framing against alternatives such as aggregate, top_n, or time_series, leaving selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_outflowsList Money That Left Your AccountsA
Read-only
Inspect

Every debit that left your accounts — in no confirmed transfer between your own accounts, and not a fee — each in ONE destination whose kind is also its next step: "own-account" (a printed account mask that names one of your accounts and no matched credit was found: ask for that account's statement), "account" (a printed account mask for an account outside your statements: request that account's statements; an in-kind move such as securities, crypto or escrow starts as a wire to that account and becomes visible only once the receiving statement is uploaded), "cash" (cash out: where it went cannot be followed, so the cumulative amount is the finding), "name" (a named party: review whether it was household spending) and "unknown" (nowhere the line says; kept visible, one entry per line, never merged). A destination carries the cumulative amount sent, per currency, never a balance. "mayBeOwnAccount" lists debits in an open candidate pair ("may be a move between your own accounts") apart, in no total. THE way to answer "did money disappear from my accounts, and where do I look next" — never answer it by summing list_transactions rows. Pass "dateRange" ({ from, to }, inclusive, YYYY-MM-DD) to report only debits in that range, for example from a separation date: transfers are matched over the whole scope first, so a transfer whose credit lies outside the range is still a transfer, never an outflow. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range (a scope date range also narrows what is matched — prefer "dateRange").

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
dateRangeNoReport only debits dated in this inclusive range. Omit to report every date.

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already cover the safe read-only profile, but the description adds substantive behavior beyond them: transfers are matched over the whole scope before any range filter, so a transfer whose credit falls outside the range is never an outflow; amounts are cumulative per currency, never a balance; 'unknown' entries are never merged; and 'mayBeOwnAccount' pairs are listed apart with no total. This is real operating semantics an agent cannot get from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Almost every clause is load-bearing (the destination-kind taxonomy and matching rules are needed to interpret results), but the content is delivered as one enormous run-on paragraph with nested quotes and no structure, so the most important usage guidance appears mid-paragraph rather than front-loaded. Informative but hard to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain the return shape, and it largely does: destination kinds with their follow-up actions, cumulative per-currency amounts, and the separate mayBeOwnAccount bucket. It stops short of fully specifying the response structure (ordering, grouping, counts), but is nearly complete for a tool of this complexity.

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?

Schema coverage is 100%, so the baseline would be 3, but the description adds meaning the schema does not: dateRange is inclusive YYYY-MM-DD, and the two date-range locations are not equivalent because a scope date range also narrows what gets matched, so dateRange is preferred. That is a genuine semantic distinction beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause states a concrete verb+resource ('Every debit that left your accounts') and explicitly carves out what it is not: not a confirmed transfer between one's own accounts and not a fee. It also distinguishes itself from siblings by forbidding the list_transactions summation route, though the core purpose is buried inside a dense enumeration of destination kinds rather than stated cleanly up front.

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?

Gives an explicit use case ('THE way to answer "did money disappear from my accounts, and where do I look next"'), an explicit anti-pattern ('never answer it by summing list_transactions rows'), and a concrete scenario for the dateRange parameter (a separation date). Alternatives and when-nots are both named, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_statementsList StatementsA
Read-only
Inspect

Browse your previously converted bank statements with pagination and optional status filter.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (1-100)
offsetNoPagination offset
statusNoFilter by status

TDQS

A4.2/5.0
Behavior4/5

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

The annotations already declare readOnlyHint, making it safe. The description adds details about pagination and optional status filtering, going beyond the annotations to describe expected behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that directly conveys the purpose and key features without unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema and the simple listing nature of the tool, the description sufficiently sets expectations. It does not detail return format, but that is not critical for a browse operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers all parameters with descriptions (limit, offset, status). The tool description only restates pagination and status filter, adding no new semantic information beyond the schema.

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 description clearly states the action (Browse) and resource (previously converted bank statements), and also mentions pagination and status filter, distinguishing it from other tools like convert_statement or get_statement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for listing previously converted statements, which differentiates it from converting or retrieving single statements. It does not explicitly name alternatives, but the context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_transactionsList TransactionsA
Read-only
Inspect

A transaction is a single line as printed on one account's statement — one side of any movement. Return a filtered list of transactions across your converted statements, capped at 50 rows. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range. Every response names the scope it actually evaluated (document count + covered date range) and each returned row carries its source document's content_hash so you can cite it. For "how many credits do I have" / processing quota / remaining pages, use get_credits instead — that is not a transaction.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum rows to return. Default 20, max 50.
orderNoSort direction. Default "desc" (largest amount / most recent date first). Only meaningful with sort_by.
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
filterNoSubset of transactions to operate on. All fields are optional and combined with AND logic.
sort_byNoSort the filtered set before applying limit. "amount" ranks by absolute magnitude (signed amounts are still returned). Omit for today's default (encounter order).

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnly/openWorld/destructive hints, so the description's job is to add output behavior — and it does: a hard 50-row cap, that every response echoes the evaluated scope (document count + date range), and that each row carries its source content_hash for citation. It doesn't say what happens when the result set exceeds the cap (truncation vs. error) or how to page beyond it.

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?

Four sentences, front-loaded with the core action and the cap, then scope behavior, then output provenance, then the sibling hand-off. The opening definition of 'transaction' is arguably expendable, but everything else earns its place and there is no repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so reasonably: it discloses the row cap, the echoed scope metadata, and the content_hash citation field. The remaining gap is pagination/overflow behavior for a tool that can plausibly exceed 50 rows across many statements.

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?

Schema coverage is 100%, so the baseline is 3; the description goes modestly beyond by framing scope as 'WHO × WHEN', stating its default (all completed statements) and the accounts/products + date-range axes, which clarifies the nested chip structure at a conceptual level. It adds little for filter/sort_by/order/limit beyond what the schema already spells out.

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?

States a specific verb and resource ('Return a filtered list of transactions across your converted statements, capped at 50 rows') and opens by defining what a transaction is, which disambiguates it from statements/transfers. It also explicitly carves out the get_credits use case, so an agent can separate it from at least one sibling without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear default ('scope defaults to all your completed statements') and the condition for narrowing ('pass scope to narrow to specific accounts/products and/or a date range'), plus an explicit when-not with a named alternative for quota questions (get_credits). It does not route to the other analytical siblings (aggregate, group_by, top_n, time_series), so it falls short of fully exhaustive guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_transfersMatch Transfers Between AccountsA
Read-only
Inspect

Match transfers between your own accounts. A transfer is TWO transactions — a debit leaving one of your accounts and a credit arriving in another — matched as two sides of the same movement (amount and date aligned); account-level successions (an account closing into a successor) are matched too. A payment to an outside party is not a transfer here: only movements with both sides visible in your statements are matched. THE way to answer any "was money moved between my accounts" / "did I transfer X" question — never try to answer a money-moved-between-accounts question with list_transactions + arithmetic; always call this tool instead. Ties come back as "ambiguous" until decided; call adjudicate_transfers to decide them. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range. Every response reports the match window (in days) it used, even when no transfers are found — a lack of matches is never silent about how hard it looked. To find large movements with NO matching counterpart in your other accounts — e.g. "trace transfers over $10,000; which ones leave without a known destination?" — pass "amountMin": reconciled pairs and successions are filtered to that floor, and the response gains an "unmatched" bucket of large movements (debits leaving, or unexplained credits arriving) with no matching pair, candidate, or succession. Omit amountMin for the ordinary reconciled-pairs answer.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
amountMinNoInclusive minimum absolute amount. When present, transfers/accountSuccessions are floored to this amount and the response gains an "unmatched" bucket of large movements with no matching counterpart. Omit for the ordinary reconciled-pairs answer.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare this a safe read, and the description layers on substantial non-obvious behavior: ties are returned as 'ambiguous' until adjudicated, scope defaults to all completed statements, every response reports its match window even when empty, and amountMin adds an 'unmatched' bucket. These are behavioral traits an agent could not infer from the schema or 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?

It is long and dense with parentheticals and quoted examples, but it is front-loaded with the core purpose and nearly every sentence carries distinct information (definition, exclusions, routing, defaults, edge behavior). Slightly overstuffed, but not padded with filler.

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 nested, zero-required-param tool with no output schema, the description covers everything an agent needs: scope semantics, the ambiguity/adjudication workflow, the match-window reporting guarantee, and the amountMin-driven 'unmatched' bucket. Return-value behavior is explained in prose, compensating for the absent output schema.

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?

With 100% schema coverage the baseline is 3, but the description genuinely adds meaning beyond the schema: it explains the default scope ('all your completed statements'), what narrowing via scope does, and — most valuably — exactly how amountMin changes results (flooring reconciled pairs/successions and introducing an 'unmatched' bucket), which the schema's one-line description only gestures at.

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 description gives a precise verb+resource ('Match transfers between your own accounts') and then defines what counts as a transfer (two sides: a debit leaving one account and a credit arriving in another, amount and date aligned), including account successions. It explicitly carves out what is NOT a transfer ('a payment to an outside party is not a transfer here'), making it trivially distinguishable from list_transactions.

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 states an explicit rule: 'THE way to answer any "was money moved between my accounts" question — never try to answer ... with list_transactions + arithmetic; always call this tool instead.' It also routes the follow-up decision to a named sibling ('call adjudicate_transfers to decide' ambiguous ties) and gives conditional guidance for amountMin versus omitting it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rate_statementRate Statement ConversionA
Destructive
Inspect

Report how well a previously converted bank statement was parsed: submit a 1-5 rating, optionally with structured feedback at any rating. Your rating counts toward the average ratings shown on bankstatemently.com. Calling this again for the same document updates your existing rating without clearing feedback already submitted for it. Returns the stored rating state in the response — there is no separate tool to read your own rating back. Every response includes a "summary" field: use it as the single source of truth for what happened.

ParametersJSON Schema
NameRequiredDescriptionDefault
ratingYes1-5 star rating for this conversion
feedbackNoFree-text feedback.
document_idYesDocument ID (from convert_statement or list_statements)
feedback_categoriesNoStructured feedback categories.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations declare destructiveHint=true, readOnlyHint=false, openWorldHint=true; the description usefully qualifies the destructive surface by stating a repeat call 'updates your existing rating without clearing feedback already submitted for it', and it discloses the public-average effect on bankstatemently.com. Combined with the return-value and summary-field guidance, it adds real behavioral context beyond the annotations, though it omits auth/rate-limit details.

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?

Front-loaded with the core action (rate a converted statement), followed by the most decision-relevant edge cases (repeat-call semantics, no read-back tool, summary field). The bankstatemently.com detail is slightly peripheral but the prose remains compact with no filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating tool with no output schema, the description covers the gap by explaining that the stored rating state is returned and that a 'summary' field is the source of truth. It also handles the idempotency/persistence question an agent would otherwise have to guess, leaving only minor return-shape detail unspecified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all four parameters, and the baseline is 3. The description's only added semantics are 'at any rating' for the optional feedback and its restatement of the 1-5 scale, which is marginal value over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Report how well a previously converted bank statement was parsed' with the concrete action of submitting a 1-5 rating plus optional structured feedback. The purpose is unambiguous and distinct from conversion siblings like convert_statement, though it does not name a sibling by name in the description text (only the schema's document_id field references convert_statement/list_statements).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context: 'previously converted bank statement' implies use after convert_statement, and 'optionally with structured feedback at any rating' tells the agent feedback is not gated on rating value. It also clarifies the repeat-call behavior (updates existing rating) and notes there is no separate read-back tool, but stops short of explicit when-not-to-use or naming an alternative rating path.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

request_uploadRequest Upload URLAInspect

Mint a single-use upload URL for pushing a conversation-attached PDF to Bankstatemently before converting it. Use this ONLY when you have no other way to reference the attached file (no pdf_file/pdf_url equivalent for this host) — e.g. a code-execution sandbox that can see the file on disk but has no URL for it. Playbook: (1) check your sandbox's uploads/attachments directory first — if the file isn't there yet, the mount can lag behind the conversation; ask the user to re-attach or wait a moment and check again before calling this tool. (2) Call request_upload to get upload_url and upload_id. (3) PUT the raw PDF bytes to upload_url with header Content-Type: application/pdf, e.g.: curl -X PUT "<upload_url>" -H "Content-Type: application/pdf" --data-binary @<path-to-file>. (4) Once the PUT succeeds, call convert_statement with upload_id set to the same value — never pdf/pdf_url/pdf_file for this flow. The URL and token are single-use and expire quickly; call request_upload again for a fresh one if the PUT fails partway through — never retry a failed PUT against the same URL. If the PUT fails with a network error or a "host not allowed"-style denial, the sandbox is likely blocking outbound requests to api.bankstatemently.com — tell the user to add api.bankstatemently.com to their host's code-execution allowed-domains setting (on claude.ai: Settings → Capabilities → Code execution) and retry. To convert several statements at once, pass count (1-100) instead of calling this tool once per file: the response returns "uploads", an array of that many { upload_id, upload_url } pairs — PUT each file to its own upload_url, then make ONE convert_statement call with upload_ids set to every upload_id. Free to use — no credits consumed (conversion itself still costs credits, same as any other convert_statement call).

ParametersJSON Schema
NameRequiredDescriptionDefault
countNoBatch size — mint this many independent single-use upload URLs in one call instead of calling request_upload once per file. When set, the response returns "uploads": an array of that many { upload_id, upload_url } pairs. Omit for the default single-URL response.

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the minimal annotations, the description discloses that the URL and token are single-use and expire quickly, that no credits are consumed by this step, and that a failed PUT must not be retried against the same URL. This gives agents clear expectations about the operation's side effects and limitations.

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 long, but nearly every sentence carries operational value, including the playbook, error handling, and batching instructions. It is organized and readable; the length is justified by the complexity of the workflow.

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?

Even though there is no output schema, the description fully covers the expected response fields (upload_id, upload_url, and batches of uploads), the exact HTTP PUT step, the relationship to convert_statement, and failure handling—so an agent has everything needed to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Though there is only one parameter, the description significantly enriches the schema by explaining what count does, why batching is preferable, what the uploads response array contains, and what occurs when count is omitted.

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 description clearly states a specific action—minting a single-use upload URL for a conversation-attached PDF—and explicitly distinguishes this tool from alternatives by saying to use it only when no pdf_file/pdf_url equivalent exists.

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?

The description gives explicit when-to-use and when-not-to-use guidance, a numbered playbook, retry rules, batch usage via count, and troubleshooting steps for blocked outbound requests. It also names the follow-up tool, convert_statement, and explains how upload_id must be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

time_seriesTransaction Time SeriesB
Read-only
Inspect

Compute a time series by grouping transactions into week or month buckets and applying a metric — useful for trends. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
bucketYesBucket size.
filterNoSubset of transactions to operate on. All fields are optional and combined with AND logic.
metricYesMetric per bucket.

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and closed-world, so the safety profile is covered. The description adds one genuine behavioral fact beyond that — the default scope spans all completed statements — but says nothing about output shape, bucketing edge cases, or empty-result behavior.

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?

Two sentences, front-loaded with the core operation and followed by the default/override behavior. No filler, though the em-dash aside about trends is marginal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-scope analytical tool with no output schema, the description covers the input contract adequately via the schema but never hints at the return shape (e.g. bucketed metric series) or how buckets without data behave. Adequate but with a clear gap for an agent reasoning about results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents scope, bucket, metric, and filter semantics in detail. The description only restates the scope narrowing behavior and the week/month bucketing, adding no syntax or format detail beyond the schema; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource combination: grouping transactions into week/month buckets and applying a metric, plus the intent ('useful for trends'). It is clear what the tool computes, though it does not explicitly differentiate itself from siblings like aggregate, group_by, or top_n.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives useful default context ('scope defaults to all your completed statements; pass scope to narrow'), which tells the agent what happens when scope is omitted. However, it never says when to prefer this over aggregate, group_by, or top_n, so sibling selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

top_nTop Transaction GroupsA
Read-only
Inspect

Return the top N groups ranked by metric (descending), per-currency for monetary metrics. Scope defaults to all your completed statements; pass "scope" to narrow to specific accounts/products and/or a date range.

ParametersJSON Schema
NameRequiredDescriptionDefault
nYesNumber of top groups to return.
scopeNoOptional structural scope (WHO × WHEN). Omit to search across all your completed statements. "accounts" is a list of account/product chips ({ kind: "account" | "product", id }, the id of an account descriptor or product returned by a tool); "dateRange" bounds by transaction date (YYYY-MM-DD).
filterNoSubset of transactions to operate on. All fields are optional and combined with AND logic.
metricYesMetric to rank by.
dimensionYesGrouping dimension.

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already establish this is a safe, non-destructive, closed-world read (readOnlyHint=true, destructiveHint=false, openWorldHint=false). The description adds real context beyond that: results are ordered descending, monetary metrics are split per-currency, and the default scope is all completed statements rather than an arbitrary set. It does not cover tie-handling or result size behavior, but the annotations lower the bar.

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?

Two sentences, front-loaded with the core behavior (top N, descending, per-currency) before the scope note. Efficient overall, though the trailing 'pass "scope" to narrow...' largely restates what the schema's scope description already says.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only ranked-aggregation tool with 100% schema coverage and annotations covering the safety profile, the description supplies what structured fields cannot: default scope and ordering/currency semantics. The one gap is that with no output schema, the shape of each returned group (dimension value + metric value) is never described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents n, dimension, metric, scope, and filter in detail; baseline is 3. The description adds only the per-currency semantics for monetary metrics, which is useful but marginal against an already exhaustive schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: return the top N groups ranked by a chosen metric in descending order, with per-currency partitioning for monetary metrics. This is clearly a ranked-aggregation tool, distinct in kind from list_* tools, but it never names or contrasts with the nearest siblings (group_by, aggregate, time_series), so differentiation relies on inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It discloses the default scope (all completed statements) and says how to narrow it via `scope`, which tells the agent when the scope parameter matters. However, it gives no guidance on when to reach for top_n versus group_by, aggregate, or time_series, so the routing decision between ranked aggregates is left implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv2.1.0
    • Changedgroup_by1 field changed
      • changedInput schema / properties / dimension / enum
        Previous value: -[
        -  "month",
        -  "category",
        -  "merchant",
        -  "account",
        -  "currency"
        -]New value: +[
        +  "month",
        +  "category",
        +  "counterparty",
        +  "account",
        +  "currency"
        +]
    • Addedlist_outflows
    • Changedrate_statement5 fields changed
      • removedInput schema / properties / export_format
        Removed value: -{
        -  "description": "Which output format you exported this conversion to (csv, xlsx, qbo, or xero).",
        -  "enum": [
        -    "csv",
        -    "xlsx",
        -    "qbo",
        -    "xero"
        -  ],
        -  "type": "string"
        -}
      • changedInput schema / properties / feedback / description
        Previous value: -"Free-text feedback. Only accepted when rating is 3 or below."New value: +"Free-text feedback."
      • changedInput schema / properties / feedback_categories / description
        Previous value: -"Structured feedback categories. Only accepted when rating is 3 or below."New value: +"Structured feedback categories."
      • removedInput schema / properties / use_case
        Removed value: -{
        -  "description": "Tags describing what you use the converted data for.",
        -  "items": {
        -    "enum": [
        -      "bookkeeping",
        -      "tax_preparation",
        -      "financial_analysis",
        -      "audit_compliance",
        -      "reconciliation",
        -      "personal_finance",
        -      "data_migration",
        -      "other"
        -    ],
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedInput schema / properties / use_case_other
        Removed value: -{
        -  "description": "Free-text use case, for when \"other\" is among the use_case tags.",
        -  "maxLength": 500,
        -  "type": "string"
        -}
    • Changedtop_n1 field changed
      • changedInput schema / properties / dimension / enum
        Previous value: -[
        -  "month",
        -  "category",
        -  "merchant",
        -  "account",
        -  "currency"
        -]New value: +[
        +  "month",
        +  "category",
        +  "counterparty",
        +  "account",
        +  "currency"
        +]
  2. 8 tool updatesv2.0.0
    • Addedadjudicate_transfers
    • Changedaggregate5 fields changed
      • addedInput schema / properties / filter / additionalProperties
        Added value: +false
      • removedInput schema / properties / filter / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedcompare7 fields changed
      • addedInput schema / properties / filterA / additionalProperties
        Added value: +false
      • removedInput schema / properties / filterA / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedInput schema / properties / filterB / additionalProperties
        Added value: +false
      • removedInput schema / properties / filterB / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedgroup_by5 fields changed
      • addedInput schema / properties / filter / additionalProperties
        Added value: +false
      • removedInput schema / properties / filter / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedlist_transactions5 fields changed
      • addedInput schema / properties / filter / additionalProperties
        Added value: +false
      • removedInput schema / properties / filter / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedlist_transfers3 fields changed
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedtime_series5 fields changed
      • addedInput schema / properties / filter / additionalProperties
        Added value: +false
      • removedInput schema / properties / filter / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedtop_n5 fields changed
      • addedInput schema / properties / filter / additionalProperties
        Added value: +false
      • removedInput schema / properties / filter / properties / accounts
        Removed value: -{
        -  "description": "Account number slugs to include.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / scope / description
        Previous value: -"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips (kind + identityKey); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."New value: +"Optional structural scope (WHO × WHEN). Omit to search across all your completed statements. \"accounts\" is a list of account/product chips ({ kind: \"account\" | \"product\", id }, the id of an account descriptor or product returned by a tool); \"dateRange\" bounds by transaction date (YYYY-MM-DD)."
      • changedInput schema / properties / scope / properties / accounts / description
        Previous value: -"Account/product chips (kind + identityKey) to scope to. Empty = all accounts."New value: +"Account/product id chips (kind + id) to scope to. Empty = all accounts."
      • changedInput schema / properties / scope / properties / accounts / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "anchorContentHash": {
        -        "description": "Document-anchored lookup when present (results page); omit for a user-scoped lookup (workspace surfaces).",
        -        "type": "string"
        -      },
        -      "identityKey": {
        -        "description": "Canonical account identity key (accountIdentityKey), never a raw DB UUID.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "account",
        -        "description": "This chip addresses a single account.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "identityKey": {
        -        "description": "Product slug.",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "product",
        -        "description": "This chip addresses a product and expands to its child accounts.",
        -        "type": "string"
        -      },
        -      "label": {
        -        "description": "Display label for this chip.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "identityKey"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The account id: the `id` of an account descriptor returned by a tool, or of a statement tool `accounts[]` entry.",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "account",
        +        "description": "This chip addresses a single account.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "description": "The product id: the `id` of a product returned by a statement tool (`get_statement` / `convert_statement`, `products[].id`).",
        +        "format": "uuid",
        +        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "product",
        +        "description": "This chip addresses a product and expands to its child accounts.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "id"
        +    ],
        +    "type": "object"
        +  }
        +]
  3. 16 tool updatesv0.1.0
    • First observedaggregate
    • First observedcategorize_statement
    • First observedcompare
    • First observedconvert_statement
    • First observeddismiss_statement
    • First observedevaluate_benchmark
    • First observedget_credits
    • First observedget_statement
    • First observedgroup_by
    • First observedlist_statements
    • First observedlist_transactions
    • First observedlist_transfers
    • First observedrate_statement
    • First observedrequest_upload
    • First observedtime_series
    • First observedtop_n

TDQS

A3.9/5.0

Scored across 18 tools

Disambiguation4/5

Each tool targets a distinct resource or action, but the five transaction-analytics tools (aggregate, compare, time_series, group_by, top_n) overlap in scope/metric handling and require careful reading to choose correctly. The transfer tools (list_transfers, adjudicate_transfers, list_outflows) also need deliberate distinction, though descriptions clarify their boundaries.

Naming Consistency4/5

All names use snake_case, and most follow a verb_noun pattern (list_transactions, get_statement, convert_statement). Minor deviations like bare verbs (aggregate, compare) and non-verb constructions (time_series, group_by, top_n) break the pattern slightly but remain readable and consistent in casing.

Tool Count3/5

18 tools is on the heavy side for the domain. Several analytics tools (aggregate, compare, time_series, group_by, top_n) could potentially be consolidated into a parameterized analysis tool, suggesting some over-fragmentation, though each tool does cover a distinct operation.

Completeness4/5

The surface covers conversion, retrieval, categorization, analytics, transfer matching, upload, credits, rating, and benchmark evaluation, giving strong lifecycle coverage. Minor gaps remain: no direct account-listing tool and dismiss_statement is a soft hide rather than a hard delete, but these are workable.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Financial data infrastructure for AI agents. Connect to a startup's books to read live P&L and bank balances, review and reclassify transactions, manage the chart of accounts, and connect banking sources.
    -
  • A
    license
    A
    quality
    D
    maintenance
    Converts PDF bank statements into structured data (Markdown, JSON, CSV, JSONL) with verified transactions and balance checks, enabling agents to audit numbers.
    5
    14 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Deterministic bank-statement parsing for AI agents: messy CSV/OFX exports to clean, categorized ledger rows. In-memory only, no storage, no external calls, no LLM in the loop.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Converts customer-supplied PDF bank statements into checked Excel, CSV, or JSON with balance validation. Runs locally with your own MainBook API key or against MainBook's hosted endpoint, and it never connects to bank accounts.
    5
    MIT