Files
accounted/extensions/general/mcp-server/resources/index.ts
T
Jakob WennbergandClaude Fable 5 a3c6566caf feat(mcp): ledger-context resource with per-company booking patterns (#928)
* feat(mcp): ledger-context resource with per-company booking patterns

Adds Accounted://ledger/context: derived account usage, counterparty
booking patterns with explicit confidence share (0.7 floor), explicit
mapping rules kept separate as authoritative, observed VAT profile, and
conventions. Backed by a SECURITY INVOKER get_ledger_usage_stats RPC so
group-bys run SQL-side, and surfaced as a top-5 digest stanza on
gnubok_get_agent_briefing so one call still bootstraps a session.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(mcp): fold source-quality prereqs into the ledger-context RPC

Merchant-name normalization at the aggregation path (the splinter fix):
new normalize_counterparty_key() SQL function mirroring
normalizeCounterpartyName() so KORTKÖP/SWISH/date-suffixed labels merge
into one counterparty key, which also makes the categorization_templates
join exact. New supplier_patterns section (per-supplier dominant expense
account + VAT treatment from supplier invoices; credit notes and reversed
invoices excluded). account_usage excludes storno lines (they re-inflate
the account a correction moved away from); the counterparty CTE keeps
corrections because the transaction relink self-heals. Pattern confidence
is now count-grounded evidence {seen_12m, agree, share, last_booked}
instead of a bare ratio, and the digest frames it as historical frequency,
never auto-book permission.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(agent-context): use roundOre for the share ratio (antipattern ratchet)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(agent-context): defensive storno filter on counterparty CTE, fail-loud secondary reads

Review follow-ups: the counterparty CTE now excludes source_type='storno'
defensively (no live code path links a transaction to a storno, but legacy
rows may predate reverseEntry's unlink; a linked storno would count the
reversed category as precedent). Corrections stay included: they are the
live booking after relink. Secondary reads (rules, templates, settings)
now throw instead of silently reading as empty data: an agent must never
be told 'no rules' when the truth is 'read failed'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 13:48:04 +02:00

35 lines
1.2 KiB
TypeScript

import type { McpResource, ResourceContext } from './types'
import { companyCurrentResource } from './company-current'
import { chartOfAccountsResource } from './chart-of-accounts'
import { periodActiveResource } from './period-active'
import { recentActivityResource } from './recent-activity'
import { capabilitiesResource } from './capabilities'
import { vatTreatmentsResource } from './vat-treatments'
import { attentionResource } from './attention'
import { ledgerContextResource } from './ledger-context'
export const dataResources: McpResource[] = [
companyCurrentResource,
chartOfAccountsResource,
periodActiveResource,
recentActivityResource,
capabilitiesResource,
vatTreatmentsResource,
attentionResource,
ledgerContextResource,
]
export function findResource(uri: string): McpResource | null {
// Strip any query string for matching
const baseUri = uri.split('?')[0]
return dataResources.find((r) => r.uri === baseUri) ?? null
}
export function parseResourceQuery(uri: string): URLSearchParams | undefined {
const qIndex = uri.indexOf('?')
if (qIndex < 0) return undefined
return new URLSearchParams(uri.slice(qIndex + 1))
}
export type { McpResource, ResourceContext }