@kirjapro/mcp-server 0.5.5 → 0.5.7

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 CHANGED
@@ -1,5 +1,156 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.7] - 2026-05-09
4
+
5
+ Pre-launch trim and supply-chain hardening. Two coordinated changes shape
6
+ the launch posture: a curated default surface that keeps the agent under
7
+ the empirical tool-selection accuracy cliff, and a fingerprint guard that
8
+ defends against silent description / annotation / inputSchema tampering
9
+ between releases.
10
+
11
+ ### Added — `KIRJAPRO_MCP_SURFACE` env var
12
+
13
+ - **Default `core` surface (26 of 53 tools)** — daily-use shape per 2025-2026
14
+ SOTA research (Anthropic Opus 4 dropped to 49% accuracy at large MCP
15
+ catalogs, recovered to 79.5% with Tool Search). 27 tools deferred:
16
+ booking shortcuts (`book_*`), templates, recurring invoices, received
17
+ invoices, batch tools, deletes, financial notes, manual offer status,
18
+ search/get_transaction, general_ledger, list_bank_accounts,
19
+ update_customer. All kept in code; restored on flip of
20
+ `KIRJAPRO_MCP_SURFACE=full`.
21
+ - **Surface-aware `INSTRUCTIONS`** — common preamble + core-mode addendum
22
+ ("redirect to web UI for these workflows") OR full-mode addendum
23
+ ("extended workflows for the deferred set"). The agent never reads
24
+ workflow hints for tools missing from its `tools/list`. Closes the
25
+ worst-class failure mode: agent reaches for closest-match tool and
26
+ ships a one-off invoice when the user wanted a recurring template.
27
+ - **Capabilities NOT in this MCP** section in `INSTRUCTIONS_COMMON` —
28
+ always-missing tasks (file uploads, bank account configuration,
29
+ e-invoice sending, multi-company switching, year-end disclosure form)
30
+ redirected to the web UI in any surface mode.
31
+ - **Boot log** announces `surface=core — registered 26 tools, deferred 27`
32
+ or `surface=full — registered all 53 tools`. Unknown values fall back
33
+ to `core` with a stderr warning.
34
+ - **`kirjapro-aloita`** prompt computes the active tool count dynamically
35
+ from `_registeredTools` size — accurate for both surfaces, no copy
36
+ drift.
37
+
38
+ ### Added — Tool description fingerprint guard
39
+
40
+ - **`tool-fingerprints.json`** ships with the package. Each tool's
41
+ `description + annotations + inputSchema` is hashed via SHA-256
42
+ truncated to 64 bits and persisted alphabetically by tool name.
43
+ Defends against the rug-pull vector documented by Pipelock and CyberArk
44
+ — silent description tampering or schema relaxation between releases.
45
+ - **CI guard** (`tools-registry.test.ts`) asserts the running build's
46
+ fingerprint set matches the persisted file. Failure message tells the
47
+ operator: bump `package.json` version and run
48
+ `npm run fingerprints:update` if intentional, revert otherwise.
49
+ - **`fingerprints:update` script** logs every `ADDED` / `REMOVED` /
50
+ `CHANGED <name> <oldhash> → <newhash>` entry before writing. Silent
51
+ laundering of a malicious description through "version-bump + regen"
52
+ must also falsify CI logs to slip past review.
53
+ - **Schema coverage in v0.5.7** — `inputSchema` now part of the hash
54
+ payload. v0.5.6 had description+annotations only, leaving Zod-enum
55
+ relaxation as a coverage gap. Closed in this release per the
56
+ pre-launch code review (docs/reviews/2026-05-09-mcp-fingerprint-guard.md).
57
+
58
+ ### Tests
59
+
60
+ - **187 passing** (was 172 in v0.5.6). Three new registry tests cover
61
+ surface=core (26-tool exact match), deferred tools NOT registered, and
62
+ CORE_TOOL_NAMES is a strict subset of the full registration set. One
63
+ new test asserts current build matches the persisted fingerprint file.
64
+
65
+ ### Fixed
66
+
67
+ - **Stale `52 tools` claim** in `INSTRUCTIONS` and the `kirjapro-aloita`
68
+ Finnish prompt — was last updated before DT-045 added
69
+ `kirjapro_get_financial_notes`. Both now derive count dynamically.
70
+ - **Supabase CLI version banner pollution** in `database.types.ts` — the
71
+ CLI emits its update-notification banner to STDOUT, which had been
72
+ concatenated to the bottom of the generated file by a prior
73
+ `gen types ... > database.types.ts` redirect. Broke `tsc --noEmit`
74
+ inside `mcp-server/` until removed. Skill
75
+ `supabase-gen-types-cli-banner-pollution` documents the failure mode
76
+ and the `grep -v` filter pipeline that prevents it.
77
+
78
+ ### Notes
79
+
80
+ - The npm package now ships `tool-fingerprints.json` alongside
81
+ `dist/index.js`. Downstream operators who want Pipelock-style pinning
82
+ can read the JSON and reject mid-release tampering.
83
+ - Part of the broader MCP SOTA enhancement track filed in
84
+ `docs/roadmap/features/planned/mcp-server-*` — Phase 1 (observability,
85
+ per-call telemetry, CI fingerprint enforcement at scale) is sequenced
86
+ for post-launch when real traffic exists to inform the eager-tool set.
87
+
88
+ ## [0.5.6] - 2026-04-20
89
+
90
+ Pre-production adversarial audit hardening. Ten findings verified and patched
91
+ across auth, idempotency, numbering, account scoping, and calendar validation.
92
+ No tool-surface changes — all tool names, parameters, and return shapes are
93
+ stable. One nullable DB column added (`mcp_idempotency_keys.body_sha256`);
94
+ legacy rows continue to work without backfill.
95
+
96
+ ### Security & correctness
97
+
98
+ - **`.or()` grammar injection blocked** — `escapeOrValue()` percent-encodes
99
+ `,`, `(`, `)` before interpolation into PostgREST `.or(...)` filters. Applied
100
+ at all four sites: `accounts.ts`, `customers.ts`, `received-invoices.ts`,
101
+ `banking.ts`. Five new test cases.
102
+ - **Audit-log IP source trustworthiness** — `mcp-auth` edge function prefers
103
+ `x-real-ip`, then `cf-connecting-ip`, then leftmost of `x-forwarded-for`
104
+ before attributing a request to a caller IP. Requires `--no-verify-jwt`
105
+ redeploy.
106
+ - **Idempotency burst fail-open** — `withIdempotency()` now polls a pending
107
+ claim in `CLAIM_WAIT_MS` slices until either the response lands or the claim
108
+ ages past `CLAIM_STALE_MS`; on exhaustion returns an explicit `retry_later`
109
+ error instead of racing into a duplicate write.
110
+ - **Idempotency body-hash check** (T3-6, migration
111
+ `20260420185239_mcp_idempotency_body_hash.sql`) — each claim stores
112
+ `sha256(canonical JSON of params ∖ idempotencyKey)`. On cache hit the server
113
+ recomputes and compares; mismatch returns `IDEMPOTENCY_BODY_MISMATCH`
114
+ instead of silently replaying the wrong cached response. Nullable column,
115
+ legacy rows and tests without params skip the check.
116
+ - **`initLegacyAuth` bypass closed** — `auth.ts` requires explicit
117
+ `ALLOW_LEGACY_AUTH=true` opt-in; otherwise throws with an actionable error.
118
+ Opt-in path logs a deprecation warning.
119
+
120
+ ### Validation & data integrity
121
+
122
+ - **`accountOverrides` allowlist** — `validateAccountOverrides()` in
123
+ `templates.ts` rejects missing or inactive target accounts, enforces type
124
+ parity with the source account, and merges per-line overrides while
125
+ rejecting conflicts where a single source maps to multiple targets.
126
+ - **Calendar-invalid dates rejected at parse** — new `isValidCalendarDate()`
127
+ + `ISO_DATE_SCHEMA` helpers validate via UTC round-trip (Feb 31 no longer
128
+ silently rolls over to Mar 3). Wired across nine tool files (27 call sites);
129
+ month-only patterns (e.g. `YYYY-MM` on ALV-kausi) are intentionally not
130
+ swapped. Six new unit tests.
131
+ - **Invoice-numbering RPC audit** (T3-5) — verified all three monotonic
132
+ mints (`customers`, `invoices`, `offers`) plus `convert_offer_to_invoice`
133
+ use advisory-locked server-side RPCs. No in-tool `MAX(n)+1` anywhere.
134
+ Documented as clean; no code change required.
135
+
136
+ ### Tooling
137
+
138
+ - **Tests:** 172 passing (up from 154 in v0.5.5). +6 ISO_DATE_SCHEMA,
139
+ +6 validateAccountOverrides, +6 body-hash (4 hash-helper + 2
140
+ mismatch/match scenarios).
141
+ - **Typecheck:** `tsc --noEmit` clean.
142
+
143
+ ### Deploy prerequisites
144
+
145
+ Published artefact requires:
146
+
147
+ 1. Apply migration `20260420185239_mcp_idempotency_body_hash.sql` to the
148
+ Supabase project (adds nullable `body_sha256`). Missing column will NOT
149
+ break the server — the INSERT still succeeds with PostgREST schema-cache
150
+ tolerance — but the mismatch check will be inert until migrated.
151
+ 2. Redeploy `mcp-auth` edge function with `--no-verify-jwt` so the IP-source
152
+ hardening (T2-3) takes effect.
153
+
3
154
  ## [0.5.5] - 2026-04-11
4
155
 
5
156
  Tool-annotation sweep: every remaining `server.tool()` call migrated to
package/README.md CHANGED
@@ -80,26 +80,51 @@ See [full setup guide](https://kirjapro.fi/docs/mcp/) for Cursor, VS Code / Copi
80
80
 
81
81
  Ask your AI assistant: *"list my fiscal years"* — it should call `kirjapro_list_fiscal_years` and return your company's accounting periods.
82
82
 
83
+ ### 4. Try these prompts
84
+
85
+ A few prompts to feel out the daily workflows the agent handles cleanly:
86
+
87
+ - *"Show my dashboard"* — financial snapshot of the current fiscal year
88
+ - *"Create an invoice for Acme Oy, 5000 € for consulting in March"* — full lifecycle from customer lookup to draft invoice
89
+ - *"Draft a contract for Acme Oy and email it to john@acme.fi, 3-month retainer at 5000 € / month"* — `tarjous`/`sopimus` create + customer-visible email link
90
+ - *"Record that invoice #42 was paid yesterday"* — payment recording + auto status transition
91
+ - *"What's my VAT for this quarter?"* — `kirjapro_get_alv_summary` with OmaVero field codes
92
+ - *"Show overdue invoices"* — AR aging report
93
+ - *"Match this bank deposit to invoice #42"* — bank reconciliation in one call
94
+
83
95
  ## What's included
84
96
 
85
- **49 tools** across 10 domains:
86
-
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 |
101
-
102
- **9 resources** for reference data: chart of accounts, VAT rates, company info, fiscal years, and 5 Finnish compliance resources.
97
+ **26 tools** in the default `core` surface, focused on the daily-use workflows: read your books, invoice flow, transactions + banking, contract create / send / convert, Finnish validators. The full 53-tool catalog (booking shortcuts, recurring invoices, templates, batch tools, etc.) is available via opt-in:
98
+
99
+ ```jsonc
100
+ {
101
+ "mcpServers": {
102
+ "kirjapro": {
103
+ "command": "npx",
104
+ "args": ["-y", "@kirjapro/mcp-server"],
105
+ "env": {
106
+ "KIRJAPRO_API_KEY": "kp_your_key_here",
107
+ "KIRJAPRO_MCP_SURFACE": "full" // 53 tools instead of 26
108
+ }
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ **Why default to 26 instead of 53:** 2025-2026 SOTA research on tool catalog scaling (Anthropic, OpenAI, MCP authors) shows tool-selection accuracy degrades between 25-50 tools per catalog. A focused surface produces better first-call selections for the daily workflows. As real usage data informs which deferred tools matter most, they'll be promoted into core.
115
+
116
+ | Domain (core) | Tools |
117
+ |---|---|
118
+ | Read your books | `list_fiscal_years`, `list_accounts`, `get_dashboard`, `get_income_statement`, `get_balance_sheet`, `get_alv_summary`, `get_ar_aging` |
119
+ | Customers | `list_customers`, `get_customer`, `create_customer`, `lookup_business` (PRH) |
120
+ | Invoice lifecycle | `list_invoices`, `get_invoice`, `create_invoice`, `record_payment`, `update_invoice_status` |
121
+ | Transactions + banking | `list_transactions`, `create_transaction`, `list_bank_transactions`, `match_bank_transaction` |
122
+ | Contracts | `create_offer` (`tarjous` / `sopimus`), `send_offer` (email link), `convert_offer_to_invoice` |
123
+ | Validators (free) | `validate_business_id`, `validate_iban`, `generate_reference` |
124
+
125
+ **Deferred in core, available with `KIRJAPRO_MCP_SURFACE=full`:** booking shortcuts (`book_*`), templates, recurring invoices, received invoices, batch tools, `delete_*`, `update_*` (besides invoice status), `search_transactions`, `get_transaction`, `get_general_ledger`, `list_bank_accounts`, `get_financial_notes`, manual offer status / list / get / delete.
126
+
127
+ **11 resources** for reference data: chart of accounts, VAT rates, company info, fiscal years, 5 Finnish compliance resources, compliance freshness index, and security data-handling.
103
128
 
104
129
  See the [full tool reference](https://kirjapro.fi/docs/mcp/) for parameters, usage examples, and error handling.
105
130
 
@@ -110,6 +135,7 @@ See the [full tool reference](https://kirjapro.fi/docs/mcp/) for parameters, usa
110
135
  - All queries use Row Level Security (RLS) — users can only access their own company's data
111
136
  - Automatic token refresh keeps long-running sessions alive
112
137
  - Rate limiting: 10 auth requests per minute per key
138
+ - **Tool description fingerprint guard** — every tool's `description + annotations + inputSchema` is hashed and shipped as `tool-fingerprints.json`. Downstream operators who want supply-chain pinning can verify the running MCP matches the known-good fingerprint set, defending against silent description tampering between releases.
113
139
 
114
140
  ## License
115
141