Skip to content

Development

  • Directoryavenir_mcp/ — the server (see Architecture)
    • …
  • Directorytests/ — unit tests, protocol tests, documentation and hygiene tests
    • …
  • Directoryevals/ — the demo budget, a stand-in for YNAB’s API, the agent evaluation
    • …
  • Directorydocsgen/ — generates the tool reference, the error catalogue and the examples
    • …
  • Directorydocs/ — this site (Astro Starlight, English, French, Spanish)
    • …
  • AGENTS.md — the contract for contributors, human or not
  • justfile — every command below
  • pyproject.toml, uv.lock — the Python project, locked
Terminal window
git clone https://github.com/mathbeal/avenir-mcp && cd avenir-mcp
uv sync # Python 3.14 and the locked dependencies
just check # every gate CI runs

just check runs, in CI’s order:

Check Command Fails when
format ruff format --check a file is not formatted
lint pylint the score is below 10.00
ruff ruff check a docstring of the package is not in Google style or leaves out an argument, the return value or an exception raised; imports are not sorted; bandit’s security checks find a risky pattern (TLS not verified, a shell command, a password in the code…)
dependencies deptry . the code imports a package pyproject.toml does not declare, or declares one it does not use
types mypy (strict) any type error
tests pytest a test fails, any warning is raised, or coverage of lines or branches is below 100 %
vocabulary lexdrift check avenir_mcp --baseline lexdrift.lock a new word appears for an idea already named
lock uv lock --check uv.lock does not match pyproject.toml

CI also runs typos, zizmor on the workflows, pip-audit on the locked dependencies, gitleaks on every commit of the history (just secrets, with Docker), the documentation build with the tests of its own code, CodeQL and the OpenSSF Scorecard (once the repository is public), a weekly comparison of YNAB’s API with its snapshot (just api-drift), and the official MCP Inspector (just inspect), which checks the server as a client sees it on the demo budget: its lists, the portability of its tool schemas, and one call of each kind. The test suite runs on Linux and macOS with Python 3.12, 3.13 and 3.14, and on Windows with Python 3.14 (on a pull request, macOS tries 3.14 only: its runners cost ten Linux ones); coverage is enforced on Linux and macOS, where the file-permission checks apply. Python 3.15 runs too, as an experiment: a failure there is a warning, not a red check. On a pull request, every commit must be signed off and the title must start with the kind of change. Two checks must be green: CI passed, which stands for every job of the quality workflow, and MCP Inspector, a workflow of its own so that its badge shows it alone.

Renovate opens pull requests every Monday morning:

Update Handling
development tools, CI actions, the documentation site (minor and patch) grouped, merged by itself once CI passes
fastmcp, httpx, pydantic — they run in front of users’ budgets one pull request each, reviewed by hand; the evaluation runs before a fastmcp update
any major version one pull request each, reviewed by hand
a known vulnerability at once, whatever the day

A new release waits three days before Renovate proposes it, so a broken or malicious version withdrawn quickly never reaches the project.

Kind Files What they check
Unit test_classifier, test_triage, test_writes, test_reconcile, test_forecast, test_analytics, test_journal, test_client the pure logic and the HTTP client, with invented data
Properties test_properties with Hypothesis, rules that hold for any input: amounts round-trip, spreading keeps every cent, months add up, cursors, bank text, confirmation fingerprints
Protocol test_protocol*, test_context, test_policy tools through an in-memory MCP client: schemas, annotations, confirmation paths, undo
Documentation test_docs generated pages and examples match the code; every page exists in French and Spanish; every environment variable is documented
API coverage test_api_coverage every operation of YNAB’s API is used by a tool, planned or left out with a reason; the client calls only documented paths
Hygiene test_hygiene no IBAN, token, statement, home path or Finder copy in the repository
Evaluation test_evals the evaluation’s own checks are right

Tests are written first. No test calls YNAB.

just mutate runs mutation testing (mutmut) on the modules that compute: it changes the code on purpose, some 1,500 times, and checks that a test fails each time. The changes no test notices point to the tests to write; many are harmless, such as a message’s wording.

Terminal window
uv run python -m docsgen # tool pages, error catalogue, examples
just docs # build the site in three languages; broken links fail
just docs-serve # live preview on http://localhost:4321/avenir-mcp/

docsgen runs avenir-mcp on the demo budget and writes what it really answers, with the date fixed and random ids replaced. Hand-written pages exist in English, French and Spanish; a test fails when one is missing.

Terminal window
just evaluate # all tasks, Sonnet, about 1 USD of your Claude plan
uv run python -m evals.run --task classify --model haiku

See Evaluation.

  • Commit messages start with a type — feat:, fix:, docs:, refactor:, test:, build:, ci:, chore: — because CHANGELOG.md is generated from them by git-cliff.
  • To release: just changelog, commit, tag vX.Y.Z matching avenir_mcp.__version__, and publish a GitHub release. The publish workflow builds, runs twine check --strict and uploads to PyPI through Trusted Publishing: no token is stored.

Unofficial project. We are not affiliated, associated, or in any way officially connected with YNAB or any of its subsidiaries or affiliates. YNAB and You Need A Budget are registered trademarks of YNAB. avenir-mcp is provided as is, without warranty, and is not financial advice. Legal notice