@kirjapro/mcp-server 0.18.0 → 0.18.1
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 +15 -0
- package/README.md +4 -3
- package/dist/index.js +19 -12
- package/package.json +1 -1
- package/server.json +1 -1
- package/tool-fingerprints.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.18.1] - 2026-10-19
|
|
4
|
+
|
|
5
|
+
No database migration; one tool fingerprint changes (`kirjapro_book_sale`).
|
|
6
|
+
|
|
7
|
+
- `kirjapro_book_sale` books the sale of a company outside the VAT register gross even when
|
|
8
|
+
the receipt or invoice it gave showed VAT (founder decision 19.10.2026, audit T2-3): a
|
|
9
|
+
`vatRate` above 0 is no longer refused with `NOT_VAT_REGISTERED_SALE`, it is the rate the
|
|
10
|
+
receipt showed. No VAT is booked (no 4210 line, `vat: 0`, `vat_rate: "0 %"`), and the
|
|
11
|
+
result and the dry run add `vat_notice`, a Finnish note the agent relays to the user: the
|
|
12
|
+
company charges no VAT, the sale was booked in full as revenue, and a receipt that showed
|
|
13
|
+
VAT is wrong and is replaced with a corrected receipt without VAT, attached as the voucher
|
|
14
|
+
in the Kirjapro app.
|
|
15
|
+
- A sale template with VAT (`cash_sale_25` and the like) is still refused for such a
|
|
16
|
+
company, and the refusal now points to `kirjapro_book_sale` with the receipt's rate.
|
|
17
|
+
|
|
3
18
|
## [0.18.0] - 2026-10-19
|
|
4
19
|
|
|
5
20
|
**Breaking: Node.js 22 or newer is required** (`engines.node` `>=22`; Node.js 20 reached its
|
package/README.md
CHANGED
|
@@ -201,9 +201,10 @@ See the [full tool reference](https://kirjapro.fi/docs/mcp/) for parameters, usa
|
|
|
201
201
|
cents (`INVALID_AMOUNT` otherwise), and `documentNumber` is the company's own
|
|
202
202
|
voucher number: leave it out for the next number (a supplier's receipt number
|
|
203
203
|
belongs in the description).
|
|
204
|
-
- A company outside the VAT register books its sales without VAT
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
- A company outside the VAT register books its sales without VAT: the sale
|
|
205
|
+
templates with VAT are not offered, and `kirjapro_book_sale` books the gross
|
|
206
|
+
amount as revenue. If the receipt showed VAT, the result's `vat_notice` tells
|
|
207
|
+
the user to give the customer a corrected receipt without VAT (0.18.1). Recurring invoice templates take prices of 0 or more
|
|
207
208
|
(a discount is `discountPercent`) and a first date from today on.
|
|
208
209
|
- Update tools are annotated `destructiveHint: true` and the recurring invoice
|
|
209
210
|
writes `openWorldHint: true`, so a host that auto-approves non-destructive
|
package/dist/index.js
CHANGED
|
@@ -35743,7 +35743,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
35743
35743
|
import { createClient } from "@supabase/supabase-js";
|
|
35744
35744
|
|
|
35745
35745
|
// src/version.ts
|
|
35746
|
-
var VERSION = "0.18.
|
|
35746
|
+
var VERSION = "0.18.1";
|
|
35747
35747
|
|
|
35748
35748
|
// src/auth.ts
|
|
35749
35749
|
var SUPABASE_PROJECT_URL = "https://tifewzsimmyoiepblhld.supabase.co";
|
|
@@ -41808,7 +41808,11 @@ var ACCOUNTS = {
|
|
|
41808
41808
|
|
|
41809
41809
|
// src/compliance/vat-guard.ts
|
|
41810
41810
|
var ALV_REGISTERED_SALE_REFUSAL = "This company is VAT-registered (ALV). A sale booked as a journal voucher never reaches the ALV report (fields 301-303 and 309), so Kirjapro refuses it. Create the sale with kirjapro_create_invoice, deliver it with kirjapro_send_invoice and record the payment with kirjapro_record_payment or bank matching.";
|
|
41811
|
-
var
|
|
41811
|
+
var SALE_TEMPLATE_NOT_VAT_REGISTERED_REFUSAL = "NOT_VAT_REGISTERED_SALE: this company is not VAT-registered (ALV), so a sale template with VAT cannot be used. Use kirjapro_book_sale with the vatRate the receipt showed (the sale is booked gross as revenue and the result says how to correct the receipt) or the cash_sale_0 template.";
|
|
41812
|
+
var euros = (amount2) => `${amount2.toFixed(2).replace(".", ",")} \u20AC`;
|
|
41813
|
+
function saleVatNotice(gross, vatRate, vat2, preview) {
|
|
41814
|
+
return `Yritys ei ole ALV-rekisteriss\xE4, joten se ei peri arvonlis\xE4veroa. Myynti ${preview ? "kirjataan" : "kirjattiin"} kokonaan myyntituloksi (${euros(gross)}) ilman ALV-osuutta. Jos asiakkaalle annetussa kuitissa tai laskussa n\xE4kyi arvonlis\xE4vero (${vatRate.replace(".", ",")} %, ${euros(vat2)}), kuitti on virheellinen: anna asiakkaalle alkuper\xE4isen tilalle korjattu kuitti ilman arvonlis\xE4veroa ja liit\xE4 korjattu kuitti tositteeksi Kirjapro-sovelluksessa.`;
|
|
41815
|
+
}
|
|
41812
41816
|
var NOT_VAT_REGISTERED_PURCHASE_REFUSAL = "This company is not VAT-registered, so it cannot deduct VAT. General-rule services from a foreign supplier can still incur full buyer VAT: use kirjapro_book_purchase with reverseCharge, eu_services/non_eu_services, deductionPercent 0 and documented vatRateBasis, or the atomic purchase form in the web app. Do not add a separate VAT row or duplicate voucher. EU goods, construction and scrap-metal registration requirements need separate assessment; do not change ordinary registration settings merely to bypass this guard. Customs collects import VAT for a buyer outside the VAT register.";
|
|
41813
41817
|
var REVERSE_CHARGE_CATEGORIES = [
|
|
41814
41818
|
"eu_goods",
|
|
@@ -42333,7 +42337,7 @@ function registerTemplateTools(server2) {
|
|
|
42333
42337
|
return toErrorContent(ALV_REGISTERED_SALE_REFUSAL);
|
|
42334
42338
|
}
|
|
42335
42339
|
if (!alvRegistered && isVatSaleTemplate(params.template)) {
|
|
42336
|
-
return toErrorContent(
|
|
42340
|
+
return toErrorContent(SALE_TEMPLATE_NOT_VAT_REGISTERED_REFUSAL);
|
|
42337
42341
|
}
|
|
42338
42342
|
}
|
|
42339
42343
|
return withIdempotency(
|
|
@@ -42452,7 +42456,7 @@ Nothing was written.`);
|
|
|
42452
42456
|
);
|
|
42453
42457
|
if (vatSaleIndexes.length > 0) {
|
|
42454
42458
|
return toErrorContent(
|
|
42455
|
-
`${
|
|
42459
|
+
`${SALE_TEMPLATE_NOT_VAT_REGISTERED_REFUSAL} Sale templates with VAT at index ${vatSaleIndexes.join(", ")}; nothing was written.`
|
|
42456
42460
|
);
|
|
42457
42461
|
}
|
|
42458
42462
|
}
|
|
@@ -43045,12 +43049,12 @@ function registerBookingTools(server2) {
|
|
|
43045
43049
|
server2.registerTool(
|
|
43046
43050
|
"kirjapro_book_sale",
|
|
43047
43051
|
{
|
|
43048
|
-
description:
|
|
43052
|
+
description: "Book a sale (myynti) of a company that is not VAT-registered: it charges no VAT, so the gross amount is revenue in full and no VAT is booked. If the receipt or invoice the company gave showed VAT, pass that vatRate: the sale is still booked gross, and the result and the dry run carry vat_notice, which you relay to the user (the receipt is replaced with a corrected one without VAT). Payment types: invoice (default, D Myyntisaamiset), cash (D bank), prepaid. A VAT-registered (ALV) company is refused: its sales reach the ALV report only as invoices (kirjapro_create_invoice + kirjapro_send_invoice).",
|
|
43049
43053
|
inputSchema: {
|
|
43050
43054
|
amount: external_exports.number().finite().positive().max(1e9).describe("EUR amount the customer pays"),
|
|
43051
43055
|
description: external_exports.string().min(1).max(500).describe('Transaction description (e.g. "Konsultointi Acme Oy, 40h \xD7 95 \u20AC")'),
|
|
43052
43056
|
date: ISO_DATE_SCHEMA.describe("Transaction date (YYYY-MM-DD)"),
|
|
43053
|
-
vatRate: external_exports.enum(["25.5", "13.5", "10", "0"]).default("0").describe('
|
|
43057
|
+
vatRate: external_exports.enum(["25.5", "13.5", "10", "0"]).default("0").describe('The VAT rate the receipt or invoice the company gave showed, if any (default "0"). No VAT is booked at any rate; a rate above 0 adds vat_notice'),
|
|
43054
43058
|
revenueAccount: external_exports.string().default(ACCOUNTS.MYYNTI_0).describe(`Revenue account number (default "${ACCOUNTS.MYYNTI_0}", the 0 % sales account invoices of a company outside the VAT register also use)`),
|
|
43055
43059
|
paymentType: external_exports.enum(["invoice", "cash", "prepaid"]).default("invoice").describe(`invoice = receivable (${ACCOUNTS.MYYNTISAAMISET}), cash/prepaid = bank payment (${ACCOUNTS.PANKKITILI})`),
|
|
43056
43060
|
paymentAccount: external_exports.string().default(ACCOUNTS.PANKKITILI).describe(`Bank account for cash/prepaid payments (default "${ACCOUNTS.PANKKITILI}")`),
|
|
@@ -43065,9 +43069,10 @@ function registerBookingTools(server2) {
|
|
|
43065
43069
|
const companyVat = await readCompanyVat(getSupabase(), getCompanyId());
|
|
43066
43070
|
if ("isError" in companyVat) return companyVat;
|
|
43067
43071
|
if (companyVat.alvRegistered) return toErrorContent(ALV_REGISTERED_SALE_REFUSAL);
|
|
43068
|
-
if (params.vatRate !== "0") return toErrorContent(NOT_VAT_REGISTERED_SALE_REFUSAL);
|
|
43069
43072
|
const gross = roundCents(params.amount);
|
|
43070
43073
|
if (gross <= 0) return toErrorContent("Myynnin summan on oltava v\xE4hint\xE4\xE4n yksi sentti.");
|
|
43074
|
+
const receiptVatRate = params.vatRate === "0" ? null : params.vatRate;
|
|
43075
|
+
const vatNotice = (preview) => saleVatNotice(gross, params.vatRate, splitVat(gross, Number(params.vatRate)).vat, preview);
|
|
43071
43076
|
const debitAccount = params.paymentType === "invoice" ? ACCOUNTS.MYYNTISAAMISET : params.paymentAccount;
|
|
43072
43077
|
const entries = [
|
|
43073
43078
|
{ accountNumber: debitAccount, debitAmount: gross, creditAmount: 0 },
|
|
@@ -43082,13 +43087,14 @@ function registerBookingTools(server2) {
|
|
|
43082
43087
|
gross,
|
|
43083
43088
|
net,
|
|
43084
43089
|
vat: vat2,
|
|
43085
|
-
vat_rate:
|
|
43090
|
+
vat_rate: "0 %",
|
|
43086
43091
|
payment_type: params.paymentType,
|
|
43087
43092
|
debit_account: tagAccountRef(debitAccount),
|
|
43088
43093
|
revenue_account: tagAccountRef(params.revenueAccount),
|
|
43089
43094
|
date: params.date,
|
|
43090
43095
|
entries: echoEntries(entries),
|
|
43091
|
-
...saleAccountWarning && { account_warning: saleAccountWarning }
|
|
43096
|
+
...saleAccountWarning && { account_warning: saleAccountWarning },
|
|
43097
|
+
...receiptVatRate && { vat_notice: vatNotice(true) }
|
|
43092
43098
|
});
|
|
43093
43099
|
}
|
|
43094
43100
|
return withIdempotency(
|
|
@@ -43112,12 +43118,13 @@ function registerBookingTools(server2) {
|
|
|
43112
43118
|
gross,
|
|
43113
43119
|
net,
|
|
43114
43120
|
vat: vat2,
|
|
43115
|
-
vat_rate:
|
|
43121
|
+
vat_rate: "0 %",
|
|
43116
43122
|
payment_type: params.paymentType,
|
|
43117
43123
|
debit_account: tagAccountRef(debitAccount),
|
|
43118
43124
|
revenue_account: tagAccountRef(params.revenueAccount),
|
|
43119
43125
|
entries: echoEntries(entries),
|
|
43120
|
-
...saleAccountWarning && { warning: saleAccountWarning }
|
|
43126
|
+
...saleAccountWarning && { warning: saleAccountWarning },
|
|
43127
|
+
...receiptVatRate && { vat_notice: vatNotice(false) }
|
|
43121
43128
|
});
|
|
43122
43129
|
}
|
|
43123
43130
|
);
|
|
@@ -45523,7 +45530,7 @@ var INSTRUCTIONS_FULL_ADDENDUM = `
|
|
|
45523
45530
|
|
|
45524
45531
|
### Booking Shortcuts
|
|
45525
45532
|
Faster than composing journal entries via \`kirjapro_create_transaction\`:
|
|
45526
|
-
- \`kirjapro_book_sale\` / \`kirjapro_book_purchase\` \u2014 one-
|
|
45533
|
+
- \`kirjapro_book_sale\` / \`kirjapro_book_purchase\` \u2014 one-liners. A VAT-registered (ALV) company books sales as invoices (\`kirjapro_create_invoice\` + \`kirjapro_send_invoice\`): \`kirjapro_book_sale\` is refused for it. A company outside the VAT register books its sale gross with no VAT; if its receipt showed VAT, relay the result's \`vat_notice\` to the user (the receipt is replaced with a corrected one). Purchases use \`kirjapro_book_purchase\` with source \`vatRateBasis\` and a documented deduction share; reverse charge records the full buyer tax, including when deduction is zero. Import means customs-tax assessment only on the complete customs base, with no duplicate supplier purchase/payment
|
|
45527
45534
|
- \`kirjapro_book_vat_settlement\` \u2014 settles the company's VAT period from ALV-saamiset/ALV-velka. Call \`kirjapro_get_alv_summary\` for the period first to preview the net and its reconciliation.
|
|
45528
45535
|
- **Payroll is intentionally NOT exposed.** Direct users to Palkkaus.fi / Palkka.fi for salary calculation; the payslip can then be booked manually via \`kirjapro_create_transaction\`.
|
|
45529
45536
|
- \`kirjapro_list_templates\` \u2192 \`kirjapro_create_from_template\` for common patterns (built-in templates; the sale templates are hidden and refused for a VAT-registered company)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kirjapro/mcp-server",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "MCP server for Finnish accounting — exposes Kirjapro bookkeeping, invoicing, and reporting tools to Claude, ChatGPT, Mistral, and other MCP clients.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/server.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@kirjapro/mcp-server",
|
|
3
3
|
"displayName": "Kirjapro - Finnish Accounting",
|
|
4
4
|
"description": "Finnish double-entry bookkeeping, invoicing, and financial reporting for growing businesses. Create transactions, generate invoices with VAT calculation, produce income statements and balance sheets, and validate Finnish business identifiers.",
|
|
5
|
-
"version": "0.18.
|
|
5
|
+
"version": "0.18.1",
|
|
6
6
|
"homepage": "https://kirjapro.fi",
|
|
7
7
|
"repository": "https://github.com/Jaollo/kirja-pro",
|
|
8
8
|
"license": "MIT",
|