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

17 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/merchant/account/currency) and apply a metric to each group. Results are per-currency. 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.7/5.0
Behavior4/5

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

Annotations already establish read-only, non-destructive behavior. Beyond that, the description adds genuinely useful traits: results are returned per-currency (not merged), and the default scope spans all completed statements unless narrowed. These are non-obvious behaviors not derivable from annotations or schema.

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, front-loaded with the core operation followed by the two non-obvious behaviors (per-currency results, default scope). No padding or repetition.

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 nested scope/filter objects, 4 parameters, and no output schema, the description should carry more weight on result shape. It notes per-currency results but never explains what the metric is applied to (e.g., transaction amount) or how groups are returned, leaving a meaningful gap for an output-less 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 dimension, metric, scope, and filter are already fully documented, including the enum values. The description restates the dimension list and the scope default but adds no syntax or semantics beyond the schema, so the baseline of 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 and resource ('Group transactions') and enumerates the five grouping dimensions plus the metric concept, so the operation is unambiguous. It does not, however, distinguish itself from closely related siblings like aggregate, top_n, or time_series, which an agent must infer.

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, which is useful operational context. But it never says when to prefer this tool over the many sibling aggregation tools (aggregate, top_n, compare, time_series), and gives no exclusions or prerequisites.

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 ConversionAInspect

Report how well a previously converted bank statement was parsed: submit a 1-5 rating, optionally with structured feedback (only accepted when the rating is 3 or below) and use-case tags. 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. Only accepted when rating is 3 or below.
use_caseNoTags describing what you use the converted data for.
document_idYesDocument ID (from convert_statement or list_statements)
export_formatNoWhich output format you exported this conversion to (csv, xlsx, qbo, or xero).
use_case_otherNoFree-text use case, for when "other" is among the use_case tags.
feedback_categoriesNoStructured feedback categories. Only accepted when rating is 3 or below.

TDQS

A4.5/5.0
Behavior5/5

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

The description discloses key behaviors beyond the annotations: it states that re-calling updates the existing rating without clearing feedback, that the response includes the stored rating state, and that every response contains a 'summary' field to use as the single source of truth. This adds significant context that annotations do not provide, and there is no contradiction.

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 compact, front-loaded with the core purpose, and each sentence adds value—covering update semantics, return behavior, and the summary field. No redundancy or filler; it is efficiently written.

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 has 7 parameters but only 2 required, and no output schema, the description adequately covers what the agent needs: it explains the response contains the stored rating state and a 'summary' field, and clarifies update semantics. This is sufficient for an agent to call it correctly without further lookup.

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 baseline is 3. The description adds some context about feedback being conditionally accepted and the update behavior, but most parameter details are already in the schema. It does not meaningfully compensate beyond what the schema already explains, so a 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 states a specific verb and resource: 'Report how well a previously converted bank statement was parsed' and clarifies it involves submitting a rating. It distinguishes from siblings by noting there is no separate tool to read your rating back, making its role unique among the listed tools.

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?

It gives clear context on when to use it (for rating a conversion) and clarifies that calling again updates the rating, which is useful for repeated submissions. It does not explicitly mention when not to use it or name alternatives like evaluate_benchmark, but the description implies the specific scenario (rating a converted statement) sufficiently.

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 declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so safety is covered. The description adds genuinely new behavior: default ordering is descending, monetary metrics are reported per-currency, and scope defaults to all completed statements unless narrowed.

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, and every clause carries information. Slightly compressed phrasing like 'per-currency for monetary metrics' costs a little immediacy but no real waste.

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 5-parameter tool with a deeply nested scope/filter schema and no output schema, the description covers scoping and defaults but says nothing about what is returned (e.g. the shape of each ranked group). An agent knows how to call it, but not fully what to expect back.

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 disclosing the descending sort order for the ranking, the per-currency split for monetary metrics, and the default scope behavior for the optional 'scope' parameter.

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 description gives a specific verb+resource: 'Return the top N groups ranked by metric (descending)'. This clearly separates it from the coarser analytical siblings like group_by and aggregate, though it never names those siblings explicitly to route the agent.

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 states the default scope behavior and that 'scope' narrows results, which is useful context. However, there is no explicit guidance on when to choose top_n over group_by, aggregate, or compare, so the when-to-use decision 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.

Tool Schema Changelog

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

  1. 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"
        +  }
        +]
  2. 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 17 tools

Disambiguation4/5

The analytics family (aggregate, group_by, top_n, compare, time_series) has genuine conceptual overlap, but each tool's description carves out a distinct operation (single metric vs. grouped dimensions vs. ranking vs. two-group comparison vs. time buckets). The transfer/transaction tools (list_transfers, list_transactions, adjudicate_transfers) are carefully distinguished, and get_credits explicitly disclaims transaction duties. A few analytics tools could still be misselected without reading carefully, but boundaries are mostly clear.

Naming Consistency4/5

Naming is uniformly lower_snake_case and mostly verb_noun (list_statements, get_statement, convert_statement, categorize_statement, rate_statement, dismiss_statement, request_upload, evaluate_benchmark). The analytics tools break the pattern as bare verbs/nouns (aggregate, group_by, top_n, compare, time_series), which is a minor stylistic deviation but still readable and consistent within its cluster.

Tool Count4/5

At 17 tools this is slightly above the ideal 3-15 band, but the domain is genuinely broad (upload, conversion, retrieval, categorization, rating, benchmarking, transfer reconciliation, analytics, quota). Nearly every tool maps to a distinct user workflow, and the five-metric analytics set is the only area that could conceivably be consolidated. Still reasonable rather than bloated.

Completeness4/5

The surface covers the full lifecycle: upload, convert, fetch, list, soft-dismiss, categorize, rate, benchmark-evaluate, plus transaction querying, transfer reconciliation, analytics, and quota checks. The main minor gap is the absence of a dedicated tool to enumerate accounts/products even though analytics tools accept an accounts/products scope, which an agent must discover indirectly via list_statements or get_statement.

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
    9 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
    A
    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