feat(mcp): gnubok_list_cash_accounts, a search-only discovery tool for bank accounts (#1810)

Follow-up to #1809: transaction listings now carry cash_account_id, but an
agent had no way to learn which cash accounts exist or which BAS ledger
each maps to. The tool lists cash_accounts (cash_account_id, ledger_account,
name, currency, iban, is_primary, enabled, source), optionally enabled
only. Search-only (catalogVisibility 'search') so tools/list stays inside
its context budget; gnubok_search_tools finds it on "bank account"/"cash
account". Scope transactions:read.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-23 03:39:29 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 6e5694fd03
commit 158ef0f484
3 changed files with 127 additions and 0 deletions
+66
View File
@@ -74,6 +74,7 @@ import {
} from '@/lib/reports/vat-filing-gate'
import { findRcBasisGaps } from '@/lib/reports/rc-basis-gaps'
import { fetchAllRows } from '@/lib/supabase/fetch-all'
import { listForCompany as listCashAccountsForCompany } from '@/lib/cash-accounts/service'
import {
looksLikeSwedishPersonalNumber,
normalizeReroutedPersonalNumber,
@@ -9817,6 +9818,71 @@ export const tools: McpTool[] = [
},
},
{
name: 'gnubok_list_cash_accounts',
title: 'List Cash Accounts',
description: 'List the company bank/cash accounts (cash_accounts): BAS ledger, currency, IBAN, primary flag. Use cash_account_id to filter transaction listings and account_number (ledger_account) for gnubok_get_reconciliation_status.',
inputSchema: {
type: 'object',
additionalProperties: false,
properties: {
enabled_only: { type: 'boolean', description: 'Only accounts that sync (default false)' },
},
},
outputSchema: {
type: 'object',
additionalProperties: false,
properties: {
cash_accounts: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
properties: {
cash_account_id: { type: 'string' },
ledger_account: { type: 'string', description: 'BAS account, e.g. "1930"' },
name: { type: ['string', 'null'] },
currency: { type: 'string' },
iban: { type: ['string', 'null'] },
is_primary: { type: 'boolean' },
enabled: { type: 'boolean' },
source: { type: 'string', enum: ['enable_banking', 'manual', 'sie_import'] },
},
required: ['cash_account_id', 'ledger_account', 'name', 'currency', 'iban', 'is_primary', 'enabled', 'source'],
},
},
count: { type: 'number' },
},
required: ['cash_accounts', 'count'],
},
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
// Search-only: a discovery helper for the transaction listings and the
// reconciliation tool, not part of the default catalog (tools/list budget).
catalogVisibility: 'search',
async execute(args, companyId, _userId, supabase) {
const rows = await listCashAccountsForCompany(supabase, companyId, {
enabledOnly: args.enabled_only === true,
})
const cashAccounts = rows.map((row) => ({
cash_account_id: row.id,
ledger_account: row.ledger_account,
name: row.name ?? null,
currency: row.currency,
iban: row.iban ?? null,
is_primary: row.is_primary === true,
enabled: row.enabled !== false,
source: row.source,
}))
return { cash_accounts: cashAccounts, count: cashAccounts.length }
},
},
// ── Document Inbox Tools ────────────────────────────────────
{