diff --git a/docs/architecture.md b/docs/architecture.md index 73da267..154acd9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -122,6 +122,46 @@ takes them whenever their last `settings.set` changes (on every lock of the store), the viewer reads them from the journal it shows, and neither reads a file; "today" is the company's time zone's, set per request. Rule: `docs/spec/rules.md` B-29. +## The MCP server's layout (`ledger-mcp`, P0; U0a) + +`crates/ledger-mcp/src/server.rs` is the server itself: `BooksServer`, the +shared store and its lock, `call_tool` and `get_info` (the `ServerHandler`), +`tool_router`, the request machinery and the helpers that cross groups. +Tool handlers live one file per group in `crates/ledger-mcp/src/tools/`, +each declared with `#[path]`, opening with `use super::*`, and holding a +`#[tool_router(router = _router, vis = "pub(super)")] impl +BooksServer`; `server.rs`'s `tool_router` adds every group's router. The +groups are: + +- `documents` — invoices, bills, payments, voids, `books.documents`, + `books.document`, the control check and the agings; +- `entries` — `books.draft_entry`, `books.add_line`, `books.post_entry`, + `books.reverse_entry`, `books.get_entry`, `books.search_entries`, the + bank CSV import; +- `reports` — the statements, `books.show`, `books.verify`, + `books.digest`, `books.export`, the CPA package, the P&L by class, and + the export builders; +- `assets`, `schedules` (schedules and recurring), `periods`, + `reconciliation`, `payroll`, `payouts`, `tax`; +- `parties` — parties, vendors, customers, roles, W-9s, the TIN vault, + 1099s, entry parties; +- `attachments` — receipts, filed documents, and their links; +- `settings` — the handbook, `books.settings` and the recorded FX rates + (the module is `settings_tools`, since `crate::settings` is the live + settings); +- `chart` — the chart of accounts, the template and CSV import, renaming + and renumbering, and the control roles; + +plus the groups split earlier: `kept` (`books.start`, settings changes, +conventions, decisions, open items, posting templates, approvals), +`projects`, `files` (uploads), `instruments`, `access` and `backup`. A +helper only one group uses lives in that group's file; the ones several +groups share live in `tools/helpers.rs` and `server.rs` re-exports them, +so no group file reaches into another group's. The tests that span the +whole tool surface sit beside `server.rs` in `server_tests.rs`; a group's +own tests live in its group file. The split changed no tool's name, +description, annotations or behaviour. + ## The MCP server's store lock (`ledger-mcp`, P0) One `Store` is shared by every session (`SharedStore`: a diff --git a/plan/served.md b/plan/served.md index 373a8aa..df02ba9 100644 --- a/plan/served.md +++ b/plan/served.md @@ -1214,7 +1214,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 5. **Files:** owns `crates/ledger-mcp/src/server.rs`, `crates/ledger-mcp/src/tools/*`; touches nothing else. 6. **Tests and proofs:** no new tests; every existing test passes unchanged (`cargo test -p ledger-mcp`, `cargo test -p ledger-cli`). `every_tool_is_documented_and_every_documented_tool_exists`, `annotations_complete`, `tool_text_lint` and `tool_descriptions_fit_700_characters` prove the surface is identical. 7. **Done when:** (1) `server.rs` is under 3,000 lines and holds no `#[tool(..)]` handler that belongs to a group; (2) `BooksServer::tool_router().list_all()` names the same 118 tools, in the same order, with identical descriptions and annotations (write a one-off comparison against `main` in the PR and paste the result); (3) `just check` green; (4) the architecture doc names the groups. -8. **As built:** none yet. +8. **As built:** (2026-10-26, branch `U0a`) Build steps 1-3 as written. The 98 handlers `server.rs` still held moved to `tools/documents.rs`, `tools/entries.rs`, `tools/reports.rs`, `tools/assets.rs`, `tools/schedules.rs`, `tools/periods.rs`, `tools/reconciliation.rs`, `tools/parties.rs`, `tools/attachments.rs`, `tools/settings.rs`, `tools/chart.rs`, `tools/payroll.rs`, `tools/payouts.rs` and `tools/tax.rs`; `books.add_class` and `books.list_classes` joined the existing `tools/projects.rs` (a project is a class with its facts), and `books.handbook`, `books.settings` and `books.set_fx_rate` make up `settings.rs` (`books.verify` and `books.digest` are in `reports.rs`). `server.rs` is under 2,000 lines (1,909) and holds no `#[tool(..)]` handler; `tool_router` composes the group routers, and `core_router` is gone because `server.rs` has no tools left. The helpers only one group uses moved into that group's file; the ones several groups share moved to `tools/helpers.rs`, which `server.rs` re-exports (`pub(crate) use helpers::*;`), and `server.rs` keeps the named shared helpers (`as_of`, `hand_over`, `resolve_vendor`, `parse_doc_ref`, `preview_lines_for`) and the request machinery. Two departures: (1) `settings.rs` is the module `settings_tools`, because `crate::settings` already names the live settings; (2) the test bodies sit in `crates/ledger-mcp/src/server_tests.rs`, a `#[path]` module of `server.rs`, with their fixtures in `server::test_support`, and each group's own tests moved into its group file: `server.rs` keeps the tests module (and the cross-group ones are the server's) but reaches 3,000 lines only with the bodies beside it. Done-when 2's count is stale: the surface is 122 tools, not 118, and a one-off dump of every tool's name, title, description, input and output schema and annotations, in `list_all()` order, diffs empty against `main`'s. #### U0b: the attention engine over `PackageBooks`