@kirjapro/mcp-server 0.3.0 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +298 -0
- package/README.md +51 -97
- package/dist/index.js +3327 -1203
- package/package.json +5 -4
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,303 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.5] - 2026-04-11
|
|
4
|
+
|
|
5
|
+
Tool-annotation sweep: every remaining `server.tool()` call migrated to
|
|
6
|
+
`server.registerTool()` and tagged with MCP tool annotations. No behavioural
|
|
7
|
+
changes — clients get richer `list_tools` metadata and `destructiveHint`
|
|
8
|
+
now flags the three `delete_*` tools so UIs can warn before invoking them.
|
|
9
|
+
|
|
10
|
+
### registerTool() migration
|
|
11
|
+
|
|
12
|
+
- **All 43 remaining tools migrated** — `customers`, `invoices`, `bookings`,
|
|
13
|
+
`offers`, `recurring-invoices`, `templates`, `accounts`, `received-invoices`,
|
|
14
|
+
`banking`, `validation`, `fiscal-years`, and `transactions` now exclusively
|
|
15
|
+
use `server.registerTool(name, { description, inputSchema, annotations }, cb)`.
|
|
16
|
+
The deprecated `server.tool()` overload is no longer called anywhere in the
|
|
17
|
+
codebase (verified by test guard — see below).
|
|
18
|
+
- **Shared annotation constants** (`src/utils.ts`) — `READ_ONLY_ANNOTATIONS`,
|
|
19
|
+
`READ_ONLY_EXTERNAL_ANNOTATIONS`, `WRITE_ANNOTATIONS`,
|
|
20
|
+
`WRITE_EXTERNAL_ANNOTATIONS`, `DESTRUCTIVE_ANNOTATIONS`. The five constants
|
|
21
|
+
cover the read/write × local/external × destructive matrix, so individual
|
|
22
|
+
tool files don't re-declare the hint bags inline.
|
|
23
|
+
- **`destructiveHint: true`** on `kirjapro_delete_invoice`,
|
|
24
|
+
`kirjapro_delete_offer`, and `kirjapro_delete_recurring_invoice`. MCP
|
|
25
|
+
clients that support the annotation can now show a distinct confirmation
|
|
26
|
+
prompt before executing irreversible operations.
|
|
27
|
+
- **`openWorldHint: true`** on `kirjapro_lookup_business` (PRH API) and
|
|
28
|
+
`kirjapro_send_offer` (sends customer-visible email via Maventa). Everything
|
|
29
|
+
else sets `openWorldHint: false` since the operation is confined to the
|
|
30
|
+
caller's own Supabase tenant.
|
|
31
|
+
- **Inline annotation block in `list_transactions`** replaced with the shared
|
|
32
|
+
`READ_ONLY_ANNOTATIONS` constant — single source of truth for hint values.
|
|
33
|
+
- **`reports.ts` local annotation const** removed; imports from `utils.js`.
|
|
34
|
+
Drops one duplicate definition that was introduced in v0.5.2.
|
|
35
|
+
|
|
36
|
+
### Test infrastructure
|
|
37
|
+
|
|
38
|
+
- **`tools-registry.test.ts` guard tests added:**
|
|
39
|
+
- `declares annotations on every registered tool` — iterates the full
|
|
40
|
+
52-tool list and asserts `annotations` is defined. Any regression that
|
|
41
|
+
forgets to pass annotations (or accidentally re-introduces
|
|
42
|
+
`server.tool()`) fails CI.
|
|
43
|
+
- `flags delete_* tools as destructive` — asserts every tool whose name
|
|
44
|
+
starts with `kirjapro_delete_` has `destructiveHint: true` and
|
|
45
|
+
`readOnlyHint: false`. Prevents a delete tool from being silently
|
|
46
|
+
labelled safe.
|
|
47
|
+
- **Full suite: 111 passing (was 109 in v0.5.4).** 7 test files, same auth
|
|
48
|
+
DNS warning as before (benign — `test.supabase.co` resolution in legacy
|
|
49
|
+
env-var test).
|
|
50
|
+
|
|
51
|
+
### Notes
|
|
52
|
+
|
|
53
|
+
- `outputSchema` on write tools is intentionally NOT added in this pass.
|
|
54
|
+
Write payloads are complex (invoice line refinements, journal entries
|
|
55
|
+
with balanced debit/credit tuples) and declaring them risks runtime
|
|
56
|
+
validation surprises on real rows. Deferred to v0.5.6+ as an incremental
|
|
57
|
+
per-tool exercise.
|
|
58
|
+
- The `WRITE_EXTERNAL_ANNOTATIONS` constant is exported but currently only
|
|
59
|
+
used by `kirjapro_send_offer`. Kept in `utils.ts` for future e-invoice
|
|
60
|
+
tools that hit Maventa directly.
|
|
61
|
+
|
|
62
|
+
## [0.5.4] - 2026-04-11
|
|
63
|
+
|
|
64
|
+
M6 tail: the three remaining read tools now declare `outputSchema`.
|
|
65
|
+
|
|
66
|
+
### Structured output
|
|
67
|
+
|
|
68
|
+
- **`registerTool()` + `outputSchema` on `get_balance_sheet`,
|
|
69
|
+
`get_ar_aging`, `get_general_ledger`** — all 9 read tools in the
|
|
70
|
+
reports / invoices / transactions surface now expose typed response
|
|
71
|
+
contracts at `list_tools` time and carry the `readOnlyHint` /
|
|
72
|
+
`idempotentHint` / `openWorldHint: false` annotation set. Inner row
|
|
73
|
+
shapes use `.passthrough()` / `z.unknown()` to stay permissive on
|
|
74
|
+
real-world rows.
|
|
75
|
+
|
|
76
|
+
### Test infrastructure
|
|
77
|
+
|
|
78
|
+
- **Snapshot assertion widened** — `tools-registry.test.ts` now checks
|
|
79
|
+
`outputSchema` presence on all 9 read tools (was 6 in v0.5.3). Any
|
|
80
|
+
future migration that drops a schema fails CI.
|
|
81
|
+
|
|
82
|
+
## [0.5.3] - 2026-04-11
|
|
83
|
+
|
|
84
|
+
Audit follow-through: schema contracts on hot read tools, registration
|
|
85
|
+
drift guard, and test-suite widening.
|
|
86
|
+
|
|
87
|
+
### Structured output
|
|
88
|
+
|
|
89
|
+
- **`registerTool()` migration + `outputSchema` on 6 hot read tools**
|
|
90
|
+
(M6 completion) — `kirjapro_list_invoices`, `kirjapro_get_invoice`,
|
|
91
|
+
`kirjapro_list_transactions`, `kirjapro_get_dashboard`,
|
|
92
|
+
`kirjapro_get_income_statement`, and `kirjapro_get_alv_summary` now
|
|
93
|
+
register via the modern `server.registerTool()` API, declare typed
|
|
94
|
+
`outputSchema` (zod raw shapes), and carry `readOnlyHint` /
|
|
95
|
+
`idempotentHint` / `openWorldHint: false` annotations. MCP clients
|
|
96
|
+
see the schemas at `list_tools` time — agents can validate return
|
|
97
|
+
shapes without "forgot field name" loops.
|
|
98
|
+
|
|
99
|
+
### Test infrastructure
|
|
100
|
+
|
|
101
|
+
- **Tool registration snapshot test** (M16 follow-through) — new
|
|
102
|
+
`tools/tools-registry.test.ts` asserts that exactly 52 tool names
|
|
103
|
+
are registered (catches accidental unregister or rename drift) and
|
|
104
|
+
that the 6 hot read tools all declare `outputSchema`. Verifies
|
|
105
|
+
`kirjapro_send_offer` and `kirjapro_convert_offer_to_invoice` are
|
|
106
|
+
in the bundle (closes the M16 regression concern).
|
|
107
|
+
|
|
108
|
+
### Notes
|
|
109
|
+
|
|
110
|
+
- Output schemas are intentionally lax on row-level fields (use
|
|
111
|
+
`.passthrough()` or `z.unknown()` for nested shapes) to avoid
|
|
112
|
+
runtime validation failures on edge-case rows. The envelope shape
|
|
113
|
+
(`results` / `total_count` / `has_more` / `next_offset`) and the
|
|
114
|
+
top-level report blocks are precise; inner rows are descriptive
|
|
115
|
+
rather than strict. Tighten over time as real usage reveals stable
|
|
116
|
+
shapes.
|
|
117
|
+
- Write tools still use `server.tool()`. Migrating writes to
|
|
118
|
+
`registerTool()` is deferred — the annotations (`destructiveHint`)
|
|
119
|
+
would be valuable, but the schema complexity (zod refinements on
|
|
120
|
+
invoice line items, etc.) needs a dedicated pass.
|
|
121
|
+
|
|
122
|
+
## [0.5.2] - 2026-04-11
|
|
123
|
+
|
|
124
|
+
Round 3 of `ENHANCEMENT-AUDIT-2026-04-11.md`: idempotency + dry-run on
|
|
125
|
+
writes, structured content on hot read tools, atomic booking RPCs, and a
|
|
126
|
+
salary rounding fix.
|
|
127
|
+
|
|
128
|
+
### Reliability
|
|
129
|
+
|
|
130
|
+
- **Idempotency keys on every write tool** (M4) — new
|
|
131
|
+
`mcp_idempotency_keys` table (`20260411132733_add_mcp_idempotency_keys.sql`)
|
|
132
|
+
stores `(company_id, key) → response_payload` with a 24h TTL. Every write
|
|
133
|
+
tool now accepts an optional `idempotencyKey` (8–128 chars). Retries with
|
|
134
|
+
the same key return the cached response verbatim — a retried
|
|
135
|
+
`kirjapro_create_invoice` on a transient network blip will no longer
|
|
136
|
+
create a duplicate invoice. Cache misses pass through; infra errors
|
|
137
|
+
fall through (the wrapper never masks a write). Covered by the new
|
|
138
|
+
`withIdempotency()` helper in `utils.ts`.
|
|
139
|
+
- **Dry-run previews on destructive tools** (M4) — `kirjapro_delete_invoice`,
|
|
140
|
+
`kirjapro_delete_offer`, `kirjapro_delete_recurring_invoice`, and
|
|
141
|
+
`kirjapro_update_offer_status` now accept `dryRun: true`. They validate
|
|
142
|
+
the operation and return `{ dry_run: true, requires_confirmation: true,
|
|
143
|
+
message, preview }` without writing. Agents should always call with
|
|
144
|
+
`dryRun: true` first for irreversible actions, relay the preview to the
|
|
145
|
+
user, and only re-call with `dryRun: false` after confirmation.
|
|
146
|
+
- **Atomic `book_salary` + `book_vat_settlement`** (M9) — both booking
|
|
147
|
+
tools now call `book_salary_atomic` / `book_vat_settlement_atomic`
|
|
148
|
+
SECURITY DEFINER RPCs guarded by `pg_advisory_xact_lock`. Serializes
|
|
149
|
+
concurrent callers per `(company, fiscal_year, period)` so parallel
|
|
150
|
+
tool invocations cannot each write a salary journal for the same pay
|
|
151
|
+
period.
|
|
152
|
+
- **`book_salary` rounding residual** (M15) — employer's TyEL + employee's
|
|
153
|
+
TyEL now use residual-method rounding (last group = total − sum of
|
|
154
|
+
others) so the journal balances to the cent. Parametrized test added
|
|
155
|
+
covering 2026 rates + a handful of adversarial gross amounts.
|
|
156
|
+
|
|
157
|
+
### Structured output
|
|
158
|
+
|
|
159
|
+
- **`structuredContent` on 6 hot read tools** (M6) — new `toResult<T>()`
|
|
160
|
+
helper returns both the JSON-stringified `content` (backward compat)
|
|
161
|
+
and a typed `structuredContent` object. Rolled out to
|
|
162
|
+
`kirjapro_list_invoices`, `kirjapro_get_invoice`,
|
|
163
|
+
`kirjapro_list_transactions`, `kirjapro_get_dashboard`,
|
|
164
|
+
`kirjapro_get_income_statement`, and `kirjapro_get_alv_summary`. Modern
|
|
165
|
+
MCP clients consume `structuredContent` without `JSON.parse`. Declaring
|
|
166
|
+
`outputSchema` via `registerTool()` is deferred to a later version
|
|
167
|
+
since it requires migrating away from the deprecated `server.tool()`
|
|
168
|
+
overload.
|
|
169
|
+
|
|
170
|
+
### Migrations
|
|
171
|
+
|
|
172
|
+
- `20260411132733_add_mcp_idempotency_keys.sql` — `mcp_idempotency_keys`
|
|
173
|
+
table, RLS (`private.has_company_access`), and
|
|
174
|
+
`cleanup_expired_mcp_idempotency_keys()` maintenance function.
|
|
175
|
+
|
|
176
|
+
## [0.5.1] - 2026-04-11
|
|
177
|
+
|
|
178
|
+
Security + compliance + race hardening bundle. Based on
|
|
179
|
+
`ENHANCEMENT-AUDIT-2026-04-11.md` — Round 1 (M1/M2/M5/M8/M10/M14/M16) and
|
|
180
|
+
Round 2 (M3/M7/M11/M12/M13).
|
|
181
|
+
|
|
182
|
+
### Security
|
|
183
|
+
|
|
184
|
+
- **Prompt injection defense** (M3) — new `tagUntrusted()` utility wraps
|
|
185
|
+
attacker-controlled free text in `<untrusted-external>...</untrusted-external>`
|
|
186
|
+
tags. Applied to `kirjapro_list_bank_transactions` (counterparty_name,
|
|
187
|
+
reference, message), `kirjapro_list_received_invoices` /
|
|
188
|
+
`kirjapro_get_received_invoice` (sender_name, sender_business_id,
|
|
189
|
+
invoice_number, payment_reference), and `kirjapro_lookup_business`
|
|
190
|
+
(PRH free-text fields). The helper also strips zero-width characters,
|
|
191
|
+
control chars, and common injection markers (`system:`,
|
|
192
|
+
`<|im_start|>`, "ignore previous", etc.) before wrapping.
|
|
193
|
+
- **`kirjapro://security/data-handling` resource** (M3) — documents the
|
|
194
|
+
wrapper contract, lists every wrapped field per tool, and gives safe
|
|
195
|
+
handling rules. Intended as a session-start read.
|
|
196
|
+
- **Multi-company JWT scoping guard** (M1) — every tool call verifies
|
|
197
|
+
the JWT's `company_id` matches the MCP session's selected company
|
|
198
|
+
before executing, closing the cross-company data leak described in
|
|
199
|
+
CLAUDE.md pitfall #13.
|
|
200
|
+
- **Stdio token-refresh hardening** (M2) — mutex + single-flight refresh
|
|
201
|
+
prevents race between concurrent tool calls and the background refresh
|
|
202
|
+
timer; all 401s now retry once with a fresh token.
|
|
203
|
+
|
|
204
|
+
### Correctness
|
|
205
|
+
|
|
206
|
+
- **Advisory-locked number generators** (M12) — new migration
|
|
207
|
+
`20260411120919_add_next_customer_offer_number_rpcs` adds
|
|
208
|
+
`get_next_customer_number(company_id)` and
|
|
209
|
+
`get_next_offer_number(company_id, type)` RPCs mirroring the
|
|
210
|
+
`pg_advisory_xact_lock(hashtext(...))` pattern from
|
|
211
|
+
`get_next_invoice_number`. `customers.ts` and `offers.ts` now call the
|
|
212
|
+
RPCs instead of read-then-write — fixes 23505 unique-index collisions
|
|
213
|
+
under concurrent creates.
|
|
214
|
+
- **Compliance rates single source of truth** (M7) — new
|
|
215
|
+
`src/compliance/rates.ts` exports `FINNISH_RATES_2026` (VAT, TyEL,
|
|
216
|
+
sotu, TTV, tapaturma, ryhmähenki) with a validity window.
|
|
217
|
+
`bookings.ts`, `templates.ts`, and `resources/compliance.ts` now
|
|
218
|
+
import from it instead of duplicating literals. Every compliance
|
|
219
|
+
resource emits an `_meta` envelope (`published_at`, `valid_through`,
|
|
220
|
+
`stale`, `days_until_expiry`); new `kirjapro://compliance/_freshness`
|
|
221
|
+
index resource lets the agent detect expired rates in one read at
|
|
222
|
+
session start.
|
|
223
|
+
- **Report tools auto-resolve fiscal year** (M11) — `get_dashboard`,
|
|
224
|
+
`get_income_statement`, `get_balance_sheet`, and `get_general_ledger`
|
|
225
|
+
now accept `fiscalYearId` as optional. When omitted, the single open
|
|
226
|
+
fiscal year is resolved via `resolveOpenFiscalYear()`; tools error
|
|
227
|
+
with a clear hint when multiple fiscal years are open.
|
|
228
|
+
|
|
229
|
+
### Fixed
|
|
230
|
+
|
|
231
|
+
- Various small bugs (M5/M8/M10/M14/M16) — field selection drift,
|
|
232
|
+
error-message sanitization, pagination off-by-ones, and type narrowing
|
|
233
|
+
cleanups from Round 1 of the audit.
|
|
234
|
+
|
|
235
|
+
### Internal
|
|
236
|
+
|
|
237
|
+
- New helper: `tagUntrusted(value, maxLen)` in `src/utils.ts`
|
|
238
|
+
- New helper: `resolveOpenFiscalYear(supabase, companyId)` in
|
|
239
|
+
`src/utils.ts`
|
|
240
|
+
- New module: `src/compliance/rates.ts` with `FINNISH_RATES_2026` +
|
|
241
|
+
`freshnessMeta()`
|
|
242
|
+
- New resource module: `src/resources/security.ts`
|
|
243
|
+
- `database.types.ts` augmented with `get_next_customer_number` and
|
|
244
|
+
`get_next_offer_number` RPC signatures
|
|
245
|
+
|
|
246
|
+
### Notes
|
|
247
|
+
|
|
248
|
+
- M13 (`record_payment` TOCTOU) reviewed and downgraded to a nit — the
|
|
249
|
+
existing `record_invoice_payment` and `confirm_reconciliation_match`
|
|
250
|
+
RPCs already `SELECT … FOR UPDATE` the invoice row, so concurrent
|
|
251
|
+
callers are serialized at the DB layer.
|
|
252
|
+
- Verified: `tsc --noEmit` clean, 101/101 unit tests pass, `esbuild`
|
|
253
|
+
bundle clean (885 KB).
|
|
254
|
+
|
|
255
|
+
## [0.5.0] - 2026-03-28
|
|
256
|
+
|
|
257
|
+
### Added
|
|
258
|
+
|
|
259
|
+
- **Recurring invoices CRUD** — 6 tools: `kirjapro_list_recurring_invoices`, `kirjapro_get_recurring_invoice`, `kirjapro_create_recurring_invoice`, `kirjapro_update_recurring_invoice`, `kirjapro_delete_recurring_invoice`, `kirjapro_trigger_recurring_invoice` for managing recurring invoice templates with weekly/monthly/quarterly/yearly scheduling
|
|
260
|
+
- **Received invoices (read-only)** — 2 tools: `kirjapro_list_received_invoices`, `kirjapro_get_received_invoice` for viewing purchase invoices with status, sender, and amount filters
|
|
261
|
+
- **PRH business lookup** — `kirjapro_lookup_business` tool to look up Finnish companies by Y-tunnus from PRH (Patent and Registration Office), returns official name, address, company form
|
|
262
|
+
- **ALV summary report** — `kirjapro_get_alv_summary` tool for VAT return preparation with output/input VAT breakdown by rate and OmaVero field codes (301-320)
|
|
263
|
+
- `invokeEdgeFunction()` utility for consistent, typed edge function invocation with error handling across all tools
|
|
264
|
+
- **Typed Supabase client** — generated `database.types.ts` from production schema, wired `createClient<Database>()`. Removes all `as unknown as T` casts from tool files (reports, transactions, customers) — queries are now type-safe end-to-end
|
|
265
|
+
- **Finnish compliance resources** — 5 new MCP resources exposing compliance knowledge: `kirjapro://compliance/vat` (rates, deduction rules, reverse charge, common mistakes), `kirjapro://compliance/invoicing` (AVL 209 e § 17 mandatory fields, hyvityslasku rules), `kirjapro://compliance/deadlines` (verokausi thresholds, filing periods, pienyrittäjä 20K€ threshold), `kirjapro://compliance/social-insurance` (2026 TyEL/sotu/TTV rates), `kirjapro://compliance/bookkeeping` (KPL requirements, retention periods, company size classification)
|
|
266
|
+
- Enhanced tool descriptions with compliance context: VAT rate rules on `kirjapro_book_purchase`, filing deadline info on `kirjapro_get_alv_summary` and `kirjapro_book_vat_settlement`
|
|
267
|
+
- Enhanced `kirjapro://vat-rates` resource with legal basis citations (AVL §) and rate change history
|
|
268
|
+
|
|
269
|
+
## [0.4.0] - 2026-03-28
|
|
270
|
+
|
|
271
|
+
### Fixed
|
|
272
|
+
|
|
273
|
+
- **search_transactions pagination bug** — amount filters no longer cause unbounded fetches of all transactions into memory. Fetches are capped at 1000 rows, pagination (`total_count`, `has_more`) now works correctly with amount-filtered results
|
|
274
|
+
- **Error message data exposure** — all Supabase/PostgREST errors are now sanitized before returning to MCP clients. Known error codes map to safe messages; unknown errors have table names, constraint names, and column names stripped. Raw errors are logged to stderr for debugging
|
|
275
|
+
- **Report query safety caps** — dashboard, income statement, and balance sheet queries are capped at 50,000 journal entries to prevent memory exhaustion on large datasets. A warning is included in the response if the cap is reached
|
|
276
|
+
|
|
277
|
+
### Added
|
|
278
|
+
|
|
279
|
+
- `sanitizeDbError()` utility for consistent, safe error message handling across all tools
|
|
280
|
+
|
|
281
|
+
## [0.3.0] - 2026-03-06
|
|
282
|
+
|
|
283
|
+
### Added
|
|
284
|
+
|
|
285
|
+
- **Transaction templates** — 3 tools: `kirjapro_list_templates`, `kirjapro_create_from_template`, `kirjapro_create_from_template_batch` for common Finnish bookkeeping patterns (cash/bank sales, purchases, rent, salary, bank transfer) with automatic VAT splitting
|
|
286
|
+
- **Domain-specific booking tools** — 3 tools: `kirjapro_book_purchase` (with reverse charge and edustus support), `kirjapro_book_salary` (2-transaction salary with 2026 Finnish social insurance rates), `kirjapro_book_vat_settlement` (automatic ALV-tilitys from journal entries)
|
|
287
|
+
- **Offers & contracts** — 5 tools: `kirjapro_list_offers`, `kirjapro_get_offer`, `kirjapro_create_offer`, `kirjapro_update_offer_status`, `kirjapro_delete_offer` with status state machine and event logging
|
|
288
|
+
- Auto-resolve fiscal year when `fiscalYearId` is omitted (uses the single open fiscal year)
|
|
289
|
+
- Account overrides for templates (e.g. swap bank account `{"2320": "2330"}`)
|
|
290
|
+
|
|
291
|
+
### Fixed
|
|
292
|
+
|
|
293
|
+
- Invoice number generation uses advisory-locked RPC to prevent race conditions
|
|
294
|
+
- Invoice delete now handles existing payments on draft invoices
|
|
295
|
+
- Missing `company_id` scoping on invoice/bank transaction update mutations
|
|
296
|
+
- Partial payment now correctly transitions invoice status to `partial`
|
|
297
|
+
- Bank transaction matching now sets `partial` status for incomplete payments
|
|
298
|
+
- VAT settlement date clamped to fiscal year end to prevent out-of-range errors
|
|
299
|
+
- Offer/customer queries use `.maybeSingle()` to prevent PGRST116 on empty results
|
|
300
|
+
|
|
3
301
|
## [0.2.0] - 2026-02-19
|
|
4
302
|
|
|
5
303
|
### Added
|
package/README.md
CHANGED
|
@@ -2,32 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
MCP server for Finnish accounting. Exposes Kirjapro bookkeeping, invoicing, and reporting tools to Claude Code, Claude Desktop, and any MCP client.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Full documentation:** [kirjapro.fi/docs/mcp](https://kirjapro.fi/docs/mcp/)
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
9
|
- Node.js 20+
|
|
10
|
-
- Kirjapro account with **Company
|
|
10
|
+
- Kirjapro account with **Entrepreneur**, **Company**, or **Custom** subscription tier
|
|
11
11
|
- API key (generate at Settings > API-avaimet)
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
15
|
### 1. Generate an API Key
|
|
16
16
|
|
|
17
|
-
1. Go to **
|
|
17
|
+
1. Go to **Asetukset > API-avaimet** in the [Kirjapro app](https://kirjapro.fi)
|
|
18
18
|
2. Click **"Luo uusi avain"**
|
|
19
|
-
3. Copy the key (shown only once)
|
|
19
|
+
3. Copy the key (starts with `kp_`, shown only once)
|
|
20
20
|
|
|
21
21
|
### 2. Configure your MCP client
|
|
22
22
|
|
|
23
23
|
#### Claude Code
|
|
24
24
|
|
|
25
|
-
Add to `.
|
|
25
|
+
Add to your project's `.mcp.json` (recommended) or global config:
|
|
26
|
+
|
|
27
|
+
| OS | Project-level (recommended) | Global |
|
|
28
|
+
|----|----------------------------|--------|
|
|
29
|
+
| macOS / Linux | `.mcp.json` in project root | `~/.claude/mcp.json` |
|
|
30
|
+
| Windows | `.mcp.json` in project root | `%USERPROFILE%\.claude\mcp.json` |
|
|
26
31
|
|
|
27
32
|
```json
|
|
28
33
|
{
|
|
29
34
|
"mcpServers": {
|
|
30
35
|
"kirjapro": {
|
|
36
|
+
"type": "stdio",
|
|
31
37
|
"command": "npx",
|
|
32
38
|
"args": ["-y", "@kirjapro/mcp-server"],
|
|
33
39
|
"env": {
|
|
@@ -38,10 +44,18 @@ Add to `.claude/mcp.json`:
|
|
|
38
44
|
}
|
|
39
45
|
```
|
|
40
46
|
|
|
47
|
+
Verify with `/mcp` in Claude Code.
|
|
48
|
+
|
|
41
49
|
#### Claude Desktop
|
|
42
50
|
|
|
43
51
|
Add to `claude_desktop_config.json`:
|
|
44
52
|
|
|
53
|
+
| OS | Path |
|
|
54
|
+
|----|------|
|
|
55
|
+
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
56
|
+
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
57
|
+
| Linux | `~/.config/Claude/claude_desktop_config.json` |
|
|
58
|
+
|
|
45
59
|
```json
|
|
46
60
|
{
|
|
47
61
|
"mcpServers": {
|
|
@@ -56,107 +70,47 @@ Add to `claude_desktop_config.json`:
|
|
|
56
70
|
}
|
|
57
71
|
```
|
|
58
72
|
|
|
73
|
+
Restart Claude Desktop after saving.
|
|
74
|
+
|
|
75
|
+
#### Other clients
|
|
76
|
+
|
|
77
|
+
See [full setup guide](https://kirjapro.fi/docs/mcp/) for Cursor, VS Code / Copilot, Windsurf, and generic stdio.
|
|
78
|
+
|
|
59
79
|
### 3. Verify
|
|
60
80
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
##
|
|
64
|
-
|
|
65
|
-
| Variable | Required | Description |
|
|
66
|
-
|----------|----------|-------------|
|
|
67
|
-
| `KIRJAPRO_API_KEY` | Yes* | API key from Settings > API-avaimet |
|
|
68
|
-
|
|
69
|
-
### Legacy (development only)
|
|
70
|
-
|
|
71
|
-
| Variable | Required | Description |
|
|
72
|
-
|----------|----------|-------------|
|
|
73
|
-
| `SUPABASE_URL` | Yes* | Supabase project URL |
|
|
74
|
-
| `SUPABASE_ACCESS_TOKEN` | Yes* | User's JWT access token |
|
|
75
|
-
| `KIRJAPRO_COMPANY_ID` | Yes* | Company UUID to operate on |
|
|
76
|
-
|
|
77
|
-
*Either `KIRJAPRO_API_KEY` or all three legacy variables must be set.
|
|
78
|
-
|
|
79
|
-
## Tools (28)
|
|
80
|
-
|
|
81
|
-
### Read Tools
|
|
82
|
-
|
|
83
|
-
| Tool | Description |
|
|
84
|
-
|------|-------------|
|
|
85
|
-
| `kirjapro_list_accounts` | List chart of accounts with filtering by type |
|
|
86
|
-
| `kirjapro_list_transactions` | List transactions with journal entries for a fiscal year |
|
|
87
|
-
| `kirjapro_search_transactions` | Search transactions by text, date range, or amount |
|
|
88
|
-
| `kirjapro_get_transaction` | Get single transaction with journal entries and account details |
|
|
89
|
-
| `kirjapro_list_invoices` | List invoices with customer names, filter by status |
|
|
90
|
-
| `kirjapro_get_invoice` | Get single invoice with lines, payments, and VAT breakdown |
|
|
91
|
-
| `kirjapro_list_customers` | List customers with search |
|
|
92
|
-
| `kirjapro_get_customer` | Get single customer with invoice stats |
|
|
93
|
-
| `kirjapro_list_bank_accounts` | List active bank accounts with balances |
|
|
94
|
-
| `kirjapro_list_bank_transactions` | List bank transactions with filtering |
|
|
95
|
-
| `kirjapro_list_fiscal_years` | List fiscal years with open/closed status |
|
|
96
|
-
| `kirjapro_get_dashboard` | Financial dashboard: revenue, expenses, invoice stats, bank balances |
|
|
97
|
-
| `kirjapro_get_income_statement` | Income statement (tuloslaskelma) for a date range |
|
|
98
|
-
| `kirjapro_get_balance_sheet` | Balance sheet (tase) as of a specific date |
|
|
99
|
-
| `kirjapro_get_ar_aging` | Accounts receivable aging (0-30, 31-60, 61-90, 90+ days) |
|
|
100
|
-
| `kirjapro_get_general_ledger` | General ledger (pääkirja) for one account with running balance |
|
|
101
|
-
|
|
102
|
-
### Write Tools
|
|
103
|
-
|
|
104
|
-
| Tool | Description |
|
|
105
|
-
|------|-------------|
|
|
106
|
-
| `kirjapro_create_transaction` | Create an accounting transaction with journal entries |
|
|
107
|
-
| `kirjapro_create_transactions_batch` | Bulk create up to 50 transactions (partial success) |
|
|
108
|
-
| `kirjapro_create_invoice` | Create invoice with auto-generated number and reference |
|
|
109
|
-
| `kirjapro_create_customer` | Create customer with Y-tunnus validation |
|
|
110
|
-
| `kirjapro_update_customer` | Update customer fields (partial update, re-validates Y-tunnus) |
|
|
111
|
-
| `kirjapro_record_payment` | Record payment against an invoice |
|
|
112
|
-
| `kirjapro_update_invoice_status` | Update invoice status with state machine validation |
|
|
113
|
-
| `kirjapro_delete_invoice` | Delete draft invoices (audit-safe) |
|
|
114
|
-
| `kirjapro_match_bank_transaction` | Match bank transaction to an invoice |
|
|
115
|
-
|
|
116
|
-
### Validation Tools
|
|
117
|
-
|
|
118
|
-
| Tool | Description |
|
|
119
|
-
|------|-------------|
|
|
120
|
-
| `kirjapro_validate_business_id` | Validate Finnish Y-tunnus |
|
|
121
|
-
| `kirjapro_validate_iban` | Validate Finnish IBAN |
|
|
122
|
-
| `kirjapro_generate_reference` | Generate viitenumero with check digit |
|
|
123
|
-
|
|
124
|
-
## Resources (4)
|
|
125
|
-
|
|
126
|
-
| URI | Description |
|
|
127
|
-
|-----|-------------|
|
|
128
|
-
| `kirjapro://accounts/chart` | Finnish standard chart of accounts (YSE 2017) |
|
|
129
|
-
| `kirjapro://vat-rates` | Finnish VAT rates (25.5%, 13.5%, 10%, 0%) |
|
|
130
|
-
| `kirjapro://company/info` | Current company details |
|
|
131
|
-
| `kirjapro://fiscal-years` | Fiscal years with open/closed status |
|
|
132
|
-
|
|
133
|
-
## Development
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
cd mcp-server
|
|
137
|
-
npm install
|
|
138
|
-
npm run dev # Run with tsx
|
|
139
|
-
npm run build # Build with esbuild
|
|
140
|
-
npm test # Run vitest
|
|
141
|
-
npm run lint # Type check
|
|
142
|
-
```
|
|
81
|
+
Ask your AI assistant: *"list my fiscal years"* — it should call `kirjapro_list_fiscal_years` and return your company's accounting periods.
|
|
82
|
+
|
|
83
|
+
## What's included
|
|
143
84
|
|
|
144
|
-
|
|
85
|
+
**49 tools** across 10 domains:
|
|
145
86
|
|
|
146
|
-
|
|
87
|
+
| Domain | Tools | Examples |
|
|
88
|
+
|--------|-------|---------|
|
|
89
|
+
| Accounts | 1 | List chart of accounts with filtering |
|
|
90
|
+
| Transactions | 4 | Create, search, batch import |
|
|
91
|
+
| Templates | 3 | Auto-balanced entries with VAT splitting |
|
|
92
|
+
| Invoices | 5 | Create, send, record payments, status management |
|
|
93
|
+
| Customers | 4 | CRUD + PRH business lookup |
|
|
94
|
+
| Banking | 3 | List accounts/transactions, match to invoices |
|
|
95
|
+
| Reports | 6 | Dashboard, income statement, balance sheet, AR aging, general ledger, ALV summary |
|
|
96
|
+
| Bookings | 4 | Purchase, sale, salary, VAT settlement — with automatic double-entry |
|
|
97
|
+
| Offers | 5 | Offer/contract lifecycle management |
|
|
98
|
+
| Recurring | 6 | Recurring invoice templates |
|
|
99
|
+
| Received | 2 | Received (purchase) invoices |
|
|
100
|
+
| Validation | 3 | Y-tunnus, IBAN, viitenumero |
|
|
147
101
|
|
|
148
|
-
|
|
149
|
-
2. Update `CHANGELOG.md`
|
|
150
|
-
3. Commit and tag: `git tag mcp-server/v0.2.0`
|
|
151
|
-
4. Push: `git push origin mcp-server/v0.2.0`
|
|
102
|
+
**9 resources** for reference data: chart of accounts, VAT rates, company info, fiscal years, and 5 Finnish compliance resources.
|
|
152
103
|
|
|
153
|
-
|
|
104
|
+
See the [full tool reference](https://kirjapro.fi/docs/mcp/) for parameters, usage examples, and error handling.
|
|
154
105
|
|
|
155
106
|
## Security
|
|
156
107
|
|
|
157
108
|
- API keys are hashed with SHA-256; the full key is never stored
|
|
158
109
|
- Keys exchange for short-lived JWTs (1 hour) via the `mcp-auth` edge function
|
|
159
|
-
- All queries use
|
|
160
|
-
- Automatic token refresh keeps long-running
|
|
161
|
-
- Feature gate: requires `hasApiAccess` (Company/Custom tier)
|
|
110
|
+
- All queries use Row Level Security (RLS) — users can only access their own company's data
|
|
111
|
+
- Automatic token refresh keeps long-running sessions alive
|
|
162
112
|
- Rate limiting: 10 auth requests per minute per key
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|