Skip to main content
Glama
calebl

YNAB MCP Server

by calebl

ynab-mcp-server

A Model Context Protocol (MCP) server for interacting with your YNAB plans at https://ynab.com

In order to have an AI interact with this tool, you will need to get your Personal Access Token from YNAB: https://api.ynab.com/#personal-access-tokens. When adding this MCP server to any client, you will need to provide your personal access token as YNAB_API_TOKEN. This token is never directly sent to the LLM. It is stored privately in an environment variable for use with the YNAB api.

A Model Context Protocol server that lets an AI assistant read and modify a YNAB plan.

The server talks to the YNAB API through the official ynab SDK. Your Personal Access Token lives in an environment variable and is never sent to the model.

It runs two ways from one codebase:

  • Local (stdio) — a child process of Claude Code or Claude Desktop on your own machine. Simplest, but only works on that machine while it is running.

  • Remote (Cloudflare Worker) — deployed behind GitHub sign-in and added to claude.ai as a custom connector, so it works from the web and the mobile app with your computer switched off. See DEPLOY.md.

Both entry points register the shared tools from src/registry.ts. The Worker can also run an optional scheduled auto-budget service that records what it would categorize, approve and assign without changing your plan and delivers spending alerts; see Auto-budget service.

Other providers:

LightNow

Setup

Get a Personal Access Token from https://api.ynab.com/#personal-access-tokens, then:

npm install
npm run build

Environment variables:

Variable

Required

Purpose

YNAB_API_TOKEN

yes

Personal Access Token used for every API call

YNAB_PLAN_ID

no

Default plan, so tools can omit planId. Find it with ynab_list_plans.

TYPESAFE_API_KEY

no

Operator-owned TypeSafe credential. Required, but not sufficient, to enable category suggestions.

YNAB_AI_CATEGORIZATION

no

Set to "true" together with TYPESAFE_API_KEY to expose the opt-in suggestion tool.

YNAB_AI_TYPICAL_PAYEES

no

Set to "true" to send each category's most frequent payee names from the last 12 months with each model request. Off by default because it discloses aggregated payee history to TypeSafe.

YNAB_READ_ONLY

no

Set to "true" (case-insensitive; surrounding whitespace is ignored) to remove tools that write to YNAB, in both the stdio server and the Worker.

Local: Claude Desktop / Claude Code

{
  "mcpServers": {
    "ynab": {
      "command": "node",
      "args": ["/absolute/path/to/ynab-mcp-server/dist/index.js"],
      "env": {
        "YNAB_API_TOKEN": "your-token",
        "YNAB_PLAN_ID": "your-plan-id"
      }
    }
  }
}

Remote: phone and claude.ai

The stdio server above cannot be reached from a phone. To use these tools from claude.ai or the Claude mobile app, deploy src/worker/ to Cloudflare Workers and add it as a custom connector. DEPLOY.md has the full walk through; the shape of it:

  1. Copy wrangler.example.jsonc to the git-ignored wrangler.jsonc, remove the optional placeholder AUTOBUDGET_DB block unless you are configuring the auto-budget service, run npx wrangler login, then create the OAUTH_KV namespace

  2. npm run deploy once to learn your *.workers.dev hostname

  3. Create a GitHub OAuth app whose callback is https://<host>/callback

  4. Use npx wrangler secret put for ALLOWED_GITHUB_LOGIN, YNAB_API_TOKEN, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, and TYPESAFE_API_KEY

  5. Run npm run deploy again

  6. Add https://<host>/mcp as a custom connector in claude.ai

The YNAB token stays a Worker secret and never reaches the client. GitHub sign-in controls who may connect to the remote Worker; the YNAB Personal Access Token controls which YNAB account it reaches. They answer different questions, and neither substitutes for the other. The Worker uses one server-wide YNAB token, so anyone admitted through the GitHub gate reaches the deployer's YNAB account, money, and every plan available to that token—not their own YNAB account. ynab_list_plans lists all of those plans, and a caller-supplied planId overrides the optional YNAB_PLAN_ID default. Any GitHub account other than ALLOWED_GITHUB_LOGIN is refused. This matters because the tool set can create and delete transactions—an unauthenticated endpoint would grant access to those plans to anyone who found the URL.

The Worker is not tied to Claude. Any MCP client that supports remote servers with OAuth can connect, for example Claude (claude.ai, desktop, and mobile), ChatGPT connectors, Claude Code, or the MCP Inspector. Because clients register themselves, every permitted sign-in shows an approval page naming the client and the exact address the grant will be sent to; approve only a sign-in you just started. To restrict which clients can connect at all, set ALLOWED_REDIRECT_URIS to their exact callback URIs (loopback redirects for local clients stay allowed). See Approving MCP clients for example callback URIs.

Related MCP server: ynab-mcp

Why not YNAB OAuth?

YNAB OAuth is deliberately not supported. Its token exchange requires a client secret even with PKCE; an open-source package cannot ship a secret, so a local package cannot honestly implement the authorization-code flow (OAuth application requirements). The only secretless flow YNAB documents is the implicit grant, which expires in two hours with no refresh (OAuth application requirements). YNAB recommends a Personal Access Token for an individual accessing their own account (Personal Access Tokens).

Setting YNAB_READ_ONLY to "true" drops every YNAB write tool from the tool list, which is worth considering for a connector you will mostly use on a phone.

Tools

Plan-scoped tools take an optional planId that falls back to YNAB_PLAN_ID. Optional tool inputs may be null; the server treats null the same as omitting that input. All monetary values — in both directions — are plain currency amounts, never YNAB's milliunits. Reported amounts use the plan currency's precision (three decimals for currencies such as the Kuwaiti dinar) and fall back to two decimals if its settings cannot be read; conversion happens in src/tools/money.ts.

Reading

Tool

What it does

ynab_list_plans

Every plan on the account. Run this first to find a plan ID.

ynab_plan_summary

A month at a glance: income, budgeted, activity, Ready to Assign, plus categories split into overspent, underfunded (goal not yet met) and positive_balance. Hidden and deleted categories are excluded. budgetVsActuals: true adds a budget_vs_actuals block: budgeted, activity, balance, variance (budgeted plus activity) and percent_used (null when nothing was assigned) per category, subtotalled per category group and in totals. Credit Card Payments is listed as its own group but left out of totals, since its activity is card spending moving in minus payments going out. YNAB's internal Inflow: Ready to Assign category (whose activity is the month's income) is skipped; other internal categories, such as Uncategorized, are listed and counted when they have activity.

ynab_list_accounts

Accounts with balances. includeClosedAccounts to see closed ones.

ynab_list_categories

Categories grouped by category group, with goal info.

ynab_list_payees

Payees, for resolving payee IDs.

ynab_list_months

Every plan month since the plan began, with raw income, budgeted, activity, Ready to Assign, age-of-money and note fields. For recent income versus spending, use ynab_cash_flow.

ynab_list_scheduled_transactions

The scheduled transactions set up in YNAB. For recurring charges found in transaction history, see ynab_detect_recurring; for a projected balance, ynab_balance_forecast.

ynab_get_transactions

Transactions optionally filtered to sinceDate–untilDate, by type (all/uncategorized/unapproved), and by at most one of accountId, categoryId or payeeId (the first in that order wins). To search, add payeeContains, memoContains (case-insensitive), minAmount/maxAmount (ignoring sign) or direction (outflow/inflow/any); any search option or untilDate adds a totals block (count, inflow, outflow, net) over every match, including transfers between accounts, and totalsOnly: true returns only that. Without categoryId or payeeId, splits are matched leg by leg and the totals count only the matching legs; with them, rows are matched as YNAB returns them, so a split's parent row in the payee listing counts at its full amount. limit defaults to 100 and does not affect the totals.

ynab_suggest_categories

Opt-in, read-only category previews for unapproved, uncategorized ordinary outflows. Deleted and categorized rows are dropped in default mode; approved, reconciled, balance-adjustment, transfer, split, and inflow rows are skipped as applicable.

Category suggestions (optional)

ynab_apply_category_suggestions is a separate write tool that is available without enabling the TypeSafe preview. Provide up to 25 explicit transaction_id, category_id, and expected_content_fingerprint rows. The tool refetches each transaction and rejects stale or ineligible changes; a retry whose category is already applied is a no-op. It supports validation-only dry runs and returns a pre-write undo manifest, but does not perform the undo. It never auto-applies suggestions, calls TypeSafe, or approves transactions.

ynab_suggest_categories is off by default. To expose it, set both an operator-owned TYPESAFE_API_KEY and YNAB_AI_CATEGORIZATION=true, then restart the server. The API key is read from the environment (or a Worker secret), never from a tool argument. Omit transactionIds, pass null, or pass an empty array to fetch unapproved transactions and retain only uncategorized rows; provide IDs to inspect only those transactions. In default mode, the tool checks every retained row for deterministic eligibility and then applies limit to the first eligible outflows in YNAB's returned order. Skipped rows do not consume the limit.

The tool is a dry-run preview: it never writes to YNAB, approves a transaction, or changes the behavior of ynab_update_transaction. It first handles exact facts in code—dropping deleted rows and handling approved or reconciled rows, YNAB balance adjustments, transfers, splits, inflows, existing categories, and hidden/internal categories. In default mode, transactions contains only the eligible rows inspected, transaction_count is that row count, and eligible_transaction_count reports all eligible rows available before the limit. The top-level skipped object reports total_count and a count plus transaction_ids for each reason: skipped_approved, skipped_reconciled, skipped_balance_adjustment, skipped_transfer, skipped_split, skipped_inflow, and skipped_already_categorized. With explicit transactionIds, every non-deleted fetched row remains an individual result, including rows carrying a skipped_* status; deleted rows are omitted. Payee history uses the latest 12 months, capped at 50 qualifying rows. When the payee has no qualifying rows with the same payee ID, history falls back to rows from payees with a similar name: after Unicode NFC normalization, lowercasing, and removing everything except letters and numbers, one name begins the other and the shorter is at least six characters, so a truncated bank payee such as "Better Bl" draws on "Better Blend" history. Each history summary reports match (payee, similar_payee_name, or null) and matched_payee_names.

Each eligible row is then routed in this order, and source names the step that answered:

  1. Exact-payee history (history_rule). When at least one qualifying row has the same payee ID and every such row uses the same still-eligible category, that category is suggested. When those rows disagree, the row is needs_review and proposes the most recently used category, with the others as top_alternatives carrying their history_count. No model call is made for either case.

  2. Personal prior (personal_prior). A naive-Bayes classifier is trained for each request on the plan's own categorized ordinary outflows from the same 12-month history, using payee and bank-import name tokens, the account, and a coarse amount bucket. It is used when history contains categorized rows across at least two categories; a single-category prior cannot rank alternatives. Name tokens never seen in training are ignored rather than scored. When its top category reaches probability 0.9, the row is suggested without a model call. The probability is reported under personal_prior.ranking, never as model_confidence. Below 0.9 the prior only ranks: its top three appear on the model's row for comparison.

  3. Model (jev). Every remaining row goes to TypeSafe's pinned jev-1.13.0 System One model in batches of ten. A model answer is a ranked shortlist, never a suggestion: every answer that names a category is needs_review, while an explicit model abstention is left_uncategorized. The pinned model's stored review threshold is therefore 0; thresholds stay model-specific because confidence scales differ between models.

Similar-name history is never a rule; when a row reaches the model, it is included as suggestive evidence. The history summary's reference_category_id is the category a proposal is compared with: the most recently used one for exact-payee history, and the plurality for similar-name history. A similar-name disagreement is reported as conflict but does not change the status, because a prefix match does not establish merchant identity. Every inspected eligible row includes a status, source, content fingerprint, proposed category, model confidence and winning probability (model rows only), up to three alternatives, the history summary, and the personal-prior ranking where one was computed. The response's thresholds object reports the values in force, and personal_prior reports how many rows trained the prior and whether it was available for routing. Applying a suggestion remains a separate, explicit human decision using ynab_apply_category_suggestions (or the general ynab_update_transaction tool).

Why this order: households file payees their own way, such as restaurants under a groceries category or clinics under a savings category. A general-purpose model cannot know that, but the plan's own history encodes it. On real household history, history rules and the personal prior were much more accurate than a model on the same rows. The model's high-confidence answers were wrong far more often than on synthetic fixtures, which is why they are review-only. To evaluate your own plan, or a local model, see Evaluating categorization and local decision models.

Enabling this feature sends the transaction's display payee, imported/original payee, memo, amount, date, and account name/type/on-budget status, plus visible category group and category names, to TypeSafe as a third-party processor. For model-bound rows with similar-name matches, it also sends the matched payee names and per-category key, group, name, and count. When YNAB_AI_TYPICAL_PAYEES=true, each model request also lists up to eight of each category's most frequent payee names from the last 12 months (typical_payees), and the response sets typical_payees_sent: true. This makes the model noticeably more accurate on a household's own filing habits, but it discloses aggregated payee history, so it is off by default. It does not send YNAB UUIDs, balances, goals, approval/cleared state, or raw transaction history. Rows answered by history or the personal prior are never sent. TypeSafe's published Jev 1.13 price at the time of this release is $0.042 per million input tokens; output tokens are free. The tool returns preflight estimates, actual token usage, and projected cost on each run and refuses requests over its per-call token/cost ceilings. Pricing and provider limits can change; check https://docs.typesafe.ai/models.

The prototype is intentionally narrow and not default-on. Its original 98.3% exact-label, 98.9% top-three, and 60/60 expected-abstention results came from 40 synthetic, single-evaluator fixtures, not a production accuracy claim. Real household history is much harder, as described above.

Reporting

In the spending reports, splits are counted through their subtransactions and transfers between your own accounts are excluded, so they report spending rather than money movement.

Tool

What it does

ynab_spending_by_category

Total spend per category over a date range, biggest first, with share of total. Defaults to the last 30 days. With monthly: true, each category also gets spend per calendar month, its mean over the full months, and its last full month's change against the earlier full months, over the last months months (default 6, at most 24) or from sinceDate, which overrides months; untilDate then defaults to today. Totals are gross outflows, so refunds aren't netted.

ynab_spending_by_payee

The same, grouped by merchant, including monthly.

ynab_cash_flow

Income vs spending per month with the running net, from YNAB's own monthly totals. Defaults to the last 6 months.

ynab_balance_forecast

The combined balance of your accounts over the next days (default 30, max 365, from today in UTC), projected from scheduled transactions only: starting balance, the scheduled events, the end-of-day running balance, the lowest point and the ending balance. accountIds picks the accounts; the default is every open on-budget account. limit caps the events (default 100, 0 leaves them out); event_count, the running balance, low point and ending balance always cover every event. Transfers between two included accounts (credit card payments too) net to zero; a transfer to an account outside the forecast counts as money leaving, and one from such an account as money arriving. Splits are counted leg by leg. Occurrences whose date has passed but that YNAB hasn't entered yet count on the first day, marked overdue with their scheduled_date and summarised in overdue_schedules. A twice-a-month schedule's second date is approximated as 15 days after the first when YNAB doesn't give it, and marked approximate.

ynab_detect_recurring

Recurring outflows such as subscriptions and bills: a payee's charges of a similar amount at a regular interval (weekly to yearly), with typical amount, yearly cost at the latest amount, next expected date, whether it seems to have stopped, and whether a scheduled transaction has the same payee name. Loan and mortgage payments are transfers, so they are not included, and refunds are not netted. A heuristic; defaults to the last 365 days.

Writing

Tool

What it does

ynab_create_transaction

Creates a transaction. Needs date, amount, an account (accountId or accountName) and a payee (payeeId or payeeName); category optional as categoryId or categoryName, or subtransactions to split it.

ynab_update_transaction

Updates any subset of an existing transaction's fields, or splits an unsplit one with subtransactions.

ynab_delete_transaction

Deletes a transaction. Not undoable.

ynab_bulk_approve_transactions

Approves an array of transaction IDs in one API call, or un-approves them with approved: false.

ynab_apply_category_suggestions

Applies up to 25 explicit category suggestions with refetch and stale-data checks, dry-run support, and a pre-write undo manifest. Never auto-applies or approves transactions.

ynab_update_category_budget

Sets the total budgeted amount for one category in a month. Not an increment; use ynab_move_money to move money between categories.

ynab_import_transactions

Triggers an import from linked institutions, the same as hitting Import in the YNAB app.

ynab_move_money

Moves budgeted money between two categories in a month, for covering overspending.

ynab_auto_assign

Spreads Ready to Assign over categories with unmet monthly goals, largest shortfall first. dryRun to preview, maxTotal to cap it.

Names instead of IDs

ynab_create_transaction accepts accountName and categoryName and matches them loosely against the plan, so "ally checking" finds Ally Checking. Closed accounts and hidden categories are never matched. If a name is ambiguous or unrecognised the call fails and names the near misses rather than guessing, and successful calls echo back matchedAccount / matchedCategory so a wrong guess is visible.

Split transactions

ynab_create_transaction and ynab_update_transaction split a transaction across categories when given subtransactions: two or more entries of { amount, category_name, payee_name, memo }, the same shape ynab_get_transactions returns for a split. Amounts are in dollars and must add up to the transaction amount exactly (on update, the new amount if given, otherwise the current one); categories go on the splits, not on the parent. Split category names are matched like categoryName and echoed back as matchedSplitCategories.

YNAB cannot change the splits of a transaction that is already split, so ynab_update_transaction refuses rather than silently dropping the change. Delete and recreate the transaction to re-split it.

Writes that can half-succeed

YNAB has no endpoint for moving money between categories, so ynab_move_money rewrites both categories' budgeted amounts in two calls. It takes from the source first, so a failure in between leaves the money in Ready to Assign rather than double-counted. When that happens the response sets partial: true and carries a recovery line with the original amount to restore. ynab_auto_assign behaves the same way: on failure it reports which categories were already funded and which were left alone.

Tools never throw at the protocol level. Failures come back as an MCP error result (isError: true) with { "success": false, "error": "..." } in the text content, so a failed write is never mistaken for a successful one.

Tool annotations

Every tool advertises MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) alongside its schema. Tools that change neither YNAB nor the Worker's service state are readOnlyHint: true; among the YNAB writing tools, only ynab_delete_transaction sets destructiveHint: true. A client may use these hints to decide which calls need a confirmation prompt.

cleared and flagColor

ynab_create_transaction and ynab_update_transaction accept cleared as one of cleared, uncleared, or reconciled, and flagColor as one of red, orange, yellow, green, blue, purple, or "" to clear an existing flag.

Development

npm run watch          # rebuild on change
npm test               # vitest (watch mode)
npm run test:run       # vitest, single run
npm run test:coverage  # coverage report
npm run typecheck      # typecheck both the node and Worker targets
npm run debug          # build, then open the MCP inspector
npm run dev:worker     # run the Worker locally with wrangler
npm run deploy         # deploy the Worker to Cloudflare

dist/ is a build artifact and is not tracked in git; npm run build regenerates it.

Releasing

Bump the version in package.json and update CHANGELOG.md, then merge to main and create a GitHub release tagged in the existing 0.2.0 style (without a v prefix). The workflow stages that release with npm; it does not make the package public. The maintainer must run npm stage list, review it, and run npm stage approve with 2FA to promote it live. Configure a Trusted Publisher on npmjs.com for ynab-mcp-server, pointing at GitHub repository calebl/ynab-mcp-server and the exact workflow filename .github/workflows/publish.yml (the filename must match exactly); under Allowed actions select only npm stage publish.

Adding a tool

Each tool is a self-contained module in src/tools/ exporting name, description, inputSchema (a Zod shape) and execute(input, api). See CLAUDE.md for the full template, then add the module to the tools array in src/registry.ts and write a test in src/tests/. Registering it there serves it from both the stdio server and the Worker; mark writes: true if the tool changes data, which is what YNAB_READ_ONLY filters on.

Useful references:

Contributing

Pull requests are welcome. For a new tool or a larger change, please open an issue first so we can agree on the scope.

  1. Fork the repository and create a branch from main.

  2. Make your change and add or update tests in src/tests/. New tools follow the pattern in Adding a tool.

  3. Run npm run test:run and npm run typecheck.

  4. Use Conventional Commits for commit messages and the pull request title.

  5. Open a pull request against main.

Every pull request runs the test suite on Node.js 22, 24 and 26 and receives an automated code review. Both checks must pass and review conversations must be resolved before the pull request can be merged.

Compatibility

These tool names are deprecated aliases. They still work for now, but are announced as deprecated in the next release and removed in the release after that:

Alias

Use instead

ynab_list_budgets

ynab_list_plans

ynab_budget_summary

ynab_plan_summary

ynab_get_unapproved_transactions

ynab_get_transactions with type: "unapproved"

ynab_approve_transaction

ynab_bulk_approve_transactions with a one-element transactionIds

budgetId and YNAB_BUDGET_ID are deprecated but still accepted; there is no removal date. Use planId and YNAB_PLAN_ID for new integrations.

License

See LICENSE.

Available Tools

26 tools
ynab_apply_category_suggestionsApply Category SuggestionsA
Idempotent

Applies explicitly supplied category suggestions after refetching and verifying every transaction fingerprint. Never auto-applies, approves, or calls TypeSafe. Supports dry-run and returns a pre-write undo manifest.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional; budgetId is a deprecated alias)
dry_runNoValidate without writing to YNAB
budgetIdNoDeprecated alias of planId
suggestionsYesExplicit category changes; maximum 25 rows

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare the safety profile (idempotentHint=true, destructiveHint=false, openWorldHint=true), yet the description adds real behavioral detail the annotations cannot: it refetches and verifies every fingerprint before writing, refuses to auto-apply, and returns a pre-write undo manifest.

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 compact sentences, front-loaded with the core action and its precondition, then the constraints, then the return guarantee. No 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 mutating tool with no output schema and full schema description coverage, this covers the action, the precondition, the safety guarantees, the dry-run escape hatch, and the return artifact (undo manifest). Nothing an agent needs to invoke it safely is missing.

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 still adds meaning by explaining that suggestions must carry fingerprints that are verified and by characterizing dry-run as a pre-write validation step. It stops short of clarifying the budgetId/planId alias relationship or the 25-item cap context, which the schema already covers.

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 (applies) plus resource (explicitly supplied category suggestions) and immediately bounds the scope with the fingerprint-refetch precondition. It is clearly distinguishable from siblings like ynab_auto_assign and ynab_update_transaction.

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 explicit negative guidance: it never auto-applies, approves, or calls TypeSafe, and it supports dry-run. It does not name the alternative tool (e.g. ynab_auto_assign) for auto-application, so the routing is implied rather than spelled out.

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

ynab_approve_transactionApprove Transaction (legacy)A
Idempotent

Deprecated alias of ynab_bulk_approve_transactions; use that instead

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
approvedNoWhether the transactions should be marked as approved (default true); false un-approves them
budgetIdNoDeprecated alias of planId (still accepted)
transactionIdYesThe id of the transaction to approve

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=false, idempotentHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered. The description adds one genuinely useful non-annotation fact — that the tool is deprecated — but says nothing about whether existing calls still work, whether behavior matches the bulk tool, or that the singular transactionId is a bulk-semantics wrapper. A 3 reflects real but thin added context.

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?

A single short sentence with the deprecation and the redirect front-loaded; there is no filler and nothing an agent must scroll past.

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 deprecated alias, the essential information an agent needs — don't use this, use that — is present and the schema is fully documented. It stops short of confirming whether the alias still functions or when it will be removed, which would fully close the loop.

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%, including the deprecated budgetId alias and the approved default/un-approve semantics, so the schema does all the work. The description adds no parameter guidance and notably does not flag the mismatch between a singular transactionId and the bulk target tool. Baseline 3 is correct.

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 identifies the tool as a deprecated alias and names the canonical sibling, ynab_bulk_approve_transactions, which combined with the title 'Approve Transaction (legacy)' makes the resource and action inferable. It does not directly state the verb+resource itself, relying on the title and sibling name to convey 'approve a transaction', but the sibling differentiation is explicit.

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 gives an unambiguous directive: use ynab_bulk_approve_transactions instead. That is the strongest possible when-to-use / when-not-to-use routing signal an agent could get for a deprecated alias.

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

ynab_auto_assignAuto AssignA

Distributes Ready to Assign across categories whose monthly goal is not yet fully funded, largest shortfall first, until the money runs out. Set dryRun to see the plan without changing anything.

NameRequiredDescriptionDefault
monthNoThe plan month in ISO format (e.g. 2024-01-01, must be the first of the month), or 'current'. Defaults to 'current'.
dryRunNoReturn the proposed assignments without writing them (default: false)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
maxTotalNoOnly assign up to this many dollars, even if more is available in Ready to Assign

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already indicate this is a write operation (readOnlyHint=false, idempotentHint=false). The description adds valuable behavioral context: it mutates budget assignments, respects a maxTotal cap, and dryRun prevents changes. It doesn't mention side effects like overwriting existing assignments, but the dryRun disclosure and allocation rule provide solid transparency beyond the annotations.

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

Conciseness5/5

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

Two sentences with no filler. The core behavior is front-loaded, and the dryRun safety note is placed second. Every word earns its place.

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 write tool with no output schema, the description explains the core behavior, the dryRun preview option, and the stopping condition. It doesn't describe the return value shape, but the absence of an output schema and the presence of dryRun make the behavior sufficiently clear for an agent to invoke it correctly.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all five parameters. The description adds context for dryRun ('see the plan without changing anything') and implies maxTotal's role, but doesn't add meaning beyond what the schema provides. Baseline 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 ('Distributes'), a clear resource ('Ready to Assign'), and a precise algorithm (largest shortfall first, until money runs out). It distinguishes itself from siblings like ynab_move_money and ynab_update_category_budget by describing an automated allocation behavior rather than a manual transfer or single-category update.

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 clearly explains what the tool does and when it applies (categories with monthly goals not fully funded), and mentions dryRun for previewing. It doesn't explicitly name alternative tools or state when not to use it, but the algorithm description makes the use case clear enough.

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

ynab_balance_forecastBalance ForecastA
Read-only

Projects the combined balance of your accounts over the next N days (from today in UTC) from scheduled transactions only: the starting balance, the scheduled events, the end-of-day running balance and the lowest point. Income or spending that is not scheduled in YNAB is not in the forecast. Transfers between two included accounts (credit card payments too) net to zero; a transfer to an account outside the forecast counts as money leaving, and one from an account outside it as money arriving. Split schedules are counted leg by leg. Occurrences whose date has passed but that YNAB has not entered yet count on the first day, marked overdue with their scheduled_date and summarised in overdue_schedules. Where YNAB does not give the second date of a twice-a-month schedule, it is approximated as 15 days after the first. Events are capped by limit; the running balance, low point and ending balance always cover every day. For past income versus spending, use ynab_cash_flow; to list the schedules themselves, use ynab_list_scheduled_transactions.

NameRequiredDescriptionDefault
daysNoHow many days ahead to project (default: 30, max: 365)
limitNoMaximum number of events to return, earliest first (default: 100; 0 leaves them out). event_count, the running balance, low point and ending balance always cover every event.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
accountIdsNoAccounts to include (IDs from ynab_list_accounts). Defaults to every open on-budget account.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already establish read-only, open-world, non-destructive behavior, but the description goes well beyond them: overdue occurrences are placed on day one and marked, twice-a-month schedules without a second date are approximated at +15 days, split schedules are counted leg by leg, and transfers net to zero or count as inflow/outflow depending on inclusion. It also discloses that limits cap event rows while balances always cover every day.

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

Conciseness4/5

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

The description is front-loaded with what is projected and what it returns, then proceeds through the accounting rules and alternatives. Every sentence carries behavioral information, though the single dense paragraph could be made easier to scan for such a rule-heavy 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?

For a read-only forecasting tool with no output schema, it covers outputs, inclusion rules, overdue handling, approximation rules, transfer netting, limit behavior, and routing to alternatives. An agent has enough to call it correctly and interpret results without further questions.

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% and already documents days, limit, planId, budgetId, and accountIds. The description adds genuine meaning beyond the schema for accountIds by explaining how included versus excluded accounts affect transfer accounting, and clarifies that the projection starts today in UTC. This is above the baseline 3 but not maximally additive since most parameter definitions are already well covered.

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: projects the combined account balance over the next N days from scheduled transactions, and enumerates the outputs (starting balance, scheduled events, end-of-day running balance, lowest point). An agent can distinguish this immediately from the sibling listing and cash-flow tools.

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?

Explicitly scopes the tool to scheduled transactions only and warns that unscheduled income/spending will not appear. It names two alternatives with their selecting conditions: ynab_cash_flow for past income versus spending, and ynab_list_scheduled_transactions to list the schedules themselves.

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

ynab_budget_summaryBudget Summary (legacy)A
Read-only

Deprecated alias of ynab_plan_summary; use that instead

NameRequiredDescriptionDefault
monthNoThe plan month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
budgetVsActualsNoAdd a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, openWorldHint=true and destructiveHint=false, so the safety profile is covered. The description adds the one trait annotations cannot express: deprecation status. It stops short of saying whether calls still succeed and return the same payload, which would have made it a 5.

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?

A single clause with zero waste, and the deprecation verdict plus the redirect are both front-loaded. Nothing could be removed without losing the routing signal.

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 deprecated alias with no output schema, the description gives everything needed to avoid calling it. It could add one clause confirming the tool still works and mirrors ynab_plan_summary's parameters, but no critical decision is blocked.

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% and every parameter (month, planId, budgetId, budgetVsActuals) is documented inline, including the deprecated budgetId alias. The description adds no parameter guidance, which is acceptable given the schema already carries it.

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 identifies the tool as a deprecated alias of ynab_plan_summary, which fully determines its behavior for an agent that knows the sibling. It doesn't restate the underlying verb/resource (budget summary for a month), relying on the name and title for that, so it is clear but not self-contained.

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?

'use that instead' is an explicit exclusion plus a named alternative, exactly the routing decision an agent needs. There is no ambiguity about whether to call this tool or the successor.

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

ynab_bulk_approve_transactionsBulk Approve TransactionsA
Idempotent

Approves (or, with approved: false, un-approves) one or more transactions in a single API call.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
approvedNoWhether the transactions should be marked as approved (default true); false un-approves them
budgetIdNoDeprecated alias of planId (still accepted)
transactionIdsYesArray of transaction IDs to approve

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=true), so the description only needs to add context. It usefully discloses that approvals are reversible via approved: false, but says nothing about partial failures in a bulk call, the 500-item cap, or the API/rate-limit cost of a single batched request.

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?

One sentence, zero filler, and the most decision-relevant bit (the un-approve capability) is parenthetically front-loaded.

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?

No output schema exists, so the description should ideally say what a bulk call returns on success or partial failure. With annotations and full schema coverage the core call is answerable, but an agent writing a mutation over up to 500 IDs is left guessing about error semantics.

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% and every parameter (planId, budgetId alias, approved, transactionIds) is documented in the schema itself. The description only restates the approved:false behavior, adding no syntax or ordering information beyond the schema, which is the baseline-3 case.

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 (Approves / un-approves) and resource (one or more transactions) plus the key batching trait 'in a single API call'. That implicitly distinguishes it from the singular ynab_approve_transaction sibling, but it never names that sibling, so the differentiation is left to inference.

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

Usage Guidelines3/5

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

There is no explicit 'use this when... use X instead when...' guidance. The bulk phrasing implies it should be preferred over ynab_approve_transaction for multiple IDs, but the agent has to derive that from 'one or more' rather than being told.

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

ynab_cash_flowCash FlowA
Read-only

Income versus spending, month by month, so you can see whether you are running a surplus. Uses YNAB's own monthly totals rather than re-adding transactions. For a projected balance, use ynab_balance_forecast.

NameRequiredDescriptionDefault
monthsNoHow many of the most recent months to report on (default: 6)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
sinceDateNoOnly include months on or after this date (ISO format: 2024-01-01). Overrides the months count.

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds a genuinely useful behavioral fact — totals come from YNAB's own monthly aggregates rather than recomputed transactions — but says nothing about return shape, currency units, or how months are bucketed when sinceDate and months overlap.

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 purpose, then a provenance note, then the alt-tool routing hint. Nothing is filler.

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 hint at the shape of the result (a monthly series of income/spending totals). It conveys the concept of monthly aggregates but not the structure, and it does not explain how optional planId/budgetId aliasing affects the call in practice.

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 months, planId, budgetId, and sinceDate are already documented, including the default of 6 months and the sinceDate-overrides-months precedence. The description adds nothing beyond that; baseline 3 applies.

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 resource and comparison (income versus spending, month by month) with the derived outcome (surplus). It also differentiates from the sibling ynab_balance_forecast, which covers projection, so an agent can route correctly 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?

Explicitly names the alternative (ynab_balance_forecast) and the condition that selects it (projected balance). It does not exclude adjacent siblings like ynab_spending_by_category or ynab_plan_summary, which also surface spending totals, so exclusions are incomplete.

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

ynab_create_transactionCreate TransactionA

Creates a new transaction in your YNAB plan. The account can be given as accountId or accountName, and the category as categoryId or categoryName - names are fuzzy-matched against the plan. Either payeeId or payeeName must also be provided. To split the transaction across categories, pass subtransactions instead of a category; their amounts must add up to the transaction amount.

NameRequiredDescriptionDefault
dateYesThe date of the transaction in ISO format (e.g. 2024-03-24)
memoNoA memo/note for the transaction (optional)
amountYesThe amount in dollars (e.g. -10.99 for money spent, 10.99 for money received)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
clearedNoThe cleared status of the transaction (optional, defaults to uncleared)
payeeIdNoThe id of the payee (optional if payeeName is provided)
approvedNoWhether the transaction is approved (optional, defaults to false)
budgetIdNoDeprecated alias of planId (still accepted)
accountIdNoThe id of the account to create the transaction in (optional if accountName is provided)
flagColorNoThe transaction flag color, or an empty string to clear the flag (optional)
payeeNameNoThe name of the payee (optional if payeeId is provided). YNAB creates the payee if it does not exist.
categoryIdNoThe category id for the transaction (optional)
accountNameNoThe name of the account, matched loosely against your accounts (e.g. 'ally checking'). Optional if accountId is provided.
categoryNameNoThe name of the category, matched loosely against your categories (e.g. 'groceries'). Optional; ignored if categoryId is provided.
subtransactionsNoSplits the transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries whose amounts sum to amount; omit categoryId/categoryName when splitting.

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=false, idempotentHint=false, destructiveHint=false and openWorldHint=true, so the write/non-idempotent profile is covered. The description's additions (fuzzy matching, split sum rule, payee requirement) largely restate schema text and omit genuinely useful behavior such as duplicate re-submission risk or the account/category resolution failure mode, so it adds modest value.

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 purpose and then the mutually-exclusive parameter rules; each sentence carries information. Slightly dense with parenthetical-style alternatives but 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?

For a 15-parameter, mutation-heavy tool with no output schema, the description covers creation semantics, the id/name alternatives, payee requirement and split mechanics. It does not cover return shape or resolution failures for unmatched names, but annotations carry the safety profile so this is largely sufficient.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description genuinely adds a cross-field constraint not captured by the schema: that either payeeId or payeeName must be provided, and that subtransactions replace (not supplement) categoryId/categoryName. This goes beyond per-parameter schema text.

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

Purpose4/5

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

The description opens with a specific verb+resource ('Creates a new transaction in your YNAB plan'), making the operation unambiguous. It is implicitly distinguishable from ynab_update_transaction and ynab_delete_transaction by the verb, but never names or contrasts an alternative explicitly.

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 conditional usage rules: account via accountId OR accountName, category via categoryId OR categoryName, payee required via payeeId OR payeeName, and subtransactions instead of a category when splitting. However, it offers no guidance on when to choose this over siblings like ynab_import_transactions or ynab_update_transaction.

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

ynab_delete_transactionDelete TransactionA
Destructive

Deletes a transaction from the plan. This action cannot be undone.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
transactionIdYesThe ID of the transaction to delete

TDQS

A3.6/5.0
Behavior3/5

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

The annotation destructiveHint=true already signals destruction, but the description adds the important context that the action cannot be undone. However, it does not elaborate on downstream effects, such as impact on account balances or related scheduled transactions, so it adds only modest value beyond the annotations.

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

Conciseness5/5

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

Two short sentences with no filler: the first states the action and target, the second warns about irreversibility. Every word earns its place, and 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 simple destructive operation with one required parameter and annotations already declaring destructive/read-only behavior, the description is largely sufficient. It could mention what happens after deletion or what response to expect, but that is not essential for invoking the tool correctly.

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%, and the schema already documents transactionId as the target ID plus planId/budgetId fallback behavior. The description adds no parameter-level meaning beyond what the schema provides, so the baseline score 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?

States a specific verb ('Deletes'), a specific resource ('a transaction'), and the scope ('from the plan'). This clearly distinguishes it from sibling tools like ynab_update_transaction or ynab_create_transaction. The purpose is immediately unambiguous.

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?

No guidance is given about when to choose this tool over alternatives, nor any conditions or prerequisites for deletion. The agent is left to infer that this is the destructive counterpart to update/create tools.

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

ynab_detect_recurringDetect RecurringA
Read-only

Finds recurring outflows (subscriptions, bills, memberships) in transaction history by payee, similar amount and regular spacing, whether or not they are scheduled in YNAB. For the scheduled transactions set up in YNAB, use ynab_list_scheduled_transactions. Gives each one's cadence, typical amount, yearly cost at the latest amount, next expected date, whether it seems to have stopped, and already_scheduled (a scheduled transaction has the same payee name; amounts are not compared). This is a heuristic: check the results before acting on them. Splits are counted through their subtransactions. Transfers are excluded, so loan and mortgage payments (transfers to a loan account) and credit card payments are not reported. Inflows are excluded too, and refunds are not netted against charges. Reads the whole window from YNAB in one request, which is slow for a long sinceDate on a busy plan. Yearly charges need a sinceDate far enough back to show minOccurrences of them.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
sinceDateNoStart of the history to scan, inclusive (ISO format: 2025-01-01). Defaults to 365 days ago.
minOccurrencesNoOn how many different dates one payee must charge a similar amount to make a pattern (default: 3)
amountTolerancePctNoHow far above the smallest charge in a group another charge may be and still count, in percent with up to 3 decimal places (default: 10)

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/destructive, but the description adds substantial context beyond them: the result is heuristic, splits are counted through subtransactions, transfers and inflows are excluded, refunds are not netted, and already_scheduled only matches on payee name without comparing amounts. It also discloses a real performance trait ('reads the whole window from YNAB in one request, which is slow for a long sinceDate on a busy plan'), which an agent needs to pick sane arguments.

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?

Purpose and the sibling alternative are front-loaded, then return fields, then caveats and performance. Nearly every sentence carries actionable information, though the exclusion/refund/netting sentences could be tightened into one clause without losing content.

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?

There is no output schema, and the description fully enumerates the return fields (cadence, typical amount, yearly cost at latest amount, next expected date, stopped flag, already_scheduled). Combined with the heuristic warning, exclusion rules, and cost-of-call note, an agent has everything needed to call and interpret 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?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning by tying sinceDate to minOccurrences ('Yearly charges need a sinceDate far enough back to show minOccurrences of them') and explaining the exclusion filter that determines what the scan sees. It does not, however, add anything about amountTolerancePct's grouping semantics 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?

States a specific verb and resource ('Finds recurring outflows ... in transaction history') plus the matching criteria (payee, similar amount, regular spacing) and scope (whether or not they are scheduled in YNAB). It explicitly distinguishes itself from the nearest sibling, ynab_list_scheduled_transactions, so an agent can choose without opening either schema.

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?

Names the alternative and the condition that selects it ('For the scheduled transactions set up in YNAB, use ynab_list_scheduled_transactions'), and adds a when-not caveat ('This is a heuristic: check the results before acting on them'). It also gives a concrete usage precondition: a sinceDate far enough back for yearly charges to reach minOccurrences.

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

ynab_get_transactionsGet TransactionsA
Read-only

Gets transactions from a plan, optionally between a start and end date and by type (all, uncategorized or unapproved). Filter by at most one of account, category or payee: they cannot be combined, and if several are given only the first in that order is applied. To search, add payee or memo text, an amount range or a direction. Any search option (or untilDate) adds inflow, outflow and net totals over every match; the totals include transfers between accounts, such as credit card payments. totalsOnly returns just the totals (e.g. categoryId with a year's dates and totalsOnly). Without categoryId or payeeId, split transactions are matched leg by leg and the totals count only the matching legs. With categoryId or payeeId, rows are matched as YNAB returns them, so a split's parent row in the payee listing counts at its full amount.

NameRequiredDescriptionDefault
typeNoFilter by transaction type. Defaults to 'all'.
limitNoMaximum number of transactions to return (default: 100). Totals always cover every match.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
payeeIdNoFilter to only transactions with this payee
budgetIdNoDeprecated alias of planId (still accepted)
accountIdNoFilter to only transactions in this account
directionNoOnly money going out, coming in, or both. Defaults to 'any'.
maxAmountNoLargest amount to include, ignoring sign, in currency units
minAmountNoSmallest amount to include, ignoring sign, in currency units (e.g. 25.50)
sinceDateNoOnly return transactions on or after this date (ISO format: 2024-01-01)
untilDateNoOnly return transactions on or before this date (ISO format: 2024-12-31)
categoryIdNoFilter to only transactions in this category
totalsOnlyNoReturn only the totals, without transaction rows (default: false)
memoContainsNoOnly transactions whose memo contains this text (case-insensitive)
payeeContainsNoOnly transactions whose payee name contains this text (case-insensitive)

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already cover safety (readOnly, non-destructive), and the description adds substantial non-obvious behavior on top: totals always cover every match regardless of limit, totals include inter-account transfers like credit card payments, and split transactions match leg-by-leg without categoryId/payeeId but as a full parent row with them. This is exactly the context annotations cannot express.

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 core purpose is front-loaded in the first sentence and every subsequent sentence carries real information about filters, totals or splits. It is a dense run-on paragraph, though, with the split-transaction caveat trailing at the end where it is easy to miss.

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 15-parameter read tool with no output schema, the definition covers the filter precedence, the date/type defaults, search-triggered aggregate behavior and the split-matching edge case. An agent can call this correctly and predict what the totals contain without further documentation.

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 field-level meaning is already documented; the description adds genuine cross-parameter semantics the schema cannot encode, namely the mutual exclusion and precedence order among accountId, categoryId and payeeId, and how categoryId/payeeId change split-row matching. Those additions push it above the baseline 3.

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 with scope: gets transactions from a plan, with date, type and filter scope spelled out. It never names a sibling to use instead, so an agent facing ynab_get_unapproved_transactions or ynab_spending_by_category has to infer the boundary, which keeps it out of the top band.

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 concrete usage rules: at most one of account/category/payee may be used, and if several are supplied only the first in that order applies. It also explains what triggers totals and when totalsOnly is appropriate (categoryId plus a year of dates). No explicit when-not-use or sibling routing, so it falls short of a 5.

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

ynab_get_unapproved_transactionsGet Unapproved Transactions (legacy)A
Read-only

Deprecated alias of ynab_get_transactions; use that instead

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
sinceDateNoOnly return transactions on or after this date (ISO format: 2024-01-01)

TDQS

A4/5.0
Behavior3/5

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

Annotations already cover safety (readOnlyHint=true, destructiveHint=false, idempotentHint=false), so the bar is lower; the description adds the deprecation status, which is not in annotations and is genuinely useful. However, it does not state whether the alias still resolves, whether it forwards the same filters, or whether behavior differs from the canonical 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?

One short sentence, front-loaded with the deprecation status and followed immediately by the actionable redirect. Nothing superfluous for a stub of this kind.

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 deprecated alias with a fully documented schema and annotations carrying the safety profile, the description gives the one fact an agent needs: don't call this, call ynab_get_transactions. The only gap is whether invoking it still produces results and whether those results are filtered to unapproved transactions.

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% and all three parameters are optional, with the schema already explaining planId defaults, the budgetId alias, and the ISO date format. The description adds nothing about parameters, so the 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?

The description states plainly that this is a deprecated alias and names the replacement, ynab_get_transactions, which distinguishes it from the sibling tool it shadows. It does not say what the tool actually returns if invoked (unapproved-only, as the name implies, versus the full list the alias points to), so the purpose is clarified only at the deprecation level.

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 gives an unambiguous directive: use ynab_get_transactions instead. That is an explicit when-not-to-use plus the correct alternative, which is exactly what usage guidance should do for a deprecated stub.

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

ynab_import_transactionsImport TransactionsA

Imports available transactions on all linked accounts for the plan. This triggers an import from connected financial institutions (equivalent to clicking 'Import' in the YNAB app).

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)

TDQS

A3.7/5.0
Behavior3/5

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

Annotations already mark this as non-read-only and non-idempotent; the description adds that it triggers an import from connected financial institutions, which is useful. However, it does not disclose potential side effects beyond the import (e.g., rate limits, network delays, or whether existing pending transactions are overwritten), so the added transparency is modest.

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 two sentences with no filler. The first sentence front-loads the core action and scope; the second adds a clarifying analogy to the YNAB app. Every word earns its place.

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 tool with two optional parameters and no output schema, the description explains the action and scope, but it does not indicate what the caller receives after the import (e.g., transaction details, count, or confirmation status). This is a meaningful gap because the absence of an output schema leaves the agent guessing about the return value.

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 input schema provides 100% description coverage for planId and budgetId, including defaulting and deprecation notes, so the description does not need to compensate. The description adds no parameter-specific semantics, which is appropriate given the schema completeness; baseline 3 applies.

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 ('imports'), a precise resource ('available transactions on all linked accounts for the plan'), and clarifies the action as equivalent to clicking Import in the YNAB app. This clearly separates it from sibling tools like create_transaction, get_transactions, and approve_transaction.

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?

The description implies the tool is used to synchronize external bank data by comparing it to the app's Import button, but it does not explicitly state when to use it versus alternatives or when not to use it. No exclusions or alternative tool names are mentioned, so usage guidance is only implicit.

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

ynab_list_accountsList AccountsA
Read-only

Lists all accounts in a plan. Useful for finding account IDs when creating transactions.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
includeClosedAccountsNoInclude closed accounts in the list (default: false)

TDQS

A4.1/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the main safety profile is covered. The description adds that all accounts in a plan are returned and that IDs are the useful output, but it does not disclose pagination, ordering, or closed-account handling beyond the schema's includeClosedAccounts field.

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 short sentences, no filler, with the action and resource stated first and the use case added as a second sentence. Every sentence earns its place.

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 simple read-only list operation with optional parameters, the description plus fully-covered schema and annotations provide everything an agent needs to invoke it correctly. No output schema is available, but the stated use case (account IDs) covers the expected return value.

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 fully documents planId, budgetId, and includeClosedAccounts. The description itself adds no parameter-level detail, but the baseline of 3 applies because the schema carries the param semantics.

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 'lists' with a clear resource ('all accounts in a plan'), and immediately states the practical purpose of finding account IDs for creating transactions. This distinguishes it from sibling tools like ynab_list_payees, ynab_list_categories, and ynab_get_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?

It gives clear context for when to use the tool: before creating transactions to look up account IDs. It does not explicitly name alternative tools or state when not to use it, but the use case is specific enough to guide selection.

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

ynab_list_budgetsList Budgets (legacy)A
Read-only

Deprecated alias of ynab_list_plans; use that instead

NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/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=true, so the safety profile is covered. The description adds the deprecation status, which is genuinely the most important behavioral fact here, but says nothing about whether calls still succeed, return empty data, or redirect.

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?

A single short sentence that front-loads the deprecation and the remedy. Zero waste.

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 no-param deprecated alias with full schema coverage, routing the agent to the successor is the essential content. Only the runtime behavior of calling the deprecated endpoint (error vs. empty result) is left unstated.

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 tool takes zero parameters, so there is nothing for the description to explain and the baseline applies. No misleading parameter information is present.

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?

It states the tool's identity precisely as a deprecated alias of ynab_list_plans, which is the only purpose a deprecated stub can have. It doesn't independently describe listing budgets, but the pointer to the live tool covers the intent.

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?

Explicitly directs the agent to use ynab_list_plans instead, naming the alternative in the sibling list. There is no ambiguity about when to call this versus the replacement.

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

ynab_list_categoriesList CategoriesA
Read-only

Lists all categories in a plan, grouped by category group. Useful for finding category IDs when creating transactions or updating budgeted amounts.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already cover the read-only, non-destructive nature via readOnlyHint=true and destructiveHint=false. The description adds meaningful behavior: categories are returned in groups and all categories are included. It does not cover edge cases like archived or hidden categories, but the annotation coverage lowers the burden.

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 sentences with no filler. The core listing behavior is front-loaded, followed by a practical use case. It does not repeat annotations or schema details unnecessarily.

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 simple read-only list tool with two optional and fully documented parameters, the description plus annotations are sufficient. The output behavior is described as grouped categories containing IDs, and the safe read-only profile is clear. Nothing critical is missing for correct invocation.

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 planId and budgetId are already fully documented including defaults and the deprecation alias. The description does not add parameter-level meaning beyond the schema, so the baseline score 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 it lists all categories in a plan, grouped by category group. This specific verb+resource combination distinguishes it from sibling tools like ynab_list_accounts and ynab_list_payees. The mention of finding category IDs makes the exact output purpose unambiguous.

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 usage context: useful for finding category IDs when creating transactions or updating budgeted amounts. It does not explicitly name alternatives or state when not to use the tool, but the scenario-based guidance is clear enough for routing.

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

ynab_list_monthsList MonthsA
Read-only

Lists every plan month since the plan began, with raw summary fields: income, budgeted, activity, Ready to Assign, age of money and the month note. For income-versus-spending questions over recent months, use ynab_cash_flow instead.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnly, non-destructive and openWorld, so safety is covered. The description adds real context beyond that: the result covers every month since the plan began and returns raw summary fields rather than aggregates. It does not mention ordering or whether results are paginated, which is the remaining gap.

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 sentences, no waste, with the scope-and-fields statement front-loaded ahead of the disambiguation pointer. Every clause carries information an agent needs.

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 usefully names the returned fields and the time scope, and both optional params are covered by the schema. Only minor behavioral details (ordering, month format, pagination) are unstated.

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% and both parameters (planId and its deprecated budgetId alias, with the YNAB_PLAN_ID default) are fully documented in the schema. The description says nothing about parameters, so baseline 3 applies — the schema does all the work.

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 (lists every plan month since the plan began) and enumerates the fields returned (income, budgeted, activity, Ready to Assign, age of money, note). It also names the sibling it is not (ynab_cash_flow), so an agent can distinguish it without opening either 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 an explicit exclusion with the alternative: for income-versus-spending questions over recent months, use ynab_cash_flow instead. What is missing is a positive statement of when this tool is the right pick (e.g. historical month-by-month raw figures), leaving half the routing decision implied.

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

ynab_list_payeesList PayeesA
Read-only

Lists all payees in a plan. Useful for finding payee IDs when creating transactions.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, covering safety. The description adds that it lists 'all' payees, which is a useful scope note, but it doesn't disclose any behavioral quirks like pagination or performance. The bar is lower due to annotations, so a 3 is appropriate.

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 concise sentences with no filler. The core action is front-loaded, and the usage hint is placed second. Every word earns its place.

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 simple read-only list tool with optional parameters and no output schema, the description adequately covers purpose and usage. It implicitly conveys that payee IDs are returned ('useful for finding payee IDs'), but it could be more explicit about the exact return shape. Still, it's largely complete.

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 has 100% description coverage for both parameters (planId and budgetId), and the description adds no additional parameter details. With high schema coverage, the baseline is 3, and no extra value is provided 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 tool lists all payees in a plan, which is a specific verb and resource. It also explicitly mentions its utility for finding payee IDs when creating transactions, distinguishing it from sibling tools like ynab_list_accounts or ynab_list_categories.

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 provides a concrete usage context: find payee IDs for creating transactions. While it doesn't explicitly mention alternatives or when not to use it, the purpose is clear enough and the sibling set is large but the tool's specific role is obvious.

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

ynab_list_plansList PlansA
Read-only

Lists all available plans from YNAB API

NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds only that it returns all available plans, which is consistent but does not add meaningful behavioral detail beyond the annotations.

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

Conciseness5/5

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

The description is a single sentence with no wasted words. It front-loads the action and resource immediately, which is ideal for a simple no-parameter tool.

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 zero-parameter read-only list tool, the description is sufficient: it states the output scope ('all available plans') and source. There is no output schema, but the description's phrasing adequately conveys that the result is a list of plans without requiring deeper return-value explanation.

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 tool has zero parameters, so the input schema is empty and there is no semantic burden on the description. The baseline of 4 applies because no parameter documentation is needed.

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 a specific verb ('Lists') and resource ('all available plans from YNAB API'), clearly identifying the scope. It is distinguishable from siblings like ynab_plan_summary because it explicitly says 'lists all available plans' rather than summarizing a single plan.

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?

No guidance is provided about when to use this tool versus alternatives such as ynab_plan_summary. The description merely states what the tool does, leaving the agent to infer selection criteria without any exclusions or comparisons.

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

ynab_list_scheduled_transactionsList Scheduled TransactionsA
Read-only

Lists the scheduled transactions set up in YNAB. To find recurring charges in transaction history, including ones that are not scheduled, use ynab_detect_recurring. For a projected balance, use ynab_balance_forecast.

NameRequiredDescriptionDefault
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)

TDQS

A3.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, openWorldHint=true and idempotentHint=false, so the safety profile is covered. The description does not contradict them and adds the conceptual split between scheduled objects and historical recurring charges, but says nothing about pagination, ordering, whether inactive/completed schedules are included, or auth/plan requirements.

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 two routing pointers. Every sentence earns its place with zero filler.

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?

There is no output schema, so the description is the only place an agent could learn what a scheduled transaction record contains (date, amount, frequency, account, next occurrence) or how results are ordered. For a simple zero-required-param list tool this is adequate, but the return shape remains undocumented.

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% and the schema already explains planId defaults to YNAB_PLAN_ID and that budgetId is a deprecated alias. The description adds no parameter guidance, so the baseline 3 applies since the schema does the heavy lifting.

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 ('Lists') and resource ('scheduled transactions set up in YNAB'), and immediately distinguishes itself from ynab_detect_recurring (transaction-history recurring charges) and ynab_balance_forecast (projection). An agent can differentiate it from ynab_get_transactions and the recurring sibling without opening any 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?

Names two alternatives with explicit conditions for choosing each ('To find recurring charges in transaction history... use ynab_detect_recurring', 'For a projected balance, use ynab_balance_forecast'). It does not state the positive condition for this tool (e.g., 'use when the user wants upcoming scheduled entries'), but the contrast makes the routing clear.

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

ynab_move_moneyMove MoneyA

Moves budgeted money from one category to another in a given month, typically to cover overspending. YNAB has no single move endpoint, so this reads both categories and rewrites their budgeted amounts; if the second write fails the response says exactly which half was applied.

NameRequiredDescriptionDefault
monthNoThe plan month in ISO format (e.g. 2024-01-01, must be the first of the month), or 'current'. Defaults to 'current'.
amountYesThe amount to move in dollars (e.g. 25.00). Must be positive.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
toCategoryIdYesThe ID of the category to give money to
fromCategoryIdYesThe ID of the category to take money from

TDQS

A4.5/5.0
Behavior5/5

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

The description goes well beyond the annotations by disclosing the non-atomic implementation: it reads both categories, rewrites both budgeted amounts, and explains the partial-failure response. This is exactly the kind of behavioral detail an agent needs and that annotations cannot express.

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 sentences: the first states the core action and typical use; the second adds only high-value implementation and failure-mode details. There is no filler, repetition, or unnecessary background.

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 mutation tool with six fully documented parameters, the description provides the missing behavioral context: non-atomicity, partial-failure reporting, and the cover-overspending purpose. The only omitted detail is the exact success return shape, but the description's failure-mode disclosure compensates and no output schema is defined.

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 month format/default, positive amount, plan/budget IDs, and category IDs. The description adds no new parameter-level semantics beyond restating the transfer direction, so the baseline of 3 applies.

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 opens with a specific verb and direct object: 'Moves budgeted money from one category to another in a given month.' It also clarifies the motivating use case, covering overspending, and distinguishes itself from a plain category budget update by noting there is no single YNAB move endpoint.

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?

'Typically to cover overspending' gives a concrete triggering context, and the move-vs-set semantics imply when this tool is appropriate rather than a simple budget update. It does not explicitly name alternatives or exclusions, but the intended usage is clear enough.

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

ynab_plan_summaryPlan SummaryA
Read-only

Get a summary of the plan for a specific month highlighting overspent categories that need attention and categories with a positive balance that are doing well. Set budgetVsActuals to also compare assigned with actual spending that month: budgeted, activity, balance, variance (budgeted plus activity; below zero means more was spent than assigned) and percent used for every visible category, with subtotals per category group and overall totals, which leave out Credit Card Payments.

NameRequiredDescriptionDefault
monthNoThe plan month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
budgetVsActualsNoAdd a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare a read-only, non-destructive operation. The description adds useful behavioral context beyond that: it explains the default summary focus and details what appears in the optional budgetVsActuals block, including the fact that overall totals exclude Credit Card Payments.

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 dense but front-loaded and every sentence carries useful information about scope or output. It avoids filler, though the main sentence is long and could be slightly easier to scan.

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

Completeness4/5

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

With no output schema and annotations covering safety, the description does most of the work by explaining the default summary behavior and the optional budgetVsActuals output structure. It leaves some detail unspecified, such as the exact shape of the default summary, but it is complete enough to call the tool correctly.

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 schema already documents the parameters. The description still adds meaningful semantics for budgetVsActuals, clarifying the fields returned and defining variance as budgeted plus activity, where below zero means overspending.

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 states a specific verb and resource: get a plan summary for a month, with emphasis on overspent and positive-balance categories. It is clear what the tool does, but it does not explicitly differentiate itself from siblings such as ynab_budget_summary or ynab_spending_by_category.

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?

The description implies usage by mentioning overspent categories and positive balances, and it gives a condition for enabling budgetVsActuals. However, it does not say when to use this tool versus alternatives or when not to use it.

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

ynab_spending_by_categorySpending By CategoryA
Read-only

Totals spending per category over a date range, biggest spend first. Splits are counted through their subtransactions, and transfers between your own accounts are excluded. Totals are gross outflows: refunds and other inflows aren't netted, so they can differ from a category's activity in YNAB. With monthly: true, each category also gets a month-by-month series, its mean over full months, and how its last full month compares with the earlier ones.

NameRequiredDescriptionDefault
limitNoOnly return the top N categories by spend
monthsNoWith monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
monthlyNotrue adds the top-level months list and, on each category, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many categories, pair it with limit.
budgetIdNoDeprecated alias of planId (still accepted)
sinceDateNoStart of the range, inclusive (ISO format: 2024-01-01). Defaults to 30 days ago.
untilDateNoEnd of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true.

TDQS

A3.9/5.0
Behavior5/5

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

Goes well past the readOnly/destructive annotations: it discloses that splits are rolled through subtransactions, that own-account transfers are excluded, and that totals are gross outflows where refunds are not netted — an accounting caveat that will change how an agent interprets the numbers. It also flags that partial and in-progress months are listed but excluded from averages and change_pct.

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 operation before the accounting caveats and the optional monthly mode. Slightly dense — the last sentence restates material already in the months/monthly schema descriptions — but no sentence is 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?

With no output schema, the description usefully names the return concepts (per-category totals, monthly_totals, average_monthly, change_pct) and the exclusion rules that govern them. It stops short of describing the top-level response envelope or how categories with zero spend are represented, which an analytics tool of this shape could reasonably state.

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% and the schema's own monthly/sinceDate/untilDate descriptions are actually more detailed than the prose here, so the description adds little parameter meaning beyond a restatement of the monthly aggregation semantics. Baseline 3 is correct when the schema does the heavy lifting.

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 and resource (totals spending per category) plus the aggregation window and sort order ('biggest spend first'), which is far more than a restatement of the title. It never names the obvious alternative, ynab_spending_by_payee, so the category-vs-payee split must be inferred from the name rather than stated.

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?

Usage is implied rather than stated: the description covers defaults, the limit pairing hint ('With many categories, pair it with limit'), and how months/sinceDate interact, but never says when to pick this tool over ynab_spending_by_payee, ynab_cash_flow, or ynab_budget_summary. An agent must infer the selection from the resource noun.

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

ynab_spending_by_payeeSpending By PayeeA
Read-only

Totals spending per payee over a date range, biggest spend first - where the money actually goes by merchant. Splits are counted through their subtransactions, and transfers between your own accounts are excluded. Totals are gross outflows: refunds and other inflows aren't netted, so they can differ from a category's activity in YNAB. With monthly: true, each payee also gets a month-by-month series, its mean over full months, and how its last full month compares with the earlier ones.

NameRequiredDescriptionDefault
limitNoOnly return the top N payees by spend
monthsNoWith monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
monthlyNotrue adds the top-level months list and, on each payee, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many payees, pair it with limit.
budgetIdNoDeprecated alias of planId (still accepted)
sinceDateNoStart of the range, inclusive (ISO format: 2024-01-01). Defaults to 30 days ago.
untilDateNoEnd of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true.

TDQS

A4/5.0
Behavior5/5

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

Goes well beyond the read-only annotations by disclosing key semantics: splits are counted through subtransactions, internal transfers are excluded, totals are gross outflows with refunds/inflows not netted, and monthly mode adds month-by-month figures with specific treatment of partial months. This is exactly the behavioral context an agent needs to interpret results correctly.

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?

Front-loads the purpose in the first sentence, then layers in the critical behavioral caveats and the monthly option. Every sentence earns its place; there is no filler or repetition of the schema beyond a concise monthly summary.

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 an aggregation read tool with no output schema, the description covers purpose, exclusions, gross-vs-net semantics, and monthly output behavior well. It still does not describe the base return shape (e.g., payee name and total fields) or pagination/limit behavior, which would fully complete the picture.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all 7 parameters in detail, including monthly, months, sinceDate, untilDate, limit, and planId/budgetId. The description only summarizes the monthly behavior and does not add parameter semantics beyond what the schema provides, so baseline 3 is appropriate.

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 ('Totals spending per payee') plus scope ('over a date range, biggest spend first') and the merchant-spend angle. It contrasts implicitly with category activity but does not name the sibling ynab_spending_by_category, so sibling differentiation is present but not explicit.

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?

The description implies when this tool is useful (merchant/payee-level spending) and notes that totals can differ from a category's activity. However, it gives no explicit when-to-use/when-not-to-use guidance or direct routing to alternatives such as ynab_spending_by_category.

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

ynab_update_category_budgetUpdate Category BudgetA
Idempotent

Sets the total budgeted amount for one category in a specific month (not an increment). To move money between categories, use ynab_move_money instead.

NameRequiredDescriptionDefault
monthYesThe plan month in ISO format (e.g. 2024-01-01). Must be the first day of the month.
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
budgetIdNoDeprecated alias of planId (still accepted)
budgetedYesThe amount to budget in dollars (e.g. 500.00). This sets the total budgeted amount, not an increment.
categoryIdYesThe ID of the category to update

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the safety profile is carried structurally. The description adds the most consequential behavioral fact – that this overwrites the total rather than adding to it – which explains the idempotency. It does not cover auth requirements or failure behavior, keeping it short of a 5.

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 sentences, zero waste, with the highest-risk semantic caveat front-loaded and the alternative routing delegated to sentence two.

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 mutation tool with annotations covering safety, full schema coverage, and no output schema, the description supplies the two facts an agent most needs: absolute-set semantics and sibling routing. Minor omission – no mention of what the write affects or returns – but nothing essential is missing for correct invocation.

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%, including the fact that 'budgeted' sets the total rather than an increment, so the description's '(not an increment)' clause largely restates the schema. Baseline 3 is appropriate since the schema does the heavy lifting on month format, planId defaults, and deprecation.

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 (sets), resource (budgeted amount), and precise scope (one category, one month), and explicitly disambiguates the semantics with '(not an increment)'. An agent can distinguish it from ynab_move_money without opening either schema.

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?

Names the alternative tool (ynab_move_money) and the condition that selects it (moving money between categories). Combined with the explicit 'not an increment' exclusion, both the when-to-use and when-not-to-use cases are covered.

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

ynab_update_transactionUpdate TransactionA
Idempotent

Updates an existing transaction. All fields except transactionId are optional - only provide fields you want to change. Pass subtransactions to split an ordinary transaction across categories; YNAB cannot re-split a transaction that is already split.

NameRequiredDescriptionDefault
dateNoThe date of the transaction in ISO format (e.g. 2024-03-24)
memoNoA memo/note for the transaction
amountNoThe amount in dollars (e.g. -10.99 for outflow, 10.99 for inflow)
planIdNoThe plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)
clearedNoThe cleared status
payeeIdNoThe ID of the payee
approvedNoWhether the transaction is approved
budgetIdNoDeprecated alias of planId (still accepted)
accountIdNoMove transaction to a different account
flagColorNoThe transaction flag color, or an empty string to clear the flag
payeeNameNoThe name of the payee (creates new payee if doesn't exist)
categoryIdNoThe category ID for the transaction
transactionIdYesThe ID of the transaction to update
subtransactionsNoSplits an ordinary transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries summing to amount (or the current amount if amount is omitted); omit categoryId. Not allowed on a transaction that is already split.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=false, idempotentHint=true, destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral context beyond them: patch semantics for omitted fields and the permanent restriction that YNAB cannot re-split an already-split transaction. It does not mention auth/permission requirements or error behavior on an invalid transactionId.

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 sentences, no filler, and the most load-bearing fact (only transactionId required; only send what you want changed) is front-loaded ahead of the edge case about splitting.

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 mutation tool whose annotations already carry the safety profile and whose schema is fully documented, this covers the mutation model, the split workflow and its key limitation. Minor gaps remain around permissions and failure modes on a bad transactionId, but nothing essential to invoking it correctly is missing.

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 and the schema already documents all 14 parameters including the split sub-shape. The description adds a usage rule the schema does not state plainly - supply only the fields you intend to change, and omit categoryId when passing subtransactions - which meaningfully affects how parameters are passed.

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 ("Updates an existing transaction") and immediately clarifies the patch semantics, so an agent understands this is a partial mutation rather than a replace. It never names the sibling it is distinguished from (ynab_create_transaction, ynab_delete_transaction, ynab_approve_transaction), so it stops short of a 5.

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?

"All fields except transactionId are optional - only provide fields you want to change" gives clear when-to-use guidance for a patch tool, and the subtransactions sentence states the condition and the one hard exclusion (cannot re-split an already-split transaction). No explicit routing to alternative siblings (e.g. approve vs update), which keeps it below 5.

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. 10 tool updatesv0.6.0
    • Changedynab_approve_transaction2 fields changed
      • changedInput schema / properties / approved / anyOf
        Previous value: -[
        -  {
        -    "default": true,
        -    "description": "Whether the transaction should be marked as approved",
        -    "type": "boolean"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "default": true,
        +    "description": "Whether the transactions should be marked as approved (default true); false un-approves them",
        +    "type": "boolean"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / approved / description
        Previous value: -"Whether the transaction should be marked as approved"New value: +"Whether the transactions should be marked as approved (default true); false un-approves them"
    • Addedynab_balance_forecast
    • Changedynab_budget_summary1 field changed
      • addedInput schema / properties / budgetVsActuals
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Add a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Add a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)"
        +}
    • Changedynab_bulk_approve_transactions1 field changed
      • addedInput schema / properties / approved
        Added value: +{
        +  "anyOf": [
        +    {
        +      "default": true,
        +      "description": "Whether the transactions should be marked as approved (default true); false un-approves them",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Whether the transactions should be marked as approved (default true); false un-approves them"
        +}
    • Addedynab_detect_recurring
    • Changedynab_get_transactions9 fields changed
      • addedInput schema / properties / direction
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Only money going out, coming in, or both. Defaults to 'any'.",
        +      "enum": [
        +        "outflow",
        +        "inflow",
        +        "any"
        +      ],
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Only money going out, coming in, or both. Defaults to 'any'."
        +}
      • changedInput schema / properties / limit / anyOf
        Previous value: -[
        -  {
        -    "description": "Maximum number of transactions to return (default: 100)",
        -    "exclusiveMinimum": 0,
        -    "maximum": 1000,
        -    "type": "integer"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Maximum number of transactions to return (default: 100). Totals always cover every match.",
        +    "exclusiveMinimum": 0,
        +    "maximum": 1000,
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum number of transactions to return (default: 100)"New value: +"Maximum number of transactions to return (default: 100). Totals always cover every match."
      • addedInput schema / properties / maxAmount
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Largest amount to include, ignoring sign, in currency units",
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Largest amount to include, ignoring sign, in currency units"
        +}
      • addedInput schema / properties / memoContains
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Only transactions whose memo contains this text (case-insensitive)",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Only transactions whose memo contains this text (case-insensitive)"
        +}
      • addedInput schema / properties / minAmount
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Smallest amount to include, ignoring sign, in currency units (e.g. 25.50)",
        +      "minimum": 0,
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Smallest amount to include, ignoring sign, in currency units (e.g. 25.50)"
        +}
      • addedInput schema / properties / payeeContains
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Only transactions whose payee name contains this text (case-insensitive)",
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Only transactions whose payee name contains this text (case-insensitive)"
        +}
      • addedInput schema / properties / totalsOnly
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Return only the totals, without transaction rows (default: false)",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Return only the totals, without transaction rows (default: false)"
        +}
      • addedInput schema / properties / untilDate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Only return transactions on or before this date (ISO format: 2024-12-31)",
        +      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Only return transactions on or before this date (ISO format: 2024-12-31)"
        +}
    • Changedynab_get_unapproved_transactions2 fields changed
      • changedInput schema / properties / sinceDate / anyOf
        Previous value: -[
        -  {
        -    "description": "Only return transactions on or after this date (ISO format: 2024-01-01). Omit to return all unapproved transactions.",
        -    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "Only return transactions on or after this date (ISO format: 2024-01-01)",
        +    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / sinceDate / description
        Previous value: -"Only return transactions on or after this date (ISO format: 2024-01-01). Omit to return all unapproved transactions."New value: +"Only return transactions on or after this date (ISO format: 2024-01-01)"
    • Changedynab_plan_summary1 field changed
      • addedInput schema / properties / budgetVsActuals
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Add a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Add a budget_vs_actuals block comparing assigned with actual spending per category for the month, with group subtotals (default: false)"
        +}
    • Changedynab_spending_by_category4 fields changed
      • addedInput schema / properties / monthly
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "true adds the top-level months list and, on each category, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many categories, pair it with limit.",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "true adds the top-level months list and, on each category, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many categories, pair it with limit."
        +}
      • addedInput schema / properties / months
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "With monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly.",
        +      "maximum": 24,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "With monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly."
        +}
      • changedInput schema / properties / untilDate / anyOf
        Previous value: -[
        -  {
        -    "description": "End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date.",
        -    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true.",
        +    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / untilDate / description
        Previous value: -"End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date."New value: +"End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true."
    • Changedynab_spending_by_payee4 fields changed
      • addedInput schema / properties / monthly
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "true adds the top-level months list and, on each payee, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many payees, pair it with limit.",
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "true adds the top-level months list and, on each payee, monthly_totals (spend per month, aligned with months), average_monthly (mean over the full months) and change_pct (the last full month against the mean of the earlier full months). Months only partly in the range, or not over yet, are listed but left out of both figures. The range starts at sinceDate when given; otherwise it covers the number of calendar months set by months (default 6, at most 24), ending with untilDate or today. With many payees, pair it with limit."
        +}
      • addedInput schema / properties / months
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "With monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly.",
        +      "maximum": 24,
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "With monthly: true, how many calendar months to cover, ending with the month of untilDate or the current month (default 6). sinceDate overrides it. Ignored without monthly."
        +}
      • changedInput schema / properties / untilDate / anyOf
        Previous value: -[
        -  {
        -    "description": "End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date.",
        -    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "description": "End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true.",
        +    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / untilDate / description
        Previous value: -"End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date."New value: +"End of the range, inclusive (ISO format: 2024-01-31). Defaults to no end date, or to today with monthly: true."
  2. 3 tool updatesv0.4.0
    • Addedynab_apply_category_suggestions
    • Changedynab_create_transaction1 field changed
      • addedInput schema / properties / subtransactions
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Splits the transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries whose amounts sum to amount; omit categoryId/categoryName when splitting.",
        +      "items": {
        +        "properties": {
        +          "amount": {
        +            "description": "The split amount in dollars, signed like the transaction amount",
        +            "type": "number"
        +          },
        +          "category_name": {
        +            "description": "The split's category name, matched loosely against your categories (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "memo": {
        +            "description": "A memo for this split (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "payee_name": {
        +            "description": "A payee for this split, if different from the transaction's (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "required": [
        +          "amount"
        +        ],
        +        "type": "object"
        +      },
        +      "minItems": 2,
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Splits the transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries whose amounts sum to amount; omit categoryId/categoryName when splitting."
        +}
    • Changedynab_update_transaction1 field changed
      • addedInput schema / properties / subtransactions
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Splits an ordinary transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries summing to amount (or the current amount if amount is omitted); omit categoryId. Not allowed on a transaction that is already split.",
        +      "items": {
        +        "properties": {
        +          "amount": {
        +            "description": "The split amount in dollars, signed like the transaction amount",
        +            "type": "number"
        +          },
        +          "category_name": {
        +            "description": "The split's category name, matched loosely against your categories (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "memo": {
        +            "description": "A memo for this split (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "payee_name": {
        +            "description": "A payee for this split, if different from the transaction's (optional)",
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "required": [
        +          "amount"
        +        ],
        +        "type": "object"
        +      },
        +      "minItems": 2,
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Splits an ordinary transaction across categories, in the same shape ynab_get_transactions returns. Needs at least two entries summing to amount (or the current amount if amount is omitted); omit categoryId. Not allowed on a transaction that is already split."
        +}
  3. 22 tool updatesv0.3.0
    • Changedynab_approve_transaction8 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / approved / anyOf
        Added value: +[
        +  {
        +    "default": true,
        +    "description": "Whether the transaction should be marked as approved",
        +    "type": "boolean"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / approved / default
        Removed value: -true
      • removedInput schema / properties / approved / type
        Removed value: -"boolean"
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The id of the budget containing the transaction (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Addedynab_auto_assign
    • Changedynab_budget_summary10 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget to get a summary for (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / month / anyOf
        Added value: +[
        +  {
        +    "default": "current",
        +    "description": "The plan month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)",
        +    "pattern": "^(current|\\d{4}-\\d{2}-\\d{2})$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / month / default
        Removed value: -"current"
      • changedInput schema / properties / month / description
        Previous value: -"The budget month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)"New value: +"The plan month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)"
      • removedInput schema / properties / month / pattern
        Removed value: -"^(current|\\d{4}-\\d{2}-\\d{2})$"
      • removedInput schema / properties / month / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_bulk_approve_transactions7 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
      • addedInput schema / properties / transactionIds / maxItems
        Added value: +500
      • addedInput schema / properties / transactionIds / minItems
        Added value: +1
    • Addedynab_cash_flow
    • Changedynab_create_transaction30 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / accountId / anyOf
        Added value: +[
        +  {
        +    "description": "The id of the account to create the transaction in (optional if accountName is provided)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / accountId / description
        Previous value: -"The id of the account to create the transaction in"New value: +"The id of the account to create the transaction in (optional if accountName is provided)"
      • removedInput schema / properties / accountId / type
        Removed value: -"string"
      • addedInput schema / properties / accountName
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The name of the account, matched loosely against your accounts (e.g. 'ally checking'). Optional if accountId is provided.",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The name of the account, matched loosely against your accounts (e.g. 'ally checking'). Optional if accountId is provided."
        +}
      • changedInput schema / properties / amount / description
        Previous value: -"The amount in dollars (e.g. 10.99)"New value: +"The amount in dollars (e.g. -10.99 for money spent, 10.99 for money received)"
      • addedInput schema / properties / approved / anyOf
        Added value: +[
        +  {
        +    "description": "Whether the transaction is approved (optional, defaults to false)",
        +    "type": "boolean"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / approved / type
        Removed value: -"boolean"
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The id of the budget to create the transaction in (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / categoryId / anyOf
        Added value: +[
        +  {
        +    "description": "The category id for the transaction (optional)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / categoryId / type
        Removed value: -"string"
      • addedInput schema / properties / categoryName
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The name of the category, matched loosely against your categories (e.g. 'groceries'). Optional; ignored if categoryId is provided.",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The name of the category, matched loosely against your categories (e.g. 'groceries'). Optional; ignored if categoryId is provided."
        +}
      • addedInput schema / properties / cleared / anyOf
        Added value: +[
        +  {
        +    "description": "The cleared status of the transaction (optional, defaults to uncleared)",
        +    "enum": [
        +      "cleared",
        +      "uncleared",
        +      "reconciled"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / cleared / description
        Previous value: -"Whether the transaction is cleared (optional, defaults to false)"New value: +"The cleared status of the transaction (optional, defaults to uncleared)"
      • removedInput schema / properties / cleared / type
        Removed value: -"boolean"
      • addedInput schema / properties / date / pattern
        Added value: +"^\\d{4}-\\d{2}-\\d{2}$"
      • addedInput schema / properties / flagColor / anyOf
        Added value: +[
        +  {
        +    "description": "The transaction flag color, or an empty string to clear the flag (optional)",
        +    "enum": [
        +      "red",
        +      "orange",
        +      "yellow",
        +      "green",
        +      "blue",
        +      "purple",
        +      ""
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / flagColor / description
        Previous value: -"The transaction flag color (red, orange, yellow, green, blue, purple) (optional)"New value: +"The transaction flag color, or an empty string to clear the flag (optional)"
      • removedInput schema / properties / flagColor / type
        Removed value: -"string"
      • addedInput schema / properties / memo / anyOf
        Added value: +[
        +  {
        +    "description": "A memo/note for the transaction (optional)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / memo / type
        Removed value: -"string"
      • addedInput schema / properties / payeeId / anyOf
        Added value: +[
        +  {
        +    "description": "The id of the payee (optional if payeeName is provided)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / payeeId / type
        Removed value: -"string"
      • addedInput schema / properties / payeeName / anyOf
        Added value: +[
        +  {
        +    "description": "The name of the payee (optional if payeeId is provided). YNAB creates the payee if it does not exist.",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / payeeName / description
        Previous value: -"The name of the payee (optional if payeeId is provided)"New value: +"The name of the payee (optional if payeeId is provided). YNAB creates the payee if it does not exist."
      • removedInput schema / properties / payeeName / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "accountId",
        -  "date",
        -  "amount"
        -]New value: +[
        +  "date",
        +  "amount"
        +]
    • Changedynab_delete_transaction5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_get_transactions18 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / accountId / anyOf
        Added value: +[
        +  {
        +    "description": "Filter to only transactions in this account",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / accountId / type
        Removed value: -"string"
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / categoryId / anyOf
        Added value: +[
        +  {
        +    "description": "Filter to only transactions in this category",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / categoryId / type
        Removed value: -"string"
      • addedInput schema / properties / limit / anyOf
        Added value: +[
        +  {
        +    "description": "Maximum number of transactions to return (default: 100)",
        +    "exclusiveMinimum": 0,
        +    "maximum": 1000,
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / limit / type
        Removed value: -"number"
      • addedInput schema / properties / payeeId / anyOf
        Added value: +[
        +  {
        +    "description": "Filter to only transactions with this payee",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / payeeId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
      • addedInput schema / properties / sinceDate / anyOf
        Added value: +[
        +  {
        +    "description": "Only return transactions on or after this date (ISO format: 2024-01-01)",
        +    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / sinceDate / type
        Removed value: -"string"
      • addedInput schema / properties / type / anyOf
        Added value: +[
        +  {
        +    "description": "Filter by transaction type. Defaults to 'all'.",
        +    "enum": [
        +      "all",
        +      "uncategorized",
        +      "unapproved"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / type / enum
        Removed value: -[
        -  "all",
        -  "uncategorized",
        -  "unapproved"
        -]
      • removedInput schema / properties / type / type
        Removed value: -"string"
    • Changedynab_get_unapproved_transactions6 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget to fetch transactions for (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
      • addedInput schema / properties / sinceDate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "Only return transactions on or after this date (ISO format: 2024-01-01). Omit to return all unapproved transactions.",
        +      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Only return transactions on or after this date (ISO format: 2024-01-01). Omit to return all unapproved transactions."
        +}
    • Changedynab_import_transactions5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_list_accounts7 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / includeClosedAccounts / anyOf
        Added value: +[
        +  {
        +    "description": "Include closed accounts in the list (default: false)",
        +    "type": "boolean"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / includeClosedAccounts / type
        Removed value: -"boolean"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_list_categories5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_list_months5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_list_payees5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Addedynab_list_plans
    • Changedynab_list_scheduled_transactions5 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Addedynab_move_money
    • Addedynab_plan_summary
    • Addedynab_spending_by_category
    • Addedynab_spending_by_payee
    • Changedynab_update_category_budget6 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • changedInput schema / properties / month / description
        Previous value: -"The budget month in ISO format (e.g. 2024-01-01). Must be the first day of the month."New value: +"The plan month in ISO format (e.g. 2024-01-01). Must be the first day of the month."
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
    • Changedynab_update_transaction28 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / accountId / anyOf
        Added value: +[
        +  {
        +    "description": "Move transaction to a different account",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / accountId / type
        Removed value: -"string"
      • addedInput schema / properties / amount / anyOf
        Added value: +[
        +  {
        +    "description": "The amount in dollars (e.g. -10.99 for outflow, 10.99 for inflow)",
        +    "type": "number"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / amount / type
        Removed value: -"number"
      • addedInput schema / properties / approved / anyOf
        Added value: +[
        +  {
        +    "description": "Whether the transaction is approved",
        +    "type": "boolean"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / approved / type
        Removed value: -"boolean"
      • addedInput schema / properties / budgetId / anyOf
        Added value: +[
        +  {
        +    "description": "Deprecated alias of planId (still accepted)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / budgetId / description
        Previous value: -"The ID of the budget (optional, defaults to YNAB_BUDGET_ID environment variable)"New value: +"Deprecated alias of planId (still accepted)"
      • removedInput schema / properties / budgetId / type
        Removed value: -"string"
      • addedInput schema / properties / categoryId / anyOf
        Added value: +[
        +  {
        +    "description": "The category ID for the transaction",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / categoryId / type
        Removed value: -"string"
      • addedInput schema / properties / cleared / anyOf
        Added value: +[
        +  {
        +    "description": "The cleared status",
        +    "enum": [
        +      "cleared",
        +      "uncleared",
        +      "reconciled"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / cleared / enum
        Removed value: -[
        -  "cleared",
        -  "uncleared",
        -  "reconciled"
        -]
      • removedInput schema / properties / cleared / type
        Removed value: -"string"
      • addedInput schema / properties / date / anyOf
        Added value: +[
        +  {
        +    "description": "The date of the transaction in ISO format (e.g. 2024-03-24)",
        +    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / date / type
        Removed value: -"string"
      • addedInput schema / properties / flagColor / anyOf
        Added value: +[
        +  {
        +    "description": "The transaction flag color, or an empty string to clear the flag",
        +    "enum": [
        +      "red",
        +      "orange",
        +      "yellow",
        +      "green",
        +      "blue",
        +      "purple",
        +      ""
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / flagColor / description
        Previous value: -"The transaction flag color"New value: +"The transaction flag color, or an empty string to clear the flag"
      • removedInput schema / properties / flagColor / enum
        Removed value: -[
        -  "red",
        -  "orange",
        -  "yellow",
        -  "green",
        -  "blue",
        -  "purple"
        -]
      • removedInput schema / properties / flagColor / type
        Removed value: -"string"
      • addedInput schema / properties / memo / anyOf
        Added value: +[
        +  {
        +    "description": "A memo/note for the transaction",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / memo / type
        Removed value: -"string"
      • addedInput schema / properties / payeeId / anyOf
        Added value: +[
        +  {
        +    "description": "The ID of the payee",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / payeeId / type
        Removed value: -"string"
      • addedInput schema / properties / payeeName / anyOf
        Added value: +[
        +  {
        +    "description": "The name of the payee (creates new payee if doesn't exist)",
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / payeeName / type
        Removed value: -"string"
      • addedInput schema / properties / planId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The plan ID (optional, defaults to YNAB_PLAN_ID; budgetId is a deprecated alias)"
        +}
  4. 17 tool updatesv1.0.0
    • Removedlist_budgets
    • Addedynab_approve_transaction
    • Addedynab_budget_summary
    • Addedynab_bulk_approve_transactions
    • Addedynab_create_transaction
    • Addedynab_delete_transaction
    • Addedynab_get_transactions
    • Addedynab_get_unapproved_transactions
    • Addedynab_import_transactions
    • Addedynab_list_accounts
    • Addedynab_list_budgets
    • Addedynab_list_categories
    • Addedynab_list_months
    • Addedynab_list_payees
    • Addedynab_list_scheduled_transactions
    • Addedynab_update_category_budget
    • Addedynab_update_transaction
  5. 1 tool update
    • First observedlist_budgets

TDQS

A3.9/5.0

Scored across 26 tools

Disambiguation4/5

The descriptions are exceptionally explicit about when to use each tool over its neighbors (e.g. scheduled_transactions vs detect_recurring vs balance_forecast, cash_flow vs list_months, spending_by_category vs spending_by_payee). The main source of confusion is four deprecated alias tools (list_budgets, get_unapproved_transactions, budget_summary, approve_transaction) that duplicate existing tools, even though they are clearly labeled as deprecated.

Naming Consistency4/5

All tools share the ynab_ prefix and snake_case, which is predictable. Most follow verb_noun (list_plans, create_transaction, update_category_budget, move_money, detect_recurring), but several use noun phrases (spending_by_category, plan_summary, balance_forecast, cash_flow), a minor deviation.

Tool Count3/5

At 26 tools this is on the heavy side for a budgeting server, and the count is inflated by four deprecated aliases that add no capability. The remaining surface is broad but defensible given the domain (transactions, budgets, forecasting, recurring detection).

Completeness4/5

Core lifecycles are well covered: full transaction CRUD plus bulk approve and import, category budget updates, money moves, auto-assign, reporting, and forecasting. Notable gaps are write operations for scheduled transactions (listable and used in forecasts but not creatable/updatable) and no direct get-single-transaction tool.

Maintenance

ActivityActive
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    An MCP server that allows users to interact with YNAB data, enabling access to account balances, transactions, and the creation of new transactions through the Model Context Protocol.
    8
    6
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server for interacting with YNAB (You Need A Budget). Provides tools for accessing budget data through MCP-enabled clients like Claude Desktop.
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A Model Context Protocol server that enables interaction with You Need A Budget (YNAB) via their API, allowing users to manage budgets, accounts, categories, and transactions through natural language.
    2
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A Model Context Protocol server for YNAB (You Need A Budget). Enables users to query budgets, accounts, categories, transactions, and more, as well as create, update, and delete transactions and manage scheduled transactions from any MCP client.
    27
    40 PyPI
    2
    MIT