From 0551dd62bce4b0da0abe80396305dcbc874ece58 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 02:10:22 +0000 Subject: [PATCH] docs: sync MCP docs with retired resources and consolidated tools --- guides/multi-agent-reviewer.mdx | 2 +- guides/on-demand-analysis.mdx | 2 +- guides/openclaw-recurring-workflows.mdx | 2 +- guides/single-routine-reviewer.mdx | 6 +- guides/tracking-subscriptions.mdx | 10 +- mcp/overview.mdx | 43 ++++-- mcp/reference/categorization.mdx | 2 +- mcp/reference/conventions.mdx | 4 +- mcp/reference/overview.mdx | 55 ++++--- mcp/reference/reports.mdx | 2 +- mcp/reference/rules-write.mdx | 183 ++++++++++-------------- mcp/reference/rules.mdx | 2 +- mcp/reference/transactions-write.mdx | 28 +++- mcp/reference/transactions.mdx | 19 ++- mcp/tools.mdx | 49 ++----- transactions/overview.mdx | 2 +- transactions/review-workflow.mdx | 4 +- transactions/tags.mdx | 2 +- 18 files changed, 210 insertions(+), 207 deletions(-) diff --git a/guides/multi-agent-reviewer.mdx b/guides/multi-agent-reviewer.mdx index f6255cf..f568082 100644 --- a/guides/multi-agent-reviewer.mdx +++ b/guides/multi-agent-reviewer.mdx @@ -39,7 +39,7 @@ can work them. Each run: -1. `count_transactions(tags=["needs-review"])`. If zero, submit a report +1. `query_transactions(tags=["needs-review"], count_only=true)`. If zero, submit a report and stop. 2. `query_transactions(tags=["needs-review"], fields="core,category", limit=50)`. diff --git a/guides/on-demand-analysis.mdx b/guides/on-demand-analysis.mdx index db22f35..67bd96d 100644 --- a/guides/on-demand-analysis.mdx +++ b/guides/on-demand-analysis.mdx @@ -103,7 +103,7 @@ include pending transactions." I'll: 1. Call list_categories to find the grocery category slugs available. 2. Call list_users to get the user IDs. -3. Call count_transactions with category_detailed=FOOD_AND_DRINK_GROCERIES, +3. Call query_transactions(count_only=true) with category_detailed=FOOD_AND_DRINK_GROCERIES, start_date=2026-01-01, end_date=2026-03-31, pending=false. If the count is manageable (<500), proceed. 4. Call query_transactions with the same filters, paginated as needed. diff --git a/guides/openclaw-recurring-workflows.mdx b/guides/openclaw-recurring-workflows.mdx index effa2a5..2c7be90 100644 --- a/guides/openclaw-recurring-workflows.mdx +++ b/guides/openclaw-recurring-workflows.mdx @@ -54,7 +54,7 @@ On each run: 1. Call `create_session` with purpose "12h triage — ". Save the returned session_id for all subsequent write calls. -2. Call `count_transactions(tags=["needs-review"])`. +2. Call `query_transactions(tags=["needs-review"], count_only=true)`. - If the count is 0: call `submit_report` with title "Triage check — queue empty." and stop. - If the count is 1–150: proceed to step 3. diff --git a/guides/single-routine-reviewer.mdx b/guides/single-routine-reviewer.mdx index 5e2a4d5..f311992 100644 --- a/guides/single-routine-reviewer.mdx +++ b/guides/single-routine-reviewer.mdx @@ -11,7 +11,7 @@ Every iteration the agent does the same four things: - Call `count_transactions(tags=["needs-review"])` to see how many transactions are pending. If the count is very large, the agent narrows by date or account. + Call `query_transactions(tags=["needs-review"], count_only=true)` to see how many transactions are pending. If the count is very large, the agent narrows by date or account. Call `query_transactions(tags=["needs-review"], fields="core,category", limit=30)` to pull a page worth of detail. Keep batches small — one batch is the unit the agent reasons over end-to-end. @@ -77,7 +77,7 @@ Step-by-step, every run: 1. Call `get_sync_status`. If any connection has `status = "error"` or `status = "pending_reauth"`, note it in the report and skip those accounts' transactions. -2. Call `count_transactions(tags=["needs-review"])`. If the count is over +2. Call `query_transactions(tags=["needs-review"], count_only=true)`. If the count is over 200, narrow the batch by the most recent 7 days. 3. Call `query_transactions(tags=["needs-review"], fields="core,category", limit=30)`. Work in batches of 30. @@ -129,4 +129,4 @@ Until you hit one of those, keep it simple. - [Breadbox in a nutshell](/guides/breadbox-in-a-nutshell) — the primitives the loop rests on. - [Review workflow](/transactions/review-workflow) — the full spec for the `needs-review` tag and its seeded rule. -- [MCP tools](/mcp/tools) — reference for `query_transactions`, `count_transactions`, and `update_transactions`. +- [MCP tools](/mcp/tools) — reference for `query_transactions` (including its `count_only` mode) and `update_transactions`. diff --git a/guides/tracking-subscriptions.mdx b/guides/tracking-subscriptions.mdx index 7ada9ba..aa486bb 100644 --- a/guides/tracking-subscriptions.mdx +++ b/guides/tracking-subscriptions.mdx @@ -74,10 +74,12 @@ To make every future charge from a merchant join a series on sync, use the [`ass The same surface is available over MCP, which is how a scheduled reviewer agent can keep your subscription list tidy: -- `list_series` (optionally `status=candidate`) to find series awaiting a verdict, then `review_series` to confirm, reject, pause, or cancel. -- `get_series` to inspect one series and the evidence behind it. -- `assign_series` to create a series detection missed, or back-link charges to an existing one. -- `add_series_tag` / `remove_series_tag` to tag a subscription and its members. +- `list_series` to scan the current series; `get_series` to inspect one. +- `assign_series` to mint a series an agent missed, or back-link transactions to an existing one. +- `update_series` to rename a series or change its type (`subscription`, `bill`, `loan`, `other`). +- `unlink_series_transactions` to detach charges that don't belong. + +When you want every future charge from a merchant to land in a series automatically, encode that as an `assign_series` rule via `create_transaction_rule` rather than calling `assign_series` repeatedly. See the [MCP tools](/mcp/tools#series-subscriptions) page for the agent-facing summary. diff --git a/mcp/overview.mdx b/mcp/overview.mdx index 5a13c7f..3ec615c 100644 --- a/mcp/overview.mdx +++ b/mcp/overview.mdx @@ -20,25 +20,38 @@ Breadbox supports two ways to connect an MCP client. ## What the MCP server exposes -The server advertises two capability types: **tools** and **resources**. +The server advertises a single capability type: **tools**. Earlier versions of Breadbox also published a parallel `breadbox://` resources surface, but that has been retired — every read is now a tool call, including the orientation reads and the operating-guidance docs. -**Tools** are callable functions the agent uses to query and change your data — listing accounts, searching transactions, counting results, categorizing, tagging, creating rules, triggering syncs, and submitting reports. Around 40 tools in total; see the [MCP Reference](/mcp/reference/overview) tab for the complete enumeration, or [MCP tools](/mcp/tools) for a human walkthrough of the ones you're most likely to grant access to. +**Tools** are callable functions the agent uses to query and change your data — listing accounts, searching transactions, counting results, categorizing, tagging, creating rules, triggering syncs, and submitting reports. The registry has 35 tools. See the [MCP Reference](/mcp/reference/overview) tab for the complete enumeration, or [MCP tools](/mcp/tools) for a human walkthrough of the ones you're most likely to grant access to. -**Resources** are passive context documents the agent can read to orient itself before taking action. +### Orientation reads -| Resource URI | What it contains | +The first thing a connecting agent should do is orient itself with the bounded reference reads — each one is a dedicated tool: + +| Tool | What it returns | |---|---| -| `breadbox://overview` | Live dataset summary organized as scope (counts, date range), freshness (last sync, ingest signals, errored connections), and backlog (needs-review and unmapped counts), plus the household roster | -| `breadbox://accounts` | Bank accounts (checking, savings, credit cards, loans, investments) with balances, institution names, and currency | -| `breadbox://categories` | Two-level category taxonomy keyed by slug; the source of valid `category_slug` values | -| `breadbox://tags` | Current tag vocabulary keyed by slug; the `needs-review` tag is the review-queue handle | -| `breadbox://users` | Household members with their roles (admin, editor, viewer) | -| `breadbox://sync-status` | Per-connection sync status and last-sync timestamps | -| `breadbox://review-guidelines` | Guidelines for reviewing transactions and creating categorization rules; editable from the MCP Settings page | -| `breadbox://report-format` | Templates and formatting rules for agent-submitted reports; editable from the MCP Settings page | -| `breadbox://rule-dsl` | Reference grammar for transaction rules: condition fields, action types, priority bands, and provider quirks | - -The `breadbox://overview` resource gives the agent ambient context about your household's financial state without requiring a round-trip tool call. An agent that reads it first knows how big the dataset is, whether it's currently in sync, and what's open in the review backlog — before it asks a single question. +| `get_overview` | Live dataset summary organized as scope (counts, date range), freshness (last sync, ingest signals, errored connections), and backlog (needs-review and unmapped counts), plus the household roster | +| `list_accounts` | Bank accounts (checking, savings, credit cards, loans, investments) with balances, institution names, and currency | +| `list_categories` | Two-level category taxonomy keyed by slug; the source of valid `category_slug` values | +| `list_tags` | Current tag vocabulary keyed by slug; the `needs-review` tag is the review-queue handle | +| `list_users` | Household members with their roles (admin, editor, viewer) | +| `get_sync_status` | Per-connection sync status and last-sync timestamps | +| `list_transaction_rules` | The active rule roster | + +Calling `get_overview` first gives the agent ambient context about your household's financial state — how big the dataset is, whether it's currently in sync, and what's open in the review backlog — before it asks a single question. + +### Operating guidance + +The near-static markdown that teaches an agent how to drive the server (the rule DSL grammar, the review playbook, report-format conventions) is served by a single `get_reference` tool, keyed by `kind`: + +| `kind` | What it returns | +|---|---| +| `instructions` | Data model overview and how the tool surface is organized | +| `rule-dsl` | Reference grammar for transaction rules: condition fields, action types, priority bands, and provider quirks | +| `review-guidelines` | Guidelines for reviewing transactions and creating categorization rules; editable from the MCP Settings page | +| `report-format` | Templates and formatting rules for agent-submitted reports; editable from the MCP Settings page | + +`get_reference` returns markdown. The `instructions`, `review-guidelines`, and `report-format` documents reflect any operator customization made on the MCP Settings page; `rule-dsl` is the fixed grammar. ## What agents can do diff --git a/mcp/reference/categorization.mdx b/mcp/reference/categorization.mdx index ca4abd9..475f785 100644 --- a/mcp/reference/categorization.mdx +++ b/mcp/reference/categorization.mdx @@ -82,4 +82,4 @@ Category writes follow the precedence **user > agent > rule**. If a transaction' To categorize in bulk by applying a stored rule to existing transactions, use `apply_rules`. Pass a `rule_id` to run one rule in isolation, or omit it to run the full active-rule pipeline in priority order. -See [Rules (write)](/mcp/reference/rules-write) for the other rules write tools (`create_transaction_rule`, `update_transaction_rule`, `delete_transaction_rule`, `batch_create_rules`). +See [Rules (write)](/mcp/reference/rules-write) for the other rules write tools (`create_transaction_rule` — accepts a `rules` array for batch creation, `update_transaction_rule`, `delete_transaction_rule`). diff --git a/mcp/reference/conventions.mdx b/mcp/reference/conventions.mdx index 27f0f7d..eb58bc8 100644 --- a/mcp/reference/conventions.mdx +++ b/mcp/reference/conventions.mdx @@ -118,7 +118,7 @@ Comma-separated values in `search` are ORed. `search=starbucks,dunkin` matches e ## Tag filters -`query_transactions` and `count_transactions` accept two tag filters: +`query_transactions` accepts two tag filters (also honored when called with `count_only: true`): - `tags` — array, AND semantics. All tags must be present. - `any_tag` — array, OR semantics. At least one tag must match. @@ -140,6 +140,6 @@ The review queue is just `tags=["needs-review"]`. - List tools default to `limit=50`, max 500. - `update_transactions` caps at 50 operations per call. -- `batch_create_rules` caps at 100 items. +- `create_transaction_rule` accepts 1–100 rules per call via its `rules` array. Exceeding a cap returns an error; the server does not silently truncate. diff --git a/mcp/reference/overview.mdx b/mcp/reference/overview.mdx index f9e4938..f26625b 100644 --- a/mcp/reference/overview.mdx +++ b/mcp/reference/overview.mdx @@ -52,37 +52,50 @@ Entity IDs in MCP responses are compact 8-character base62 strings (e.g., `k7Xm9 This differs from the REST API, which returns both `id` (UUID) and `short_id` on every record. If you're cross-referencing between an agent session and the admin UI, remember that what the agent sees as `id` is what the UI calls `short_id`. -## Resources +## Reads-as-tools, no MCP resources -MCP resources are static or live documents the server exposes alongside tools. Breadbox serves nine, each annotated with an audience (`assistant`-only by default; the four with real attach-in-chat flows are dual-audience for both `user` and `assistant`), a priority, and a `lastModified` timestamp (build time for static prompts, read time for live data). +Earlier versions of Breadbox exposed the orientation data and the operating-guidance docs as a parallel `breadbox://` resources surface. That surface has been retired entirely — the registry advertises **0 resources, 35 tools**. Resources weren't visible to MCP clients that can't call `resources/list` (notably Claude.ai), so every read is now a tool call. -| URI | MIME | Audience | What it returns | -| --- | --- | --- | --- | -| `breadbox://overview` | `application/json` | user, assistant | Live dataset summary clustered as `scope`, `freshness`, and `backlog`, plus the household `users` roster | -| `breadbox://accounts` | `application/json` | user, assistant | Bank accounts (checking, savings, credit cards, loans, investments) with balances, institution names, and currency | -| `breadbox://categories` | `application/json` | assistant | Two-level category taxonomy keyed by slug; source for valid `category_slug` values when categorizing or authoring rules | -| `breadbox://tags` | `application/json` | assistant | Current tag vocabulary keyed by slug; the `needs-review` tag is the review-queue handle | -| `breadbox://users` | `application/json` | assistant | Household members with their roles (admin, editor, viewer) | -| `breadbox://sync-status` | `application/json` | assistant | Per-connection sync status and last-sync timestamps | -| `breadbox://review-guidelines` | `text/markdown` | user, assistant | Guidance for reviewing transactions and creating rules (user-editable in `/mcp` admin) | -| `breadbox://report-format` | `text/markdown` | user, assistant | Report structure templates used by `submit_report` (user-editable) | -| `breadbox://rule-dsl` | `text/markdown` | assistant | Reference grammar for transaction rules: condition fields, action types, priority bands, sync vs retroactive semantics, and provider quirks | +The migration is mechanical: + +| Old resource URI | Now | +| --- | --- | +| `breadbox://overview` | `get_overview` tool | +| `breadbox://accounts` | `list_accounts` tool | +| `breadbox://categories` | `list_categories` tool | +| `breadbox://tags` | `list_tags` tool | +| `breadbox://users` | `list_users` tool | +| `breadbox://sync-status` | `get_sync_status` tool | +| `breadbox://rules` (rules list) | `list_transaction_rules` tool | +| `breadbox://instructions` | `get_reference` tool, `kind=instructions` | +| `breadbox://rule-dsl` | `get_reference` tool, `kind=rule-dsl` | +| `breadbox://review-guidelines` | `get_reference` tool, `kind=review-guidelines` | +| `breadbox://report-format` | `get_reference` tool, `kind=report-format` | + +A new agent is expected to call `get_overview` first to orient itself, and to call `get_reference(kind="review-guidelines")` before processing review work. -The live `accounts`, `categories`, `tags`, `users`, and `sync-status` resources replace what would otherwise be redundant `list_*` tool calls — agents can read them on connect instead of paying for a round-trip per list. +### Guidance docs via `get_reference` -Agents are expected to read `breadbox://overview` first to orient themselves, and to read `breadbox://review-guidelines` before processing review work. +`get_reference` is a single read tool that serves the near-static markdown that teaches an agent how to drive the server. Pass a `kind`: -### `breadbox://overview` shape +| `kind` | Returns | +| --- | --- | +| `instructions` | Data-model + conventions overview, how the tool surface is organized. | +| `rule-dsl` | The full transaction-rule condition grammar, action types, pipeline-stage ordering, and sync-vs-retroactive semantics. Fixed grammar — not operator-customizable. | +| `review-guidelines` | Principles for reviewing transactions and creating rules. Reflects operator customization from the MCP Settings page. | +| `report-format` | Structure and formatting conventions for `submit_report`. Reflects operator customization. | -The overview resource returns a JSON object with four top-level keys: +The response is a single markdown content block. + +### `get_overview` shape + +`get_overview` returns a JSON object with four top-level keys: - `users` — minimal household roster (`id`, `name`). - `scope` — dataset size: `transaction_count`, `account_count`, `category_count`, `earliest_transaction_date`, `latest_transaction_date`. - `freshness` — ingest-time signals: `last_sync_at` (most recent successful sync across active connections), `errored_connection_count`, `pending_transaction_count`, `transactions_added_last_24h`, `transactions_added_last_7d`. The `transactions_added_last_*` counters track when Breadbox first ingested each row, not when the underlying transaction occurred. - `backlog` — what's open: `needs_review_count` (transactions tagged `needs-review`) and `unmapped_transaction_count` (transactions with no category). -The 30-day spending summary, the per-connection list, and the `accounts_by_type` histogram that earlier versions of this resource returned have been removed — read `breadbox://accounts`, `breadbox://sync-status`, or call `transaction_summary` for that detail. - ## Error shape Tool errors return a standard MCP call result with `isError: true` and a single text content block containing JSON: @@ -103,7 +116,7 @@ A complete list of every tool Breadbox exposes, grouped by domain. Tools without **Data access (read)** -- Overview: `get_overview` — household snapshot; mirrors `breadbox://overview`. +- Overview: `get_overview` — household snapshot (scope, freshness, backlog). - Transactions: [`query_transactions`, `transaction_summary`, `list_annotations`](/mcp/reference/transactions) - Accounts and users: [`list_accounts`, `list_users`](/mcp/reference/accounts) - Categories: [`list_categories`](/mcp/reference/categories) @@ -117,7 +130,7 @@ A complete list of every tool Breadbox exposes, grouped by domain. Tools without **Mutations (write)** -- Transactions: [`update_transactions`](/mcp/reference/transactions-write) — compound write for category sets, tag adds/removes, and comments. +- Transactions: [`update_transactions`](/mcp/reference/transactions-write) — compound write for category sets, tag adds/removes, flag toggles, and comments. - Transaction metadata: `set_transaction_metadata` - Rules: [`create_transaction_rule`, `update_transaction_rule`, `delete_transaction_rule`, `apply_rules`](/mcp/reference/rules-write) - Tags: [`create_tag`, `update_tag`, `delete_tag`](/mcp/reference/tags-write) diff --git a/mcp/reference/reports.mdx b/mcp/reference/reports.mdx index 705b01f..1ee7efd 100644 --- a/mcp/reference/reports.mdx +++ b/mcp/reference/reports.mdx @@ -18,7 +18,7 @@ The `title` IS the message — it's rendered as the primary line in the dashboar The `body` is where structure, headers, and detail go — the UI renders markdown with `##` section headers, bullet lists, tables, and inline transaction links (`[Transaction Name](/transactions/ID)`). -Read `breadbox://report-format` for the full style guide and report templates (review report, spending report, anomaly report). +Call `get_reference(kind="report-format")` for the full style guide and report templates (review report, spending report, anomaly report). ### Parameters diff --git a/mcp/reference/rules-write.mdx b/mcp/reference/rules-write.mdx index be54ad0..2be1ea6 100644 --- a/mcp/reference/rules-write.mdx +++ b/mcp/reference/rules-write.mdx @@ -1,12 +1,12 @@ --- title: "Rule write MCP reference" sidebarTitle: "Rule writes" -description: "Create, update, delete, and batch-create transaction rules. Apply rules retroactively." +description: "Create (single or batch), update, and delete transaction rules. Apply rules retroactively." --- Transaction rules are condition trees that fire during sync to auto-categorize, tag, or annotate new transactions. See [Rules (read)](/mcp/reference/rules) for `list_transaction_rules` and `preview_rule`, and [Categorization](/mcp/reference/categorization#apply_rules) for `apply_rules` (retroactive application). -The full DSL lives in the Breadbox repo at `docs/rule-dsl.md`. Key concepts recapped below under [Pipeline stages](#pipeline-stages-and-priority). +The full DSL grammar is available via `get_reference(kind="rule-dsl")`. Key concepts recapped below under [Pipeline stages](#pipeline-stages-and-priority). All tools on this page are **Write** scope. @@ -14,10 +14,18 @@ All tools on this page are **Write** scope. ## create_transaction_rule -Create a transaction rule. Rules match condition trees against transactions during sync and fire in pipeline-stage order (priority ASC — lower runs first). Pass `stage` (`baseline` | `standard` | `refinement` | `override`) instead of a raw priority when you can — stage resolves to priority 0/10/50/100 so rules from different agents compose predictably. +Create one or more transaction rules in a single call. Pass a `rules` array of 1–100 rule specs — a single rule is just a one-element array. Rules match condition trees against transactions during sync and fire in pipeline-stage order (priority ASC — lower runs first). Set `apply_retroactively: true` on any item to immediately back-fill it against existing transactions. + +This tool absorbs the retired `batch_create_rules` — there is no separate batch tool. Earlier-stage rules' tag and category mutations feed later-stage rules' conditions in the same pass, so composable pipelines (rule A tags `coffee` → rule B reads that tag → rule C sets a category) should be authored as a single multi-rule call. ### Parameters + + Array of rule specs, 1–100 entries. Each spec follows the shape below. + + +### Rule spec shape + Human-readable description. Convention: `": "`. @@ -61,54 +69,84 @@ Create a transaction rule. Rules match condition trees against transactions duri If `true`, immediately apply this rule to existing transactions after creation. Materializes `set_category`, `add_tag`, `remove_tag`; skips `add_comment` (sync-only). -### Example input +### Example — single rule ```json { - "name": "name: Starbucks → food_and_drink_coffee", - "conditions": { - "field": "merchant_name", - "op": "contains", - "value": "starbucks" - }, - "actions": [ - { "type": "set_category", "category_slug": "food_and_drink_coffee" } - ], - "stage": "standard", - "trigger": "on_create" + "rules": [ + { + "name": "name: Starbucks → food_and_drink_coffee", + "conditions": { + "field": "merchant_name", + "op": "contains", + "value": "starbucks" + }, + "actions": [ + { "type": "set_category", "category_slug": "food_and_drink_coffee" } + ], + "stage": "standard", + "trigger": "on_create" + } + ] } ``` - +### Example — composable pipeline + +Earlier stages' tag and category mutations are visible to later stages in the same sync pass, so a three-rule pipeline can be authored atomically: ```json { - "rule": { - "id": "r9Xm2pQr", - "name": "name: Starbucks → food_and_drink_coffee", - "conditions": { - "field": "merchant_name", - "op": "contains", - "value": "starbucks" + "rules": [ + { + "name": "Tag coffee shops", + "stage": "baseline", + "conditions": { + "field": "merchant_name", + "op": "contains", + "value": "starbucks" + }, + "actions": [{ "type": "add_tag", "tag_slug": "coffee" }] }, - "actions": [ - { "type": "set_category", "category_slug": "food_and_drink_coffee" } - ], - "trigger": "on_create", - "priority": 10, - "enabled": true, - "hit_count": 0, - "last_hit_at": null, - "created_at": "2026-04-23T14:45:00Z", - "created_by": "review-agent@example.com", - "expires_at": null - } + { + "name": "Categorize coffee-tagged", + "stage": "standard", + "conditions": { "field": "tags", "op": "contains", "value": "coffee" }, + "actions": [ + { "type": "set_category", "category_slug": "food_and_drink_coffee" } + ] + }, + { + "name": "Flag expensive coffee", + "stage": "refinement", + "conditions": { + "and": [ + { "field": "tags", "op": "contains", "value": "coffee" }, + { "field": "amount", "op": "gt", "value": 15 } + ] + }, + "actions": [{ "type": "add_tag", "tag_slug": "expensive" }] + } + ] } ``` - +### Example output + +```json +{ + "created": 3, + "failed": 0, + "rules": [ + { "id": "r9Xm2pQr", "name": "Tag coffee shops", "priority": 0 }, + { "id": "rAYn0qR3", "name": "Categorize coffee-tagged", "priority": 10 }, + { "id": "rBZo1rS4", "name": "Flag expensive coffee", "priority": 50 } + ], + "errors": [] +} +``` -If `apply_retroactively: true` was passed, the response also includes `retroactive_matches: ` (or `retroactive_error: ""` on failure). +The response returns the created rules plus any per-item errors so a partial batch is recoverable. If `apply_retroactively: true` was set on a rule, that rule's entry also carries `retroactive_matches: ` (or `retroactive_error: ""` on failure). --- @@ -203,77 +241,6 @@ Delete a rule by ID. System-seeded rules (the `needs-review` auto-tagger) cannot --- -## batch_create_rules - -Create up to 100 rules in one call. Ideal for composable pipelines — each item can set its `stage` to order rules so earlier stages set up tags/categories that later stages react to. - -Each item follows the same shape as `create_transaction_rule`. Returns created rules plus any per-item errors so partial success is recoverable. - -### Parameters - - - Array of rule definitions. Max 100. Each item has `name` (required), `conditions`, `actions` or `category_slug` (one required), `trigger`, `stage`, `priority`, `expires_in`. - - -### Example input - -```json -{ - "rules": [ - { - "name": "Tag coffee shops", - "stage": "baseline", - "conditions": { - "field": "merchant_name", - "op": "contains", - "value": "starbucks" - }, - "actions": [{ "type": "add_tag", "tag_slug": "coffee" }] - }, - { - "name": "Categorize coffee-tagged", - "stage": "standard", - "conditions": { - "field": "tags", - "op": "contains", - "value": "coffee" - }, - "actions": [ - { "type": "set_category", "category_slug": "food_and_drink_coffee" } - ] - }, - { - "name": "Flag expensive coffee", - "stage": "refinement", - "conditions": { - "and": [ - { "field": "tags", "op": "contains", "value": "coffee" }, - { "field": "amount", "op": "gt", "value": 15 } - ] - }, - "actions": [{ "type": "add_tag", "tag_slug": "expensive" }] - } - ] -} -``` - -### Example output - -```json -{ - "created": 3, - "failed": 0, - "rules": [ - { "id": "r9Xm2pQr", "name": "Tag coffee shops", "priority": 0 }, - { "id": "rAYn0qR3", "name": "Categorize coffee-tagged", "priority": 10 }, - { "id": "rBZo1rS4", "name": "Flag expensive coffee", "priority": 50 } - ], - "errors": [] -} -``` - ---- - ## Pipeline stages and priority Rules fire in priority-ASC order during each sync pass, and within a single pass each rule observes mutations from earlier-stage rules. That makes rules composable — rule A can add a tag, rule B's condition can react to that tag, rule C can set a category based on the combined state. diff --git a/mcp/reference/rules.mdx b/mcp/reference/rules.mdx index 5e6b130..1facc65 100644 --- a/mcp/reference/rules.mdx +++ b/mcp/reference/rules.mdx @@ -6,7 +6,7 @@ description: "MCP read tools for listing, filtering, previewing, and finding cov Transaction rules are condition trees that fire during sync to auto-categorize, tag, or annotate transactions. These read tools let agents inspect the existing rule set and dry-run conditions before creating new rules. -See [Rule writes](/mcp/reference/rules-write) for `create_transaction_rule`, `update_transaction_rule`, `delete_transaction_rule`, `batch_create_rules`, and `apply_rules`. +See [Rule writes](/mcp/reference/rules-write) for `create_transaction_rule` (single or batch via the `rules` array), `update_transaction_rule`, `delete_transaction_rule`, and `apply_rules`. --- diff --git a/mcp/reference/transactions-write.mdx b/mcp/reference/transactions-write.mdx index d2ab136..a58ae62 100644 --- a/mcp/reference/transactions-write.mdx +++ b/mcp/reference/transactions-write.mdx @@ -4,7 +4,7 @@ sidebarTitle: "Transaction writes" description: "Compound writes for category, tags, and comments on transactions. Categorization lives on its own page." --- -Write tools for editing transactions. `update_transactions` is the single primitive — it covers category, tags, and a comment in one atomic op per row, for up to 50 transactions per call. +Write tools for editing transactions. `update_transactions` is the single primitive — it covers category sets, category resets, tag adds/removes, flag toggles, and a free-form comment in one atomic op per row, for up to 50 transactions per call. The retired per-row tools (`categorize_transaction`, `batch_categorize_transactions`, `reset_transaction_category`, `bulk_recategorize`, `flag_transaction`, `unflag_transaction`) all fold into it. All tools on this page are **Write** scope. See [Categorization](/mcp/reference/categorization) for category-only writes. @@ -48,7 +48,11 @@ Every change lands as a single linked annotation per operation, so the activity - Category slug to set. Sets `category_override = 'agent'` (skips the row if a user has already set it to `'user'`). Omit to leave the category unchanged. + Category slug to set. Sets `category_override = 'agent'` (skips the row if a user has already set it to `'user'`). Omit to leave the category unchanged. Mutually exclusive with `reset_category`. + + + + Drop the transaction back to uncategorized so rules can re-categorize it on the next sync. Mutually exclusive with `category_slug`. Use to undo a prior agent or rule decision. @@ -59,6 +63,10 @@ Every change lands as a single linked annotation per operation, so the activity List of `{slug, note?}` entries. `note` is recommended for workflow tags like `needs-review`. + + Flag (`true`) or unflag (`false`) the transaction for human attention without changing its category. Pair `flagged: true` with a `comment` carrying the reason; retrieve flagged rows later with `query_transactions(flagged=true)`. Omit to leave the flag untouched. Replaces the retired `flag_transaction` / `unflag_transaction` tools. + + Free-form comment written as an annotation. Max 10000 chars. Markdown supported. @@ -101,3 +109,19 @@ Every change lands as a single linked annotation per operation, so the activity } ``` +### Flagging a transaction + +To mark a transaction for follow-up without changing its category, pass `flagged: true` with a `comment` carrying the reason. Retrieve flagged rows later with `query_transactions(flagged=true)`. Clearing a flag is `flagged: false`. + +```json +{ + "operations": [ + { + "transaction_id": "k7Xm9pQ2", + "flagged": true, + "comment": "Charge from a merchant we don't recognize — verify before next statement." + } + ] +} +``` + diff --git a/mcp/reference/transactions.mdx b/mcp/reference/transactions.mdx index 52a4eee..96a8757 100644 --- a/mcp/reference/transactions.mdx +++ b/mcp/reference/transactions.mdx @@ -50,6 +50,10 @@ Returns a paginated list of transactions matching the supplied filters. This is Filter by pending status. Omit to return both. + + Filter to flagged transactions (`true`) or unflagged (`false`). Omit to return both. Use `flagged=true` to retrieve transactions you (or an agent) marked for follow-up via `update_transactions`. + + Case-insensitive substring match on `name` and `merchant_name`. Comma-separate values for OR. @@ -90,6 +94,10 @@ Returns a paginated list of transactions matching the supplied filters. This is Comma-separated fields or aliases (`minimal`, `core`, `category`, `timestamps`). See [Conventions](/mcp/reference/conventions#fields-aliases). `id` is always included. + + When `true`, return only `{"count": N}` for the given filters — no rows, no pagination. `cursor`, `limit`, `sort_by`, `sort_order`, and `fields` are ignored. Use this to size a result set or compare counts across date ranges or categories before paginating. Replaces the retired `count_transactions` tool. + + ### Example input ```json @@ -133,25 +141,22 @@ Returns a paginated list of transactions matching the supplied filters. This is --- -## count_transactions +## Counting matches: `query_transactions(count_only=true)` -Returns the count of transactions matching the filters, without fetching any rows. Agents use this as a cheap pre-flight to decide whether to paginate or narrow filters. +There is no separate `count_transactions` tool. To get just a count for a given set of filters, pass `count_only: true` to `query_transactions` with the same filters you'd otherwise use. The response is `{"count": N}` with no rows, no pagination, and no cursor — `cursor`, `limit`, `sort_by`, `sort_order`, and `fields` are ignored. Agents use this as a cheap pre-flight to decide whether to paginate or narrow filters. **Scope:** Read **Mirrors:** [`GET /api/v1/transactions/count`](/api/overview) -### Parameters - -Accepts the same filters as `query_transactions` except `cursor`, `limit`, `sort_by`, `sort_order`, and `fields`. - ### Example input ```json { "start_date": "2026-01-01", "end_date": "2026-04-01", - "category_slug": "food_and_drink_groceries" + "category_slug": "food_and_drink_groceries", + "count_only": true } ``` diff --git a/mcp/tools.mdx b/mcp/tools.mdx index 58421a3..a5db0d7 100644 --- a/mcp/tools.mdx +++ b/mcp/tools.mdx @@ -16,7 +16,7 @@ This page is for **you** — the person deciding what to hand an agent. Agents r ## What a typical agent session looks like -An agent connected to Breadbox usually opens a session by orienting itself before it starts querying. First it calls `list_users` and `list_accounts` to see who's in the household and which accounts exist — this gives it the IDs it needs to filter anything downstream. Then, before pulling rows, it calls `count_transactions` with its intended filters so it knows whether to expect fifty results or five thousand. Only then does it call `query_transactions`, paginating with the returned cursor if `has_more` is `true`. +An agent connected to Breadbox usually opens a session by orienting itself before it starts querying. First it calls `list_users` and `list_accounts` to see who's in the household and which accounts exist — this gives it the IDs it needs to filter anything downstream. Then, before pulling rows, it calls `query_transactions` with `count_only: true` and its intended filters so it knows whether to expect fifty results or five thousand. Only then does it call `query_transactions` for real, paginating with the returned cursor if `has_more` is `true`. That pattern — orient, size, query — keeps token usage predictable and matches how Breadbox's tools are designed. You don't need to enforce it from the outside; the tool descriptions nudge the agent toward it. @@ -161,32 +161,17 @@ When there are no more pages, the response includes `"has_more": false` and `"ne --- -## `count_transactions` +## Counting without paginating: `query_transactions(count_only=true)` -Counts matching transactions without returning any transaction data. Accepts the same filters as `query_transactions` (excluding `cursor`, `limit`, `sort_by`, and `sort_order`). It's the cheap pre-flight an agent uses to decide whether to narrow filters or brace for pagination. - -**Scope:** Read - -**Input parameters** - -| Parameter | Type | Required | Description | -| --- | --- | --- | --- | -| `start_date` | string (YYYY-MM-DD) | No | Count transactions on or after this date (inclusive). | -| `end_date` | string (YYYY-MM-DD) | No | Count transactions before this date (exclusive). To cover all of January, pass `2025-02-01`. | -| `account_id` | string | No | Filter to a specific account. | -| `user_id` | string | No | Filter to accounts owned by this family member. | -| `category_slug` | string | No | Filter by category slug. Parent slugs include all children. | -| `min_amount` | number | No | Minimum transaction amount. | -| `max_amount` | number | No | Maximum transaction amount. | -| `pending` | boolean | No | Filter by pending status. | -| `search` | string | No | Full-text search over merchant name and description. | +There's no separate `count_transactions` tool. To get just a count for a given set of filters, call `query_transactions` with `count_only: true` and the same filters you'd otherwise use. The response is `{"count": N}` with no rows, no pagination, and no cursor — `cursor`, `limit`, `sort_by`, `sort_order`, and `fields` are ignored. It's the cheap pre-flight an agent uses to decide whether to narrow filters or brace for pagination. **Example input** ```json { "start_date": "2025-01-01", - "end_date": "2025-02-01" + "end_date": "2025-02-01", + "count_only": true } ``` @@ -200,7 +185,7 @@ Counts matching transactions without returning any transaction data. Accepts the ## `list_categories` -Returns the Breadbox category taxonomy as a flat list. Each category has a stable `slug` — the handle agents pass to `query_transactions` and `count_transactions` to filter by category, and to rule actions to set a category. +Returns the Breadbox category taxonomy as a flat list. Each category has a stable `slug` — the handle agents pass to `query_transactions` to filter by category, and to rule actions to set a category. **Scope:** Read @@ -242,7 +227,7 @@ None. Pass an empty object. } ``` -Pass a category `slug` as the `category_slug` parameter in `query_transactions` and `count_transactions` to filter by category. Parent slugs (e.g., `food_and_drink`) include all child categories automatically. +Pass a category `slug` as the `category_slug` parameter in `query_transactions` to filter by category. Parent slugs (e.g., `food_and_drink`) include all child categories automatically. --- @@ -343,22 +328,16 @@ None. Pass an empty object. ## Series (subscriptions) -Breadbox detects recurring charges and groups them into [series](/guides/tracking-subscriptions). These tools are the agent-facing side of the **Recurring** page — they let a scheduled reviewer adjudicate what the detector proposed and fill in anything it missed. (The tool *names* stay `*_series` for API stability even though the surface is now called Recurring.) +Breadbox groups recurring charges into [series](/guides/tracking-subscriptions). A series is a thin surrogate identity (id, name, type) — its membership is maintained by `assign_series` rules in the rule engine, not by a built-in detector. These tools are the agent-facing side of the **Recurring** page; an agent uses them to mint or rename a series and to one-off-link or unlink specific charges. | Tool | Scope | What it does | | --- | --- | --- | -| `list_series` | Read | List detected series. Filter by `status` (`active`, `candidate`, `paused`, `cancelled`); `candidate` surfaces the ones awaiting a verdict. Each row carries cadence, expected amount + currency, next expected date, and the detection signals. | -| `get_series` | Read | Fetch one series by ID, including the full evidence the detector used. | -| `explain_series_candidates` | Read | Answer "why isn't *X* recurring?" — lists recurring-looking merchants the precision-first detector skipped, with the reason (too few occurrences, irregular cadence, unstable amount, …). | -| `review_series` | Write | Apply a verdict: `confirm`, `reject` (sticky — never re-proposed at that amount band), `pause`, or `cancel`. A user's prior confirmation outranks a later agent verdict. | -| `update_series` | Write | Edit a series' user-owned attributes: name, expected amount, cadence, expected day, category, or owner. Every field is optional; omit to leave unchanged. Edits survive future detection runs (the detector won't revert them). | -| `set_series_type` | Write | Set the series type: `subscription`, `bill`, `loan`, or `other`. Overrides the type the detector inferred from the charges' category; the override is sticky. | -| `assign_series` | Write | Create a series the detector missed, or back-link transactions to an existing one. Never steals a charge already in another series. | -| `unlink_series_transactions` | Write | Detach transactions from a series (inverse of `assign_series`). Clears the series link and strips inherited tags from the affected charges only. | -| `rekey_series` | Write | Fix a series grouped under a wrong or fallback merchant key (e.g. `payment` → `spotify`), repointing it and its charges. | -| `split_series` | Write | Break an over-grouped series in two — move stray charges into a new series (e.g. a $4.99 add-on swept into a $139/yr renewal). | -| `add_series_tag` / `remove_series_tag` | Write | Tag a series; every linked transaction inherits the tag automatically. Removing strips only the inherited copies. | +| `list_series` | Read | List recurring series. Lean by default (`name`, `type`); pass `fields=all` for the full row. Use `query_transactions` with a `series_id` filter to enumerate a series' charges. | +| `get_series` | Read | Fetch one series by short ID or UUID. | +| `assign_series` | Write | Link transactions to a series, creating it if needed. Provide `series_id` to assign to an existing series, or `series_name` + `create_if_missing: true` to mint one (surrogate-first — the same name always resolves the same series). Optional `type` (`subscription`, `bill`, `loan`, `other`) for a minted series. `transaction_ids` (≤50) back-link members; an `assign_series` call never steals a charge already in another series. | +| `update_series` | Write | Edit a series' `name` and/or `type`. Both optional; omit to leave unchanged. Renaming onto another live series' name is rejected — the name is the series' unique mint key. | +| `unlink_series_transactions` | Write | Detach transactions (≤50) from a series — the inverse of `assign_series`. Each listed transaction must currently belong to the series; the call errors out otherwise so it can't silently touch the wrong rows. | - A typical reviewer agent calls `list_series(status="candidate")`, inspects each with `get_series`, and resolves it with `review_series` — the same confirm/reject loop a person runs on the Recurring page. + When you want every future charge from a merchant to land in a series automatically, encode that as an `assign_series` rule via `create_transaction_rule` instead of calling `assign_series` for each new transaction. diff --git a/transactions/overview.mdx b/transactions/overview.mdx index 4fba0ec..cbc665f 100644 --- a/transactions/overview.mdx +++ b/transactions/overview.mdx @@ -71,7 +71,7 @@ Navigate to **Transactions** in the admin dashboard sidebar to browse, search, a For programmatic access, Breadbox offers two interfaces: - **REST API** — Use `GET /api/v1/transactions` with query parameters to filter (date, account, user, category, amount, search), sort, paginate, and filter by tags (`tags=` / `any_tag=`). See [Transactions API](/api/overview) for the full parameter list and [Tags API](/api/overview) for attaching and detaching tags. -- **MCP server** — AI agents connect to Breadbox's MCP server and use tools like `query_transactions`, `count_transactions`, and `update_transactions` to query, categorize, tag, and summarize in natural-language workflows. See [MCP overview](/mcp/overview) for setup and [MCP Reference](/mcp/reference/overview) for the full tool list. +- **MCP server** — AI agents connect to Breadbox's MCP server and use tools like `query_transactions` (which doubles as a counter via `count_only=true`) and `update_transactions` to query, categorize, tag, and summarize in natural-language workflows. See [MCP overview](/mcp/overview) for setup and [MCP Reference](/mcp/reference/overview) for the full tool list. ## Soft deletes diff --git a/transactions/review-workflow.mdx b/transactions/review-workflow.mdx index 6807979..5b69ae1 100644 --- a/transactions/review-workflow.mdx +++ b/transactions/review-workflow.mdx @@ -58,7 +58,7 @@ System-seeded rules can be disabled but not deleted, so you can always turn the Because the queue is just a tag filter, AI agents connected over MCP can participate using the same tools humans would: - `query_transactions(tags=["needs-review"])` to fetch the backlog -- `count_transactions(tags=["needs-review"])` to check the size before diving in +- `query_transactions(tags=["needs-review"], count_only=true)` to check the size before diving in - `update_transactions` with a compound op (`category_slug` \+ `tags_to_remove` with a note \+ an optional `comment`) to resolve items in batches - Leave the tag in place when an agent isn't confident — that's the equivalent of "skipping" @@ -66,7 +66,7 @@ A typical agent loop: - `count_transactions(tags=["needs-review"])` to size it up, then `query_transactions(tags=["needs-review"], fields=core,category, limit=30)`. + `query_transactions(tags=["needs-review"], count_only=true)` to size it up, then `query_transactions(tags=["needs-review"], fields=core,category, limit=30)`. For each row the agent inspects name, merchant, amount, and any pre-applied category. It applies your review guidelines (configurable in settings) to decide whether to accept the category, change it, or defer. diff --git a/transactions/tags.mdx b/transactions/tags.mdx index 24d0e50..16a4423 100644 --- a/transactions/tags.mdx +++ b/transactions/tags.mdx @@ -53,7 +53,7 @@ A tag reaches a transaction one of four ways — and the activity timeline recor ## Querying by tag -Tag-based filters are available through the **MCP tools** (`query_transactions`, `count_transactions`) and the admin dashboard. The REST API does not currently expose tag filters on `GET /api/v1/transactions` — if you need to query by tag over HTTP, use MCP. See [issue #624](https://github.com/canalesb93/breadbox/issues/624) for the V1 parity plan. +Tag-based filters are available through the **MCP tool** `query_transactions` (use `count_only: true` for a count-only response) and the admin dashboard. The REST API does not currently expose tag filters on `GET /api/v1/transactions` — if you need to query by tag over HTTP, use MCP. See [issue #624](https://github.com/canalesb93/breadbox/issues/624) for the V1 parity plan. MCP tools accept two filter shapes: