diff --git a/extensions/general/mcp-server/__tests__/payload-size.bench.test.ts b/extensions/general/mcp-server/__tests__/payload-size.bench.test.ts index c9fbf758..8ad32f88 100644 --- a/extensions/general/mcp-server/__tests__/payload-size.bench.test.ts +++ b/extensions/general/mcp-server/__tests__/payload-size.bench.test.ts @@ -238,9 +238,13 @@ describe('tools/list payload size guard', () => { // connect card, same one-click feel as bank/Skatteverket): the skill // instructs calling it when the user names Fortnox/BL/Briox/Wint, so // default catalog for the standing Claude.ai reason. + // * 63K to 63.4K with gnubok_reconcile_match promoted to the default + // catalog: the onboarding efterkontroll instructs matching bank rows + // against SIE verifikat, and a search-only tool is uncallable on + // Claude.ai (E2E #12 punted to the web app over it). // Long-term answer to growth is leaning harder on gnubok_search_tools: if this // fires again, prefer trimming descriptions or making a tool opt-in via search // before bumping further. - expect(approxTokens).toBeLessThan(63_000) + expect(approxTokens).toBeLessThan(63_400) }) }) diff --git a/extensions/general/mcp-server/__tests__/reconciliation-tools.test.ts b/extensions/general/mcp-server/__tests__/reconciliation-tools.test.ts index 16c9f791..7d6d834b 100644 --- a/extensions/general/mcp-server/__tests__/reconciliation-tools.test.ts +++ b/extensions/general/mcp-server/__tests__/reconciliation-tools.test.ts @@ -1,6 +1,6 @@ /** * The account-keyed reconciliation tools: status (account_key branch), items, - * reconcile_match (stages; dry_run previews), reconcile_unmatch (search-only). + * reconcile_match (stages; dry_run previews; default catalog), reconcile_unmatch (search-only). * Service functions are mocked; the staging path runs for real in dry_run * mode (no insert), so the STAGED_OPERATION_SCHEMA contract is exercised. */ @@ -60,7 +60,9 @@ describe('reconciliation MCP tools', () => { expect(isDefaultCatalogTool(tool('gnubok_get_reconciliation_status'))).toBe(true) expect(isDefaultCatalogTool(tool('gnubok_list_reconciliation_items'))).toBe(true) // Writes sit behind search to respect the tools/list payload ceiling. - expect(isDefaultCatalogTool(tool('gnubok_reconcile_match'))).toBe(false) + // Default since E2E #12: the onboarding efterkontroll instructs the + // matching step and Claude.ai cannot call search-only tools. + expect(isDefaultCatalogTool(tool('gnubok_reconcile_match'))).toBe(true) expect(isDefaultCatalogTool(tool('gnubok_reconcile_unmatch'))).toBe(false) expect(isDefaultCatalogTool(tool('gnubok_link_transaction_to_journal_entry'))).toBe(false) expect(deriveToolMeta(tool('gnubok_reconcile_match'))).toMatchObject({ diff --git a/extensions/general/mcp-server/server.ts b/extensions/general/mcp-server/server.ts index 7df34403..a5ef505e 100644 --- a/extensions/general/mcp-server/server.ts +++ b/extensions/general/mcp-server/server.ts @@ -10852,7 +10852,7 @@ export const tools: McpTool[] = [ { name: 'gnubok_list_reconciliation_items', title: 'Reconciliation Items', - description: 'Rows behind one account\'s reconciliation bridge, bucketed (proposed, unmatched_external, unmatched_ledger, matched, ignored, upcoming): side, qualified id, amount, proposal with confidence + reasons, allowed actions. Link via gnubok_reconcile_match (search).', + description: 'Rows behind one account\'s reconciliation bridge, bucketed (proposed, unmatched_external, unmatched_ledger, matched, ignored, upcoming): side, qualified id, amount, proposal with confidence + reasons, allowed actions. Link via gnubok_reconcile_match.', inputSchema: { type: 'object', additionalProperties: false, @@ -10905,10 +10905,11 @@ export const tools: McpTool[] = [ name: 'gnubok_reconcile_match', title: 'Reconcile: Link Pairs', description: 'Link outside rows (bank or skattekonto) to existing verifikat on one account; no new bokföring. Pass pairs, or use_proposals to apply the persisted proposals. Stages. dry_run previews.', - // Search-only to stay under the tools/list payload ceiling: the default - // catalog carries the reads (status + items); this write is reached via - // gnubok_search_tools, the close_period loadout and the items tool's hint. - catalogVisibility: 'search', + // Default catalog since E2E #12: the onboarding efterkontroll instructs + // matching SIE-covered bank rows against existing verifikat, and + // Claude.ai cannot call search-only tools: the agent misread the + // uncallable tool as a missing reconciliation:write scope and punted the + // whole matching step to the web app. inputSchema: { type: 'object', additionalProperties: false, diff --git a/extensions/general/mcp-server/skills/onboarding.ts b/extensions/general/mcp-server/skills/onboarding.ts index 4bb9e2d9..1c6edee7 100644 --- a/extensions/general/mcp-server/skills/onboarding.ts +++ b/extensions/general/mcp-server/skills/onboarding.ts @@ -38,6 +38,13 @@ need zero of these questions. - "Lägg till ett nytt bolag" (an existing user adding a second company) - A byrå/consultant onboarding a new client company (pass \`team_id\`) +**Already set up? Deliver value immediately instead.** When +\`gnubok_get_agent_briefing\` shows a company that already exists with +data and connections (the user onboarded via the web app), do NOT walk +the setup steps: go straight to the Step 4b reconciliation pass and the +Att göra-list, and open with the findings: a numbered list with amounts +in your FIRST reply. That first impression is the product. + ## Step 0: connect If this session is not connected yet, the first company-scoped call (for @@ -167,23 +174,39 @@ link, and duplicate raw URLs read as clutter. When the user says they are done (or comes back), re-call \`gnubok_connect_bank\` to verify \`connected\`, then go DIRECTLY to step 5. -## Step 4b: after the import: efterkontroll (this is where trust is won) +## Step 3b: DIRECTLY after the import: verify and PREPARE (before the bank) -Run a short audit pass as soon as history + bank are in, and fix findings -through the normal staged flow, a few lines per finding: +The moment the import commits, run a fast pass so the connections land in +a book that is READY for them: the user should feel value before the bank +even connects. -- \`gnubok_get_trial_balance\`: does the book balance and match the SIE? -- Skattekonto vs 1630: if Skatteverket is connected, reconcile the - skattekonto events against the ledger. Common finds: paid payroll taxes - still standing as liabilities on 2710/2731, the 1630 account missing - entirely, unbooked ränta/avgifter (kostnadsränta 8423, skattefri - intäktsränta 8314, ej avdragsgill förseningsavgift 6992: never the - ordinary cost accounts, or the year-end tax computation goes wrong). +- \`gnubok_get_trial_balance\`: balances, and matches the SIE's UB. +- Sanity-read the content: no income accounts? liabilities that look + already-paid? Say so in one line each; do not fix yet. +- PREPARE the chart for what the connections will bring: if the import + lacks 1630 (skattekonto), 8423 (kostnadsränta skattekonto), 8314 + (skattefri intäktsränta) or 6992 (ej avdragsgilla avgifter), create + them NOW so tax payments and fees book correctly from the first sync. +- Voucher gaps: explain each with \`gnubok_explain_voucher_gap\`. + +## Step 4b: after the connections: reconcile (this is where trust is won) + +Once bank + Skatteverket deliver data, run the reconciliation pass and +fix findings through the normal staged flow, a few lines per finding: + +- Bank rows covered by the SIE period: MATCH them against existing + verifikat with \`gnubok_reconcile_match\` (per account; \`dry_run\` + first): never categorize them again, that double-books salaries and + everything else. Only rows after the SIE's last date get booked fresh. +- Skattekonto vs 1630: reconcile the events against the ledger. Common + finds: paid payroll taxes still standing on 2710/2731, ränta/avgifter + unbooked (8423/8314/6992: never ordinary cost accounts, or the + year-end tax computation goes wrong). End state must match + Skatteverket's saldo to the öre. - Auto-created bank accounts (1930/1931/1935) named after the company: suggest proper names. - Underlag coverage: verifikat over ~5 000 kr without documents (BFL 5 kap 6 §): list them, offer the receipt-matcher flow. -- Voucher gaps: explain each with \`gnubok_explain_voucher_gap\`. Present findings as a short numbered list with amounts, fix in priority order on the user's go-ahead, and re-verify the reconciled balances match