YNAB MCP Server
You can read, analyze, and modify your YNAB plans through MCP tools.
List plans, accounts, categories, payees, months, scheduled transactions, and transactions with filtering/search and totals.
Get month summaries, including overspending/underfunded/positive categories and optional budget-vs-actuals by category and group.
Produce reports: spending by category or payee, cash flow, scheduled-balance forecasts, and recurring-charge detection.
Create, update, delete, split, approve, or unapprove transactions, including cleared status and flag colors.
Set category budget amounts, move budgeted money between categories, and auto-assign Ready to Assign to underfunded goals with dry-run support.
Trigger transaction import from linked bank accounts.
Apply explicit category suggestions with fingerprint validation, dry-run support, and an undo manifest.
Optionally support AI category suggestions via TypeSafe configuration; write tools can be disabled with YNAB_READ_ONLY.
Supports publishing the MCP server as an npm package for easier distribution and installation
Used for building tools that interact with YNAB's API through typed interfaces
Utilized for schema validation of tool inputs when interacting with YNAB data
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@YNAB MCP Server show me my budget summary for this month"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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:
Setup
Get a Personal Access Token from https://api.ynab.com/#personal-access-tokens, then:
npm install
npm run buildEnvironment variables:
Variable | Required | Purpose |
| yes | Personal Access Token used for every API call |
| no | Default plan, so tools can omit |
| no | Operator-owned TypeSafe credential. Required, but not sufficient, to enable category suggestions. |
| no | Set to |
| no | Set to |
| no | Set to |
| no | Worker only. The single GitHub login allowed through GitHub sign-in. Required for GitHub sign-in. |
| no | Worker only. The GitHub OAuth app's credentials. Required for GitHub sign-in. |
| no | Worker only. Exact OAuth callback URIs that GitHub sign-in may deliver grants to. See Restricting redirects. Must be unset with Cloudflare Access. |
| no | Worker only. Your Cloudflare Access team domain ( |
| no | Worker only. The Access application's Audience (AUD) tag. |
| no | Worker only. The single email allowed through Access. Any other identity, including a service token, is refused. |
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:
Copy
wrangler.example.jsoncto the git-ignoredwrangler.jsonc, remove the optional placeholderAUTOBUDGET_DBblock unless you are configuring the auto-budget service, runnpx wrangler login, then create theOAUTH_KVnamespacenpm run deployonce to learn your*.workers.devhostnameCreate a GitHub OAuth app whose callback is
https://<host>/callbackUse
npx wrangler secret putforALLOWED_GITHUB_LOGIN,YNAB_API_TOKEN,GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET, andTYPESAFE_API_KEYRun
npm run deployagainAdd
https://<host>/mcpas 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.
To sign in through Cloudflare Access instead of GitHub, see Cloudflare Access, which also lists the MCP clients tested with it.
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 |
| Every plan on the account. Run this first to find a plan ID. |
| A month at a glance: income, budgeted, activity, Ready to Assign, plus categories split into |
| Accounts with balances. |
| Categories grouped by category group, with goal info. |
| Payees, for resolving payee IDs. |
| 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 |
| The scheduled transactions set up in YNAB. For recurring charges found in transaction history, see |
| Transactions optionally filtered to |
| 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:
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 issuggested. When those rows disagree, the row isneeds_reviewand proposes the most recently used category, with the others astop_alternativescarrying theirhistory_count. No model call is made for either case.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 issuggestedwithout a model call. The probability is reported underpersonal_prior.ranking, never asmodel_confidence. Below 0.9 the prior only ranks: its top three appear on the model's row for comparison.Model (
jev). Every remaining row goes to TypeSafe's pinnedjev-1.13.0System One model in batches of ten. A model answer is a ranked shortlist, never a suggestion: every answer that names a category isneeds_review, while an explicit model abstention isleft_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 |
| Total spend per category over a date range, biggest first, with share of total. Defaults to the last 30 days. With |
| The same, grouped by merchant, including |
| Income vs spending per month with the running net, from YNAB's own monthly totals. Defaults to the last 6 months. |
| The combined balance of your accounts over the next |
| 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 |
| Creates a transaction. Needs |
| Updates any subset of an existing transaction's fields, or splits an unsplit one with |
| Deletes a transaction. Not undoable. |
| Approves an array of transaction IDs in one API call, or un-approves them with |
| 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. |
| Sets the total budgeted amount for one category in a month. Not an increment; use |
| Triggers an import from linked institutions, the same as hitting Import in the YNAB app. |
| Moves budgeted money between two categories in a month, for covering overspending. |
| Spreads Ready to Assign over categories with unmet monthly goals, largest shortfall first. |
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 Cloudflaredist/ 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:
YNAB SDK types:
node_modules/ynab/dist/index.d.tsYNAB OpenAPI spec: https://api.ynab.com/papi/open_api_spec.yaml
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.
Fork the repository and create a branch from
main.Make your change and add or update tests in
src/tests/. New tools follow the pattern in Adding a tool.Run
npm run test:runandnpm run typecheck.Use Conventional Commits for commit messages and the pull request title.
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
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.
Star History
Available Tools
22 toolsynab_apply_category_suggestionsApply Category SuggestionsAIdempotent
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.
Inputs: suggestions (required), planId, dry_run, budgetId.
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.
Inputs: month, dryRun, planId, budgetId, +1 more.
ynab_balance_forecastBalance ForecastARead-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.
Inputs: days, limit, planId, budgetId, +1 more.
ynab_bulk_approve_transactionsBulk Approve TransactionsAIdempotent
Approves (or, with approved: false, un-approves) one or more transactions in a single API call.
Inputs: transactionIds (required), planId, approved, budgetId.
ynab_cash_flowCash FlowARead-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.
Inputs: months, planId, budgetId, sinceDate.
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.
Inputs: date (required), amount (required), memo, planId, +11 more.
ynab_delete_transactionDelete TransactionADestructive
Deletes a transaction from the plan. This action cannot be undone.
Inputs: transactionId (required), planId, budgetId.
ynab_detect_recurringDetect RecurringARead-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.
Inputs: planId, budgetId, sinceDate, minOccurrences, +1 more.
ynab_get_transactionsGet TransactionsARead-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.
Inputs: type, limit, planId, payeeId, +11 more.
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).
Inputs: planId, budgetId.
ynab_list_accountsList AccountsARead-only
Lists all accounts in a plan. Useful for finding account IDs when creating transactions.
Inputs: planId, budgetId, includeClosedAccounts.
ynab_list_categoriesList CategoriesARead-only
Lists all categories in a plan, grouped by category group. Useful for finding category IDs when creating transactions or updating budgeted amounts.
Inputs: planId, budgetId.
ynab_list_monthsList MonthsARead-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.
Inputs: planId, budgetId.
ynab_list_payeesList PayeesARead-only
Lists all payees in a plan. Useful for finding payee IDs when creating transactions.
Inputs: planId, budgetId.
ynab_list_plansList PlansARead-only
Lists all available plans from YNAB API
Inputs: no named parameters.
ynab_list_scheduled_transactionsList Scheduled TransactionsARead-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.
Inputs: planId, budgetId.
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.
Inputs: amount (required), toCategoryId (required), fromCategoryId (required), month, +2 more.
ynab_plan_summaryPlan SummaryARead-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.
Inputs: month, planId, budgetId, budgetVsActuals.
ynab_spending_by_categorySpending By CategoryARead-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.
Inputs: limit, months, planId, monthly, +3 more.
ynab_spending_by_payeeSpending By PayeeARead-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.
Inputs: limit, months, planId, monthly, +3 more.
ynab_update_category_budgetUpdate Category BudgetAIdempotent
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.
Inputs: month (required), budgeted (required), categoryId (required), planId, +1 more.
ynab_update_transactionUpdate TransactionAIdempotent
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.
Inputs: transactionId (required), date, memo, amount, +10 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 22 tools
Most tools target distinct resources and actions, and descriptions actively steer away from neighbours (list_months vs cash_flow, list_scheduled_transactions vs detect_recurring vs balance_forecast). The remaining overlap sits in the analytics cluster (spending_by_category, spending_by_payee, cash_flow, plan_summary with budgetVsActuals, list_months), which is disambiguated only by dense prose rather than sharp boundaries. ynab_apply_category_suggestions is also unclear since no companion tool produces the 'suggestions' it consumes.
All names use snake_case with a consistent ynab_ prefix, which makes the set predictable. There is a minor drift between verb_noun names (list_months, create_transaction, move_money) and bare noun phrases (plan_summary, cash_flow, balance_forecast, spending_by_category). The deviation is cosmetic and still readable.
At 22 tools the surface is on the heavy side, but YNAB is a genuinely multi-resource domain (plans, months, accounts, categories, payees, transactions, schedules, analytics) and each tool maps to a real operation. Nothing looks padded purely for the sake of count, though the analytics group could plausibly be consolidated.
Transaction lifecycle is fully covered (get, create, update, delete, bulk approve, import), along with budgeting operations (update_category_budget, move_money, auto_assign). Gaps are mostly where the YNAB API itself is read-only: no create/update/delete for scheduled transactions, accounts, payees, or category groups. A 'get single entity' path is also absent, but list tools plus filters cover it in practice.
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Query your real net worth, spending, transactions, budgets and portfolio from any MCP client.
A Model Context Protocol server for Wix AI tools
Hosted remote MCP server for YNAB on Cloudflare Workers with OAuth
Related MCP Servers
- AlicenseAqualityBmaintenanceAn 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.86MIT
- AlicenseNot gradedqualityDmaintenanceA 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.4MIT
- AlicenseNot gradedqualityDmaintenanceA 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.2MIT
- AlicenseAqualityBmaintenanceA 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.2718 PyPI2MIT