e-arveldaja-mcp 0.2.0 → 0.3.0
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/.claude/commands/book-invoice.md +17 -1
- package/README.md +8 -0
- package/dist/annotations.d.ts +43 -0
- package/dist/annotations.js +14 -0
- package/dist/api/base-resource.d.ts +1 -2
- package/dist/api/base-resource.js +5 -3
- package/dist/api/clients.api.js +1 -1
- package/dist/api/journals.api.d.ts +1 -0
- package/dist/api/journals.api.js +5 -1
- package/dist/api/products.api.js +1 -1
- package/dist/api/purchase-invoices.api.js +8 -8
- package/dist/api/sale-invoices.api.js +1 -1
- package/dist/api/transactions.api.js +1 -1
- package/dist/file-validation.js +14 -6
- package/dist/index.js +61 -48
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +9 -0
- package/dist/money.d.ts +2 -0
- package/dist/money.js +2 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +456 -0
- package/dist/resources/dynamic-resources.d.ts +3 -0
- package/dist/resources/dynamic-resources.js +63 -0
- package/dist/tool-error.d.ts +2 -0
- package/dist/tool-error.js +7 -0
- package/dist/tools/account-balance.js +30 -23
- package/dist/tools/aging-analysis.js +8 -6
- package/dist/tools/bank-reconciliation.js +6 -6
- package/dist/tools/crud-tools.d.ts +2 -0
- package/dist/tools/crud-tools.js +64 -58
- package/dist/tools/document-audit.js +3 -2
- package/dist/tools/estonian-tax.js +17 -15
- package/dist/tools/financial-statements.js +26 -24
- package/dist/tools/lightyear-investments.js +29 -27
- package/dist/tools/pdf-workflow.js +13 -23
- package/dist/tools/purchase-vat-defaults.js +4 -3
- package/dist/tools/recurring-invoices.js +3 -1
- package/dist/tools/wise-import.js +4 -3
- package/package.json +1 -1
- package/workflows/book-invoice.md +17 -1
|
@@ -71,6 +71,21 @@ If no past invoices exist, call `list_purchase_articles` and choose the most app
|
|
|
71
71
|
- 49 (Consultation/Konsultatsioon, acct 5340)
|
|
72
72
|
- 62 (Other operating/Muud tegevuskulud, acct 5990)
|
|
73
73
|
|
|
74
|
+
### Step 5b: Determine reverse charge VAT (pöördkäibemaks)
|
|
75
|
+
|
|
76
|
+
ALWAYS check if reverse charge applies. Set `reversed_vat_id: 1` on items when:
|
|
77
|
+
- Supplier is **outside Estonia** (EU or non-EU) AND provides services
|
|
78
|
+
- Invoice mentions "reverse charge", "Article 196", "pöördkäibemaks", or has 0% VAT with a foreign supplier
|
|
79
|
+
- Supplier country is NOT Estonia (check cl_code_country, VAT number prefix, or address)
|
|
80
|
+
|
|
81
|
+
When reverse charge applies:
|
|
82
|
+
- `vat_rate_dropdown`: "0"
|
|
83
|
+
- `reversed_vat_id`: 1
|
|
84
|
+
|
|
85
|
+
When supplier is Estonian with regular VAT:
|
|
86
|
+
- `vat_rate_dropdown`: the VAT rate (e.g. "24")
|
|
87
|
+
- `reversed_vat_id`: null (don't set)
|
|
88
|
+
|
|
74
89
|
### Step 6: Create the purchase invoice
|
|
75
90
|
|
|
76
91
|
Call `create_purchase_invoice_from_pdf`:
|
|
@@ -84,7 +99,8 @@ Call `create_purchase_invoice_from_pdf`:
|
|
|
84
99
|
- cl_purchase_articles_id: from step 5
|
|
85
100
|
- purchase_accounts_id: from step 5
|
|
86
101
|
- total_net_price: net amount
|
|
87
|
-
- vat_rate_dropdown: VAT rate as string (e.g. "24")
|
|
102
|
+
- vat_rate_dropdown: VAT rate as string (e.g. "24", or "0" for reverse charge)
|
|
103
|
+
- reversed_vat_id: 1 if reverse charge applies (see step 5b)
|
|
88
104
|
- amount: quantity
|
|
89
105
|
- vat_price: EXACT total VAT from the original invoice
|
|
90
106
|
- gross_price: EXACT total gross from the original invoice
|
package/README.md
CHANGED
|
@@ -138,6 +138,14 @@ Download your Lightyear account statement CSV and capital gains report, then:
|
|
|
138
138
|
|
|
139
139
|
The assistant will parse the trades, pair foreign currency conversions, calculate capital gains from the FIFO report, and create journal entries with the correct securities accounts.
|
|
140
140
|
|
|
141
|
+
### Import Wise bank transactions
|
|
142
|
+
|
|
143
|
+
Download your Wise transaction history CSV (Account → Statements → CSV), then:
|
|
144
|
+
|
|
145
|
+
> "Import my Wise transactions from transaction-history.csv into e-arveldaja"
|
|
146
|
+
|
|
147
|
+
The assistant will parse the CSV, create bank transactions with correct amounts, and separate Wise fees into their own entries for proper expense accounting. Supports EUR and foreign currency card payments (USD etc.).
|
|
148
|
+
|
|
141
149
|
### Generate financial reports
|
|
142
150
|
|
|
143
151
|
> "Generate a P&L and balance sheet as of 28.02.2026"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** MCP tool annotation presets for e-arveldaja tools. */
|
|
2
|
+
/** Read-only data retrieval — safe to auto-approve. */
|
|
3
|
+
export declare const readOnly: {
|
|
4
|
+
readonly readOnlyHint: true;
|
|
5
|
+
readonly destructiveHint: false;
|
|
6
|
+
readonly idempotentHint: true;
|
|
7
|
+
readonly openWorldHint: true;
|
|
8
|
+
};
|
|
9
|
+
/** Creates a new record (draft). Not destructive but not idempotent. */
|
|
10
|
+
export declare const create: {
|
|
11
|
+
readonly readOnlyHint: false;
|
|
12
|
+
readonly destructiveHint: false;
|
|
13
|
+
readonly idempotentHint: false;
|
|
14
|
+
readonly openWorldHint: true;
|
|
15
|
+
};
|
|
16
|
+
/** Updates an existing record. Reversible. */
|
|
17
|
+
export declare const mutate: {
|
|
18
|
+
readonly readOnlyHint: false;
|
|
19
|
+
readonly destructiveHint: false;
|
|
20
|
+
readonly idempotentHint: true;
|
|
21
|
+
readonly openWorldHint: true;
|
|
22
|
+
};
|
|
23
|
+
/** Irreversible action: confirm, delete. Requires user confirmation. */
|
|
24
|
+
export declare const destructive: {
|
|
25
|
+
readonly readOnlyHint: false;
|
|
26
|
+
readonly destructiveHint: true;
|
|
27
|
+
readonly idempotentHint: true;
|
|
28
|
+
readonly openWorldHint: true;
|
|
29
|
+
};
|
|
30
|
+
/** Sends data externally (email, e-invoice). Irreversible and not idempotent. */
|
|
31
|
+
export declare const send: {
|
|
32
|
+
readonly readOnlyHint: false;
|
|
33
|
+
readonly destructiveHint: true;
|
|
34
|
+
readonly idempotentHint: false;
|
|
35
|
+
readonly openWorldHint: true;
|
|
36
|
+
};
|
|
37
|
+
/** Batch operation that modifies multiple records. Not idempotent. */
|
|
38
|
+
export declare const batch: {
|
|
39
|
+
readonly readOnlyHint: false;
|
|
40
|
+
readonly destructiveHint: true;
|
|
41
|
+
readonly idempotentHint: false;
|
|
42
|
+
readonly openWorldHint: true;
|
|
43
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** MCP tool annotation presets for e-arveldaja tools. */
|
|
2
|
+
const base = { openWorldHint: true };
|
|
3
|
+
/** Read-only data retrieval — safe to auto-approve. */
|
|
4
|
+
export const readOnly = { ...base, readOnlyHint: true, destructiveHint: false, idempotentHint: true };
|
|
5
|
+
/** Creates a new record (draft). Not destructive but not idempotent. */
|
|
6
|
+
export const create = { ...base, readOnlyHint: false, destructiveHint: false, idempotentHint: false };
|
|
7
|
+
/** Updates an existing record. Reversible. */
|
|
8
|
+
export const mutate = { ...base, readOnlyHint: false, destructiveHint: false, idempotentHint: true };
|
|
9
|
+
/** Irreversible action: confirm, delete. Requires user confirmation. */
|
|
10
|
+
export const destructive = { ...base, readOnlyHint: false, destructiveHint: true, idempotentHint: true };
|
|
11
|
+
/** Sends data externally (email, e-invoice). Irreversible and not idempotent. */
|
|
12
|
+
export const send = { ...base, readOnlyHint: false, destructiveHint: true, idempotentHint: false };
|
|
13
|
+
/** Batch operation that modifies multiple records. Not idempotent. */
|
|
14
|
+
export const batch = { ...base, readOnlyHint: false, destructiveHint: true, idempotentHint: false };
|
|
@@ -9,8 +9,7 @@ export interface ListParams {
|
|
|
9
9
|
export declare class BaseResource<T> {
|
|
10
10
|
protected client: HttpClient;
|
|
11
11
|
protected basePath: string;
|
|
12
|
-
|
|
13
|
-
constructor(client: HttpClient, basePath: string, idParam: string);
|
|
12
|
+
constructor(client: HttpClient, basePath: string);
|
|
14
13
|
protected cacheKey(key: string): string;
|
|
15
14
|
protected invalidateCache(pattern?: string): void;
|
|
16
15
|
list(params?: ListParams): Promise<PaginatedResponse<T>>;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { Cache } from "../cache.js";
|
|
2
|
+
import { log } from "../logger.js";
|
|
2
3
|
export const cache = new Cache(300);
|
|
3
4
|
export class BaseResource {
|
|
4
5
|
client;
|
|
5
6
|
basePath;
|
|
6
|
-
|
|
7
|
-
constructor(client, basePath, idParam) {
|
|
7
|
+
constructor(client, basePath) {
|
|
8
8
|
this.client = client;
|
|
9
9
|
this.basePath = basePath;
|
|
10
|
-
this.idParam = idParam;
|
|
11
10
|
}
|
|
12
11
|
cacheKey(key) {
|
|
13
12
|
return `${this.client.cacheNamespace}:${key}`;
|
|
@@ -36,6 +35,9 @@ export class BaseResource {
|
|
|
36
35
|
const response = await this.list({ ...params, page });
|
|
37
36
|
allItems.push(...response.items);
|
|
38
37
|
totalPages = response.total_pages;
|
|
38
|
+
if (totalPages > 1 && page === 1) {
|
|
39
|
+
log("info", `${this.basePath}: fetching ${totalPages} pages...`);
|
|
40
|
+
}
|
|
39
41
|
page++;
|
|
40
42
|
} while (page <= totalPages);
|
|
41
43
|
return allItems;
|
package/dist/api/clients.api.js
CHANGED
|
@@ -10,6 +10,7 @@ export declare class JournalsApi extends BaseResource<Journal> {
|
|
|
10
10
|
*/
|
|
11
11
|
listAllWithPostings(): Promise<Journal[]>;
|
|
12
12
|
confirm(id: number): Promise<ApiResponse>;
|
|
13
|
+
invalidate(id: number): Promise<ApiResponse>;
|
|
13
14
|
getDocument(id: number): Promise<ApiFile>;
|
|
14
15
|
uploadDocument(id: number, name: string, contents: string): Promise<ApiResponse>;
|
|
15
16
|
deleteDocument(id: number): Promise<ApiResponse>;
|
package/dist/api/journals.api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseResource, cache } from "./base-resource.js";
|
|
2
2
|
export class JournalsApi extends BaseResource {
|
|
3
3
|
constructor(client) {
|
|
4
|
-
super(client, "/journals"
|
|
4
|
+
super(client, "/journals");
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Load all journals with postings guaranteed to be populated.
|
|
@@ -38,6 +38,10 @@ export class JournalsApi extends BaseResource {
|
|
|
38
38
|
this.invalidateCache();
|
|
39
39
|
return this.client.patch(`/journals/${id}/register`, {});
|
|
40
40
|
}
|
|
41
|
+
async invalidate(id) {
|
|
42
|
+
this.invalidateCache();
|
|
43
|
+
return this.client.patch(`/journals/${id}/invalidate`, {});
|
|
44
|
+
}
|
|
41
45
|
async getDocument(id) {
|
|
42
46
|
return this.client.get(`/journals/${id}/document_user`);
|
|
43
47
|
}
|
package/dist/api/products.api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseResource } from "./base-resource.js";
|
|
2
|
-
|
|
2
|
+
import { roundMoney } from "../money.js";
|
|
3
3
|
/**
|
|
4
4
|
* For non-VAT (mitte-KMD) companies: set project_no_vat_gross_price on items
|
|
5
5
|
* so the API computes item-level vat_amount for informational tracking.
|
|
@@ -31,7 +31,7 @@ function normalizeItemsForNonVat(items, isVatRegistered, grossPrice) {
|
|
|
31
31
|
}
|
|
32
32
|
export class PurchaseInvoicesApi extends BaseResource {
|
|
33
33
|
constructor(client) {
|
|
34
|
-
super(client, "/purchase_invoices"
|
|
34
|
+
super(client, "/purchase_invoices");
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Create a purchase invoice and set invoice-level totals.
|
|
@@ -55,8 +55,8 @@ export class PurchaseInvoicesApi extends BaseResource {
|
|
|
55
55
|
// Read back to get item-level VAT computed by API
|
|
56
56
|
const invoice = await this.get(id);
|
|
57
57
|
const items = invoice.items;
|
|
58
|
-
const itemVat = items ?
|
|
59
|
-
const itemNet = items ?
|
|
58
|
+
const itemVat = items ? roundMoney(items.reduce((s, i) => s + (i.vat_amount ?? 0), 0)) : 0;
|
|
59
|
+
const itemNet = items ? roundMoney(items.reduce((s, i) => s + (i.total_net_price ?? 0), 0)) : 0;
|
|
60
60
|
// Invoice-level VAT: explicit value wins for VAT-registered companies.
|
|
61
61
|
// Non-KMD companies must keep invoice-level vat_price at 0 even if item VAT is tracked.
|
|
62
62
|
const vat = isVatRegistered
|
|
@@ -65,7 +65,7 @@ export class PurchaseInvoicesApi extends BaseResource {
|
|
|
65
65
|
// Invoice-level gross: explicit value wins, otherwise net + actual item VAT
|
|
66
66
|
const gross = grossPrice !== undefined
|
|
67
67
|
? grossPrice
|
|
68
|
-
:
|
|
68
|
+
: roundMoney(itemNet + itemVat);
|
|
69
69
|
if (vat > 0 || gross > 0) {
|
|
70
70
|
await this.update(id, { vat_price: vat, gross_price: gross, items: invoice.items });
|
|
71
71
|
this.invalidateCache();
|
|
@@ -80,10 +80,10 @@ export class PurchaseInvoicesApi extends BaseResource {
|
|
|
80
80
|
const invoice = await this.get(id);
|
|
81
81
|
const items = invoice.items;
|
|
82
82
|
if (items) {
|
|
83
|
-
const itemVat =
|
|
84
|
-
const net =
|
|
83
|
+
const itemVat = roundMoney(items.reduce((s, i) => s + (i.vat_amount ?? 0), 0));
|
|
84
|
+
const net = roundMoney(items.reduce((s, i) => s + (i.total_net_price ?? 0), 0));
|
|
85
85
|
const vat = isVatRegistered ? itemVat : 0;
|
|
86
|
-
const gross =
|
|
86
|
+
const gross = roundMoney(net + itemVat);
|
|
87
87
|
const currentGross = invoice.gross_price;
|
|
88
88
|
const shouldRepair = !currentGross || Math.abs(currentGross - gross) > 0.02;
|
|
89
89
|
if (shouldRepair) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseResource } from "./base-resource.js";
|
|
2
2
|
export class SaleInvoicesApi extends BaseResource {
|
|
3
3
|
constructor(client) {
|
|
4
|
-
super(client, "/sale_invoices"
|
|
4
|
+
super(client, "/sale_invoices");
|
|
5
5
|
}
|
|
6
6
|
async confirm(id) {
|
|
7
7
|
this.invalidateCache();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseResource } from "./base-resource.js";
|
|
2
2
|
export class TransactionsApi extends BaseResource {
|
|
3
3
|
constructor(client) {
|
|
4
|
-
super(client, "/transactions"
|
|
4
|
+
super(client, "/transactions");
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Confirm a transaction with distribution rows.
|
package/dist/file-validation.js
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { stat, realpath } from "fs/promises";
|
|
2
2
|
import { resolve, extname, isAbsolute } from "path";
|
|
3
|
-
import { existsSync } from "fs";
|
|
3
|
+
import { existsSync, realpathSync } from "fs";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
/**
|
|
6
6
|
* Allowed root directories for file reads. Configurable via EARVELDAJA_ALLOWED_PATHS
|
|
7
7
|
* (colon-separated list). Defaults to $HOME and /tmp.
|
|
8
|
+
* Roots are resolved through symlinks so that the check works even if
|
|
9
|
+
* e.g. /tmp is a symlink to /private/tmp (macOS).
|
|
8
10
|
*/
|
|
9
11
|
function getAllowedRoots() {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const raw = process.env.EARVELDAJA_ALLOWED_PATHS
|
|
13
|
+
? process.env.EARVELDAJA_ALLOWED_PATHS.split(":").map(p => resolve(p))
|
|
14
|
+
: [homedir(), "/tmp"];
|
|
15
|
+
return raw.map(root => {
|
|
16
|
+
try {
|
|
17
|
+
return realpathSync(root);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return root;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
15
23
|
}
|
|
16
24
|
/**
|
|
17
25
|
* Get the project root (directory containing package.json).
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,11 @@ import { registerDocumentAuditTools } from "./tools/document-audit.js";
|
|
|
25
25
|
import { registerLightyearTools } from "./tools/lightyear-investments.js";
|
|
26
26
|
import { registerWiseImportTools } from "./tools/wise-import.js";
|
|
27
27
|
import { registerResources } from "./resources/static-resources.js";
|
|
28
|
+
import { registerDynamicResources } from "./resources/dynamic-resources.js";
|
|
29
|
+
import { registerPrompts } from "./prompts.js";
|
|
30
|
+
import { toolError } from "./tool-error.js";
|
|
31
|
+
import { setLogger } from "./logger.js";
|
|
32
|
+
import { readOnly, mutate } from "./annotations.js";
|
|
28
33
|
function buildApiContext(httpClient) {
|
|
29
34
|
return {
|
|
30
35
|
clients: new ClientsApi(httpClient),
|
|
@@ -87,7 +92,7 @@ async function main() {
|
|
|
87
92
|
const api = createScopedApiContext(connectionState, connectionContexts, invocationStorage);
|
|
88
93
|
const server = new McpServer({
|
|
89
94
|
name: "e-arveldaja",
|
|
90
|
-
version: "
|
|
95
|
+
version: "0.3.0",
|
|
91
96
|
description: "EXPERIMENTAL, UNOFFICIAL MCP server for the Estonian e-arveldaja (e-Financials) API. " +
|
|
92
97
|
"NOT affiliated with or endorsed by RIK. Use entirely at your own risk — " +
|
|
93
98
|
"this software interacts with live financial data and can create, modify, and delete accounting records. " +
|
|
@@ -98,7 +103,7 @@ async function main() {
|
|
|
98
103
|
});
|
|
99
104
|
// --- Multi-account tools ---
|
|
100
105
|
server.tool("list_connections", "List all available e-arveldaja connections (API key files). " +
|
|
101
|
-
"Shows which connection is currently active.", {}, async () => {
|
|
106
|
+
"Shows which connection is currently active.", {}, readOnly, async () => {
|
|
102
107
|
const connections = allConfigs.map((nc, i) => ({
|
|
103
108
|
index: i,
|
|
104
109
|
name: nc.name,
|
|
@@ -121,7 +126,7 @@ async function main() {
|
|
|
121
126
|
"Clears cached data atomically. Use list_connections to see available indices. " +
|
|
122
127
|
"In-flight tool calls will fail fast and should be retried on the intended connection.", {
|
|
123
128
|
index: z.number().describe("Connection index from list_connections"),
|
|
124
|
-
}, async ({ index }) => {
|
|
129
|
+
}, mutate, async ({ index }) => {
|
|
125
130
|
if (index < 0 || index >= allConfigs.length) {
|
|
126
131
|
return {
|
|
127
132
|
content: [{
|
|
@@ -160,60 +165,68 @@ async function main() {
|
|
|
160
165
|
}],
|
|
161
166
|
};
|
|
162
167
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return async (...handlerArgs) => {
|
|
168
|
+
// Wrap server.tool to pin each handler to a connection snapshot via AsyncLocalStorage.
|
|
169
|
+
// The wrapper captures the active connection at invocation time, runs the handler
|
|
170
|
+
// inside that snapshot, and asserts the connection hasn't changed on return.
|
|
171
|
+
function wrapHandler(handler) {
|
|
172
|
+
return (async (...args) => {
|
|
169
173
|
const snapshot = captureSnapshot(connectionState);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
174
|
+
try {
|
|
175
|
+
return await invocationStorage.run(snapshot, async () => {
|
|
176
|
+
const result = await handler(...args);
|
|
177
|
+
assertSnapshotCurrent(connectionState, snapshot);
|
|
178
|
+
return result;
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
return toolError(error);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
// Create a proxy that intercepts server.tool() calls and wraps the last function argument.
|
|
187
|
+
// This is forward-compatible with any overload signature the SDK may add.
|
|
188
|
+
const scopedServer = new Proxy(server, {
|
|
189
|
+
get(target, prop, receiver) {
|
|
190
|
+
if (prop !== "tool")
|
|
191
|
+
return Reflect.get(target, prop, receiver);
|
|
192
|
+
return (...toolArgs) => {
|
|
193
|
+
// The handler is always the last argument and always a function
|
|
194
|
+
const lastIdx = toolArgs.length - 1;
|
|
195
|
+
if (lastIdx >= 0 && typeof toolArgs[lastIdx] === "function") {
|
|
196
|
+
toolArgs[lastIdx] = wrapHandler(toolArgs[lastIdx]);
|
|
197
|
+
}
|
|
198
|
+
return target.tool(...toolArgs);
|
|
199
|
+
};
|
|
200
|
+
},
|
|
195
201
|
});
|
|
196
|
-
// Register all tools
|
|
197
|
-
registerCrudTools(
|
|
198
|
-
registerAccountBalanceTools(
|
|
199
|
-
registerPdfWorkflowTools(
|
|
200
|
-
registerBankReconciliationTools(
|
|
201
|
-
registerFinancialStatementTools(
|
|
202
|
-
registerAgingTools(
|
|
203
|
-
registerRecurringInvoiceTools(
|
|
204
|
-
registerEstonianTaxTools(
|
|
205
|
-
registerDocumentAuditTools(
|
|
206
|
-
registerLightyearTools(
|
|
207
|
-
registerWiseImportTools(
|
|
202
|
+
// Register all tools (via scopedServer so handlers get connection-pinned)
|
|
203
|
+
registerCrudTools(scopedServer, api);
|
|
204
|
+
registerAccountBalanceTools(scopedServer, api);
|
|
205
|
+
registerPdfWorkflowTools(scopedServer, api);
|
|
206
|
+
registerBankReconciliationTools(scopedServer, api);
|
|
207
|
+
registerFinancialStatementTools(scopedServer, api);
|
|
208
|
+
registerAgingTools(scopedServer, api);
|
|
209
|
+
registerRecurringInvoiceTools(scopedServer, api);
|
|
210
|
+
registerEstonianTaxTools(scopedServer, api);
|
|
211
|
+
registerDocumentAuditTools(scopedServer, api);
|
|
212
|
+
registerLightyearTools(scopedServer, api);
|
|
213
|
+
registerWiseImportTools(scopedServer, api);
|
|
208
214
|
// Register resources
|
|
209
215
|
registerResources(server, api);
|
|
216
|
+
registerDynamicResources(server, api);
|
|
217
|
+
// Register prompts
|
|
218
|
+
registerPrompts(server);
|
|
210
219
|
// Start server
|
|
211
220
|
const transport = new StdioServerTransport();
|
|
212
221
|
await server.connect(transport);
|
|
222
|
+
// Route log output through MCP logging protocol
|
|
223
|
+
setLogger((level, message) => {
|
|
224
|
+
server.sendLoggingMessage({ level, data: message });
|
|
225
|
+
});
|
|
213
226
|
const names = allConfigs.map(c => c.name).join(", ");
|
|
214
|
-
|
|
227
|
+
process.stderr.write(`e-arveldaja MCP server started (${allConfigs.length} connection(s): ${names})\n`);
|
|
215
228
|
}
|
|
216
229
|
main().catch((err) => {
|
|
217
|
-
|
|
230
|
+
process.stderr.write(`Fatal error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
218
231
|
process.exit(1);
|
|
219
232
|
});
|
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
package/dist/money.d.ts
ADDED
package/dist/money.js
ADDED