YNAB MCP Starter
Production-style TypeScript starter repo for a read-only YNAB MCP server.
This starter is intentionally small and explicit:
- Node.js 18+
- TypeScript with strict compiler settings
- Zod-validated tool inputs and outputs
- Read-only YNAB API client with retries and timeout handling
- Unit tests with mocked YNAB responses
- Clear TODO markers where MCP transport wiring should be connected
What This Repo Includes
src/
clients/ YNAB API client, environment config, and error types
schemas/ strict Zod schemas for tool contracts
server/ MCP server composition and transport TODO placeholders
tools/ read-only business logic for each YNAB capability
types/ shared API and service types
tests/ unit tests with mocked API responses
Implemented read-only capabilities:
- list budgets
- list accounts
- list categories
- list recent transactions
- find uncategorized transactions
- monthly spend by category
Write access is intentionally not implemented.
Setup
- Install dependencies:
npm install
- Copy the example environment file:
cp .env.example .env
- Set your YNAB token in
.env:
YNAB_TOKEN=your-token-here
- Run local development mode:
npm run dev
Scripts
npm run buildcompiles TypeScript intodist/npm run devruns the starter entrypoint with file watchingnpm run lintruns ESLintnpm run testruns unit tests with Vitestnpm run typecheckruns TypeScript in no-emit mode
MCP Wiring
The repo includes the server composition layer, but it does not lock you into one transport yet.
Look for TODO comments in:
- src/server/index.ts
- src/server/registerTools.ts
That is where you should:
- Instantiate the MCP server
- Register tool definitions and schemas
- Connect stdio, SSE, or another transport
- Add structured logging and operational hooks
Security Notes
- This starter expects a
YNAB_TOKENpersonal access token in environment variables. - Never hardcode the token in source files, tests, prompts, or logs.
- Keep the token scoped to read-only operational use and rotate it if it is exposed.
- Avoid logging raw YNAB API responses in production because they may contain transaction memos or other sensitive financial metadata.
- This starter only performs
GETrequests to the YNAB API. No write endpoints are implemented.
Design Notes
- The YNAB client centralizes retries, timeout handling, and error normalization.
- Tool modules are isolated from HTTP details and operate on a small service interface.
- Zod schemas validate both tool inputs and tool outputs to catch drift early.
- Money amounts are exposed in both YNAB milliunits and human-friendly decimal amounts.
- Monthly category spend only counts outflows for the requested month.
Example Prompts
- "List my YNAB budgets."
- "Show the accounts in budget
budget-id-123." - "List categories for budget
budget-id-123." - "Show the most recent 20 transactions in budget
budget-id-123." - "Find uncategorized transactions in budget
budget-id-123since2026-04-01." - "Summarize monthly spend by category for budget
budget-id-123in2026-04."
Testing
The tests mock YNAB API responses so you can validate behavior without a live token:
npm run test
Production Hardening Ideas
- Add request correlation IDs and structured logs
- Add metrics around retries, rate limiting, and latency
- Add integration tests against a mocked HTTP layer
- Add result pagination controls if your MCP client expects larger result sets
- Add a secrets manager integration instead of local
.envfiles for deployment