kassza 0.11.0 → 0.13.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.
Files changed (132) hide show
  1. package/README.md +376 -111
  2. package/agents/README.md +20 -5
  3. package/agents/api.md +165 -2
  4. package/agents/pitfalls.md +16 -3
  5. package/agents/recipes.md +215 -45
  6. package/agents/skills/kassza/SKILL.md +11 -8
  7. package/dist/cli.cjs +552 -0
  8. package/dist/cli.d.cts +1 -0
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.js +552 -0
  11. package/dist/client-6MkeuFqD.d.ts +268 -0
  12. package/dist/client-B5FryKxJ.d.cts +268 -0
  13. package/dist/client-C-PdfL_P.cjs +1275 -0
  14. package/dist/client-CfaS1-Jx.js +1228 -0
  15. package/dist/context-BxQlIlug.d.ts +425 -0
  16. package/dist/context-DXNbTPwz.d.cts +425 -0
  17. package/dist/create-once-Cz621l8r.js +330 -0
  18. package/dist/create-once-DgMtKKcG.cjs +395 -0
  19. package/dist/crypto-Dpn4FHQ6.cjs +65 -0
  20. package/dist/crypto-usDg8L2K.js +36 -0
  21. package/dist/data-link/index.cjs +232 -0
  22. package/dist/data-link/index.d.cts +79 -0
  23. package/dist/data-link/index.d.ts +79 -0
  24. package/dist/data-link/index.js +224 -0
  25. package/dist/{dates-DtHzwNU6.d.cts → dates-9zvESP0i.d.cts} +2 -1
  26. package/dist/{dates-DtHzwNU6.d.ts → dates-9zvESP0i.d.ts} +2 -1
  27. package/dist/{dates-PPxH0n5H.cjs → dates-CPgBodkP.cjs} +44 -1
  28. package/dist/{dates-D2XebOIg.js → dates-CXyj7Azy.js} +39 -2
  29. package/dist/delegation/index.cjs +396 -0
  30. package/dist/delegation/index.d.cts +100 -0
  31. package/dist/delegation/index.d.ts +100 -0
  32. package/dist/delegation/index.js +378 -0
  33. package/dist/{errors-DapdV5DK.js → errors-DLrb0g64.js} +122 -5
  34. package/dist/{errors-B0QJhUW1.cjs → errors-DxeuTslP.cjs} +127 -4
  35. package/dist/get-Byc9T5WO.d.cts +151 -0
  36. package/dist/get-Byc9T5WO.d.ts +151 -0
  37. package/dist/get-Csm2n0rZ.cjs +445 -0
  38. package/dist/get-DT3JEgQ6.js +380 -0
  39. package/dist/index.cjs +21 -1410
  40. package/dist/index.d.cts +20 -3
  41. package/dist/index.d.ts +20 -3
  42. package/dist/index.js +8 -1409
  43. package/dist/ipn/index.cjs +1 -1
  44. package/dist/ipn/index.js +1 -1
  45. package/dist/issue-AGRohSm7.cjs +914 -0
  46. package/dist/issue-DtSLpVdJ.js +777 -0
  47. package/dist/json-4y4E2xxS.cjs +61 -0
  48. package/dist/json-B70TwoX1.d.cts +4 -0
  49. package/dist/json-B70TwoX1.d.ts +4 -0
  50. package/dist/json-DjnqnaJK.js +32 -0
  51. package/dist/mcp/index.cjs +10 -0
  52. package/dist/mcp/index.d.cts +71 -0
  53. package/dist/mcp/index.d.ts +71 -0
  54. package/dist/mcp/index.js +2 -0
  55. package/dist/money/index.cjs +12 -10
  56. package/dist/money/index.js +3 -1
  57. package/dist/{money-DkiGukAw.cjs → money-BxytJW6f.cjs} +42 -177
  58. package/dist/{money-C9j7nBNP.js → money-t7uy1n91.js} +29 -110
  59. package/dist/nav/index.cjs +1046 -0
  60. package/dist/nav/index.d.cts +247 -0
  61. package/dist/nav/index.d.ts +247 -0
  62. package/dist/nav/index.js +1012 -0
  63. package/dist/nav-BEwcX7-N.cjs +203 -0
  64. package/dist/nav-CK1WgYo7.js +156 -0
  65. package/dist/parse-BJj-aqKy.cjs +380 -0
  66. package/dist/parse-C608ehqM.js +291 -0
  67. package/dist/payments/barion.cjs +208 -0
  68. package/dist/payments/barion.d.cts +28 -0
  69. package/dist/payments/barion.d.ts +28 -0
  70. package/dist/payments/barion.js +199 -0
  71. package/dist/payments/index.cjs +16 -0
  72. package/dist/payments/index.d.cts +31 -0
  73. package/dist/payments/index.d.ts +31 -0
  74. package/dist/payments/index.js +3 -0
  75. package/dist/payments/paypal.cjs +351 -0
  76. package/dist/payments/paypal.d.cts +59 -0
  77. package/dist/payments/paypal.d.ts +59 -0
  78. package/dist/payments/paypal.js +337 -0
  79. package/dist/payments/revolut.cjs +261 -0
  80. package/dist/payments/revolut.d.cts +48 -0
  81. package/dist/payments/revolut.d.ts +48 -0
  82. package/dist/payments/revolut.js +249 -0
  83. package/dist/payments/simplepay.cjs +313 -0
  84. package/dist/payments/simplepay.d.cts +86 -0
  85. package/dist/payments/simplepay.d.ts +86 -0
  86. package/dist/payments/simplepay.js +299 -0
  87. package/dist/payments/stripe.cjs +315 -0
  88. package/dist/payments/stripe.d.cts +49 -0
  89. package/dist/payments/stripe.d.ts +49 -0
  90. package/dist/payments/stripe.js +303 -0
  91. package/dist/reports/index.cjs +103 -0
  92. package/dist/reports/index.d.cts +70 -0
  93. package/dist/reports/index.d.ts +70 -0
  94. package/dist/reports/index.js +94 -0
  95. package/dist/request-body-CH6ZGOrq.cjs +34 -0
  96. package/dist/request-body-uZHMRlQr.js +29 -0
  97. package/dist/rounding-BLyHjjI5.js +20 -0
  98. package/dist/rounding-TxoWy2ww.cjs +37 -0
  99. package/dist/serialize-BXOww1Uq.cjs +286 -0
  100. package/dist/serialize-DSE_o9RK.js +215 -0
  101. package/dist/server-C6PoNkdD.cjs +1557 -0
  102. package/dist/server-Cd8HB661.js +1504 -0
  103. package/dist/storage/fs.cjs +1 -1
  104. package/dist/storage/fs.js +1 -1
  105. package/dist/storage/index.cjs +2 -2
  106. package/dist/storage/index.d.cts +1 -1
  107. package/dist/storage/index.d.ts +1 -1
  108. package/dist/storage/index.js +2 -2
  109. package/dist/tax-number-BYFkBp4A.cjs +141 -0
  110. package/dist/tax-number-BdqKsxNR.js +76 -0
  111. package/dist/testing/index.cjs +1656 -84
  112. package/dist/testing/index.d.cts +203 -3
  113. package/dist/testing/index.d.ts +203 -3
  114. package/dist/testing/index.js +1653 -83
  115. package/dist/types-BVeR7KyU.d.cts +56 -0
  116. package/dist/types-BVeR7KyU.d.ts +56 -0
  117. package/dist/types-DH8QoNZK.d.cts +135 -0
  118. package/dist/types-k--zHf4l.d.ts +135 -0
  119. package/dist/validators/index.cjs +14 -88
  120. package/dist/validators/index.js +1 -75
  121. package/dist/vat-g35srbNG.cjs +116 -0
  122. package/dist/vat-v_dcWCto.js +81 -0
  123. package/dist/webhook-81giRMdQ.cjs +223 -0
  124. package/dist/webhook-CpCMHhn2.d.ts +6 -0
  125. package/dist/webhook-CpMJuP6c.d.cts +6 -0
  126. package/dist/webhook-CrEGohbg.js +152 -0
  127. package/llms.txt +4 -4
  128. package/package.json +148 -2
  129. package/dist/client-B9kbKKBf.d.cts +0 -748
  130. package/dist/client-zv4enyq7.d.ts +0 -748
  131. package/dist/create-5YkUcJSe.js +0 -957
  132. package/dist/create-DZsl3Z4m.cjs +0 -1178
@@ -0,0 +1,1557 @@
1
+ const require_create_once = require("./create-once-DgMtKKcG.cjs");
2
+ const require_errors = require("./errors-DxeuTslP.cjs");
3
+ const require_client = require("./client-C-PdfL_P.cjs");
4
+ const require_dates = require("./dates-CPgBodkP.cjs");
5
+ const require_vat = require("./vat-g35srbNG.cjs");
6
+ const require_money = require("./money-BxytJW6f.cjs");
7
+ const require_issue = require("./issue-AGRohSm7.cjs");
8
+ const require_crypto = require("./crypto-Dpn4FHQ6.cjs");
9
+ const require_nav = require("./nav-BEwcX7-N.cjs");
10
+ //#region src/mcp/protocol.ts
11
+ const MCP_MODERN_VERSIONS = ["2026-07-28"];
12
+ const MCP_LEGACY_VERSIONS = [
13
+ "2025-11-25",
14
+ "2025-06-18",
15
+ "2025-03-26",
16
+ "2024-11-05"
17
+ ];
18
+ const MCP_SUPPORTED_VERSIONS = [...MCP_MODERN_VERSIONS, ...MCP_LEGACY_VERSIONS];
19
+ const META_PROTOCOL_VERSION = "io.modelcontextprotocol/protocolVersion";
20
+ const META_CLIENT_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
21
+ const META_SERVER_INFO = "io.modelcontextprotocol/serverInfo";
22
+ const JSON_RPC_PARSE_ERROR = -32700;
23
+ const JSON_RPC_INVALID_REQUEST = -32600;
24
+ const JSON_RPC_METHOD_NOT_FOUND = -32601;
25
+ const JSON_RPC_INVALID_PARAMS = -32602;
26
+ const JSON_RPC_INTERNAL_ERROR = -32603;
27
+ const MCP_UNSUPPORTED_PROTOCOL_VERSION = -32022;
28
+ var McpProtocolError = class extends Error {
29
+ name = "McpProtocolError";
30
+ code;
31
+ id;
32
+ data;
33
+ constructor(code, message, options = {}) {
34
+ super(message);
35
+ this.code = code;
36
+ this.id = options.id ?? null;
37
+ this.data = options.data;
38
+ }
39
+ };
40
+ function isJsonObject(value) {
41
+ return typeof value === "object" && value !== null && !Array.isArray(value);
42
+ }
43
+ function isValidId(value) {
44
+ return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
45
+ }
46
+ function readableId(value) {
47
+ return isValidId(value) ? value : null;
48
+ }
49
+ function failure(id, code, message, data) {
50
+ return {
51
+ jsonrpc: "2.0",
52
+ id,
53
+ error: data === void 0 ? {
54
+ code,
55
+ message
56
+ } : {
57
+ code,
58
+ message,
59
+ data
60
+ }
61
+ };
62
+ }
63
+ function success(id, result) {
64
+ return {
65
+ jsonrpc: "2.0",
66
+ id,
67
+ result
68
+ };
69
+ }
70
+ function parseMcpMessage(value) {
71
+ if (!isJsonObject(value) || value.jsonrpc !== "2.0") throw new McpProtocolError(JSON_RPC_INVALID_REQUEST, "Érvénytelen JSON-RPC 2.0 üzenet.", { id: isJsonObject(value) ? readableId(value.id) : null });
72
+ if (typeof value.method !== "string") {
73
+ if ("result" in value || "error" in value) return { kind: "ignored" };
74
+ throw new McpProtocolError(JSON_RPC_INVALID_REQUEST, "Hiányzik a method mező.", { id: readableId(value.id) });
75
+ }
76
+ if (!("id" in value)) return {
77
+ kind: "notification",
78
+ method: value.method
79
+ };
80
+ if (!isValidId(value.id)) throw new McpProtocolError(JSON_RPC_INVALID_REQUEST, "A kérés azonosítója (id) csak szöveg vagy szám lehet, null nem.");
81
+ if (value.params !== void 0 && !isJsonObject(value.params)) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, "A params mezőnek objektumnak kell lennie.", { id: value.id });
82
+ return {
83
+ kind: "request",
84
+ id: value.id,
85
+ method: value.method,
86
+ params: value.params ?? {}
87
+ };
88
+ }
89
+ function protocolFailure(error) {
90
+ return failure(error.id, error.code, error.message, error.data);
91
+ }
92
+ //#endregion
93
+ //#region src/mcp/arguments.ts
94
+ var ToolInputError = class extends Error {
95
+ name = "ToolInputError";
96
+ };
97
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
98
+ const NUMERIC_TEXT = /^-?\d+(?:[.,]\d+)?$/;
99
+ function field(path, key) {
100
+ return path === "" ? key : `${path}.${key}`;
101
+ }
102
+ function objectArg(value, path) {
103
+ if (!isJsonObject(value)) throw new ToolInputError(`A(z) ${path} mezőnek objektumnak kell lennie.`);
104
+ return value;
105
+ }
106
+ function assertKnownKeys(value, allowed, path) {
107
+ const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
108
+ if (unknown.length === 0) return;
109
+ throw new ToolInputError(`Ismeretlen mező ${path === "" ? "a bemenetben" : `a(z) ${path} objektumban`}: ${unknown.join(", ")}. Megengedett mezők: ${allowed.join(", ")}.`);
110
+ }
111
+ function optionalString(value, key, path) {
112
+ const raw = value[key];
113
+ if (raw === void 0 || raw === null) return void 0;
114
+ if (typeof raw !== "string") throw new ToolInputError(`A(z) ${field(path, key)} mezőnek szövegnek kell lennie.`);
115
+ const trimmed = raw.trim();
116
+ return trimmed === "" ? void 0 : trimmed;
117
+ }
118
+ function requiredString(value, key, path) {
119
+ const result = optionalString(value, key, path);
120
+ if (result === void 0) throw new ToolInputError(`A(z) ${field(path, key)} mező kötelező, és nem lehet üres.`);
121
+ return result;
122
+ }
123
+ function optionalNumber(value, key, path) {
124
+ const raw = value[key];
125
+ if (raw === void 0 || raw === null) return void 0;
126
+ if (typeof raw !== "number" || !Number.isFinite(raw)) throw new ToolInputError(`A(z) ${field(path, key)} mezőnek véges számnak kell lennie.`);
127
+ return raw;
128
+ }
129
+ function optionalInteger(value, key, path) {
130
+ const result = optionalNumber(value, key, path);
131
+ if (result !== void 0 && !Number.isInteger(result)) throw new ToolInputError(`A(z) ${field(path, key)} mezőnek egész számnak kell lennie.`);
132
+ return result;
133
+ }
134
+ function optionalBoolean(value, key, path) {
135
+ const raw = value[key];
136
+ if (raw === void 0 || raw === null) return void 0;
137
+ if (typeof raw !== "boolean") throw new ToolInputError(`A(z) ${field(path, key)} mezőnek true vagy false értéknek kell lennie.`);
138
+ return raw;
139
+ }
140
+ function optionalDate(value, key, path) {
141
+ const result = optionalString(value, key, path);
142
+ if (result !== void 0 && !DATE_PATTERN.test(result)) throw new ToolInputError(`A(z) ${field(path, key)} mezőt ÉÉÉÉ-HH-NN formában add meg (például 2026-10-02).`);
143
+ return result;
144
+ }
145
+ function optionalEnum(value, key, path, allowed) {
146
+ const raw = optionalString(value, key, path);
147
+ if (raw === void 0) return void 0;
148
+ const match = allowed.find((candidate) => candidate === raw);
149
+ if (match === void 0) throw new ToolInputError(`A(z) ${field(path, key)} értéke nem megengedett: ${raw}. Lehetséges értékek: ${allowed.join(", ")}.`);
150
+ return match;
151
+ }
152
+ function optionalArray(value, key, path) {
153
+ const raw = value[key];
154
+ if (raw === void 0 || raw === null) return void 0;
155
+ if (!Array.isArray(raw)) throw new ToolInputError(`A(z) ${field(path, key)} mezőnek tömbnek kell lennie.`);
156
+ return raw;
157
+ }
158
+ function requiredArray(value, key, path, limits) {
159
+ const result = optionalArray(value, key, path) ?? [];
160
+ if (result.length < limits.min || result.length > limits.max) throw new ToolInputError(`A(z) ${field(path, key)} tömbben ${limits.min} és ${limits.max} közötti számú elem lehet, kapott: ${result.length}.`);
161
+ return result;
162
+ }
163
+ function numericFromText(value) {
164
+ if (typeof value !== "string" || !NUMERIC_TEXT.test(value.trim())) return value;
165
+ return Number(value.trim().replace(",", "."));
166
+ }
167
+ function vatFailure(value, path) {
168
+ return new ToolInputError(`Ismeretlen áfakulcs a(z) ${path} mezőben: ${JSON.stringify(value)}. Add meg számként (például 27, 18, 5 vagy 0) vagy kódként (például "AAM", "TAM", "EUT", "EUKT", "F.AFA", "K.AFA").`);
169
+ }
170
+ function invoiceVat(value, path) {
171
+ const candidate = numericFromText(value);
172
+ if (require_vat.isVatRate(candidate)) return candidate;
173
+ throw vatFailure(value, path);
174
+ }
175
+ function receiptVat(value, path) {
176
+ const candidate = numericFromText(value);
177
+ if (require_vat.isVatRate(candidate)) return candidate;
178
+ const code = require_issue.RECEIPT_ONLY_VAT_CODES.find((entry) => entry === candidate);
179
+ if (code !== void 0) return code;
180
+ throw vatFailure(value, path);
181
+ }
182
+ //#endregion
183
+ //#region src/mcp/confirmation.ts
184
+ const DEFAULT_CONFIRMATION_TTL_MS = 9e5;
185
+ const SECRET_BYTES = 32;
186
+ const SIGNATURE_LENGTH = 32;
187
+ const IDEMPOTENCY_KEY_LENGTH = 20;
188
+ const TOKEN_PATTERN = /^([0-9a-z]+)\.([0-9a-f]+)$/;
189
+ function canonicalize(value) {
190
+ if (Array.isArray(value)) return value.map(canonicalize);
191
+ if (typeof value !== "object" || value === null) return value;
192
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, entry]) => [key, canonicalize(entry)]));
193
+ }
194
+ function canonicalJson(value) {
195
+ return JSON.stringify(canonicalize(value)) ?? "null";
196
+ }
197
+ async function idempotencyKey(action, day, payload) {
198
+ return (await require_crypto.digestHex("SHA-256", `${action}\n${day}\n${canonicalJson(payload)}`)).slice(0, IDEMPOTENCY_KEY_LENGTH).toUpperCase();
199
+ }
200
+ function randomSecret() {
201
+ return crypto.getRandomValues(new Uint8Array(SECRET_BYTES));
202
+ }
203
+ function resolveTtl(ttlMs) {
204
+ if (ttlMs === void 0) return DEFAULT_CONFIRMATION_TTL_MS;
205
+ if (!Number.isInteger(ttlMs) || ttlMs <= 0) throw new TypeError(`A confirmationTtlMs pozitív egész szám legyen, kapott: ${ttlMs}`);
206
+ return ttlMs;
207
+ }
208
+ function createConfirmations(options) {
209
+ const secret = options.secret ?? randomSecret();
210
+ const ttlMs = resolveTtl(options.ttlMs);
211
+ const sign = async (action, expiresAt, payload) => {
212
+ return (await require_crypto.hmacHex("SHA-256", secret, `${action}\n${expiresAt}\n${canonicalJson(payload)}`)).slice(0, SIGNATURE_LENGTH);
213
+ };
214
+ return {
215
+ async issue(action, payload) {
216
+ const expiresAt = options.now().getTime() + ttlMs;
217
+ const signature = await sign(action, expiresAt, payload);
218
+ return {
219
+ token: `${expiresAt.toString(36)}.${signature}`,
220
+ expiresAt: new Date(expiresAt).toISOString()
221
+ };
222
+ },
223
+ async verify(action, payload, token, previewTool) {
224
+ const again = `Hívd meg újra a ${previewTool} eszközt pontosan ezekkel az adatokkal, mutasd meg az előnézetet a felhasználónak, és a jóváhagyása után az új kóddal próbáld újra.`;
225
+ if (typeof token !== "string" || token.trim() === "") throw new ToolInputError(`Hiányzik a megerősítő kód (confirmation). ${again}`);
226
+ const match = TOKEN_PATTERN.exec(token.trim());
227
+ const expiresAt = match?.[1] === void 0 ? NaN : Number.parseInt(match[1], 36);
228
+ if (!match?.[2] || !Number.isSafeInteger(expiresAt)) throw new ToolInputError(`A megerősítő kód formátuma érvénytelen. ${again}`);
229
+ if (options.now().getTime() > expiresAt) throw new ToolInputError(`A megerősítő kód lejárt. ${again}`);
230
+ const expected = await sign(action, expiresAt, payload);
231
+ if (!require_crypto.timingSafeEqual(expected, match[2])) throw new ToolInputError(`A megerősítő kód nem ehhez a kéréshez tartozik (az adatok eltérnek az előnézettől). ${again}`);
232
+ }
233
+ };
234
+ }
235
+ //#endregion
236
+ //#region src/core/version.ts
237
+ const KASSZA_VERSION = "0.12.0";
238
+ //#endregion
239
+ //#region src/mcp/tool-kit.ts
240
+ const LOCAL_READ = {
241
+ readOnlyHint: true,
242
+ destructiveHint: false,
243
+ idempotentHint: true,
244
+ openWorldHint: false
245
+ };
246
+ const REMOTE_READ = {
247
+ readOnlyHint: true,
248
+ destructiveHint: false,
249
+ idempotentHint: true,
250
+ openWorldHint: true
251
+ };
252
+ const REMOTE_CREATE = {
253
+ readOnlyHint: false,
254
+ destructiveHint: false,
255
+ idempotentHint: true,
256
+ openWorldHint: true
257
+ };
258
+ const REMOTE_REVERSE = {
259
+ readOnlyHint: false,
260
+ destructiveHint: true,
261
+ idempotentHint: true,
262
+ openWorldHint: true
263
+ };
264
+ const amountFormat = new Intl.NumberFormat("hu-HU", { maximumFractionDigits: 2 });
265
+ function money(value, currency) {
266
+ return `${amountFormat.format(value)} ${currency}`;
267
+ }
268
+ function plainJson(value) {
269
+ return JSON.parse(JSON.stringify(value, (_key, entry) => entry instanceof Uint8Array ? void 0 : entry));
270
+ }
271
+ function lines(...parts) {
272
+ return parts.filter((part) => typeof part === "string" && part !== "").join("\n");
273
+ }
274
+ function splitConfirmation(args) {
275
+ const { confirmation, ...payload } = args;
276
+ return {
277
+ payload,
278
+ confirmation
279
+ };
280
+ }
281
+ //#endregion
282
+ //#region src/mcp/inputs.ts
283
+ const MCP_INVOICE_TYPES = ["invoice", "proforma"];
284
+ const BUYER_KEYS = [
285
+ "name",
286
+ "zip",
287
+ "city",
288
+ "address",
289
+ "country",
290
+ "email",
291
+ "taxNumber",
292
+ "euTaxNumber"
293
+ ];
294
+ const ITEM_KEYS = [
295
+ "name",
296
+ "quantity",
297
+ "unit",
298
+ "netUnitPrice",
299
+ "grossUnitPrice",
300
+ "vat",
301
+ "comment"
302
+ ];
303
+ const PAYMENT_KEYS = [
304
+ "method",
305
+ "amount",
306
+ "description"
307
+ ];
308
+ const INVOICE_INPUT_KEYS = [
309
+ "type",
310
+ "buyer",
311
+ "items",
312
+ "paymentMethod",
313
+ "currency",
314
+ "exchangeRate",
315
+ "exchangeBank",
316
+ "language",
317
+ "issueDate",
318
+ "fulfillmentDate",
319
+ "dueDate",
320
+ "comment",
321
+ "orderNumber",
322
+ "externalId",
323
+ "prefix",
324
+ "paid",
325
+ "eInvoice",
326
+ "sendEmail"
327
+ ];
328
+ const RECEIPT_INPUT_KEYS = [
329
+ "items",
330
+ "payments",
331
+ "paymentMethod",
332
+ "currency",
333
+ "exchangeRate",
334
+ "exchangeBank",
335
+ "comment",
336
+ "orderNumber",
337
+ "prefix"
338
+ ];
339
+ function unitPriceOf(item, path) {
340
+ const net = optionalNumber(item, "netUnitPrice", path);
341
+ const gross = optionalNumber(item, "grossUnitPrice", path);
342
+ const quantity = optionalNumber(item, "quantity", path);
343
+ if (net === void 0 === (gross === void 0)) throw new ToolInputError(`A(z) ${path} tételnél pontosan az egyiket add meg: netUnitPrice (nettó egységár) vagy grossUnitPrice (bruttó egységár).`);
344
+ return {
345
+ ...net === void 0 ? {} : { netUnitPrice: net },
346
+ ...gross === void 0 ? {} : { grossUnitPrice: gross },
347
+ ...quantity === void 0 ? {} : { quantity }
348
+ };
349
+ }
350
+ function itemObject(value, index) {
351
+ const path = `items[${index}]`;
352
+ const item = objectArg(value, path);
353
+ assertKnownKeys(item, ITEM_KEYS, path);
354
+ return {
355
+ item,
356
+ path
357
+ };
358
+ }
359
+ function invoiceItemOf(value, index) {
360
+ const { item, path } = itemObject(value, index);
361
+ return {
362
+ name: requiredString(item, "name", path),
363
+ unit: optionalString(item, "unit", path),
364
+ comment: optionalString(item, "comment", path),
365
+ vat: invoiceVat(item.vat, `${path}.vat`),
366
+ ...unitPriceOf(item, path)
367
+ };
368
+ }
369
+ function receiptItemOf(value, index) {
370
+ const { item, path } = itemObject(value, index);
371
+ return {
372
+ name: requiredString(item, "name", path),
373
+ unit: optionalString(item, "unit", path),
374
+ comment: optionalString(item, "comment", path),
375
+ vat: receiptVat(item.vat, `${path}.vat`),
376
+ ...unitPriceOf(item, path)
377
+ };
378
+ }
379
+ function buyerOf(value, sendEmail) {
380
+ const buyer = objectArg(value, "buyer");
381
+ assertKnownKeys(buyer, BUYER_KEYS, "buyer");
382
+ return {
383
+ name: requiredString(buyer, "name", "buyer"),
384
+ zip: requiredString(buyer, "zip", "buyer"),
385
+ city: requiredString(buyer, "city", "buyer"),
386
+ address: requiredString(buyer, "address", "buyer"),
387
+ country: optionalString(buyer, "country", "buyer"),
388
+ email: optionalString(buyer, "email", "buyer"),
389
+ taxNumber: optionalString(buyer, "taxNumber", "buyer"),
390
+ euTaxNumber: optionalString(buyer, "euTaxNumber", "buyer"),
391
+ sendEmail
392
+ };
393
+ }
394
+ function paymentOf(value, index) {
395
+ const path = `payments[${index}]`;
396
+ const payment = objectArg(value, path);
397
+ assertKnownKeys(payment, PAYMENT_KEYS, path);
398
+ const amount = optionalNumber(payment, "amount", path);
399
+ if (amount === void 0) throw new ToolInputError(`A(z) ${path}.amount mező kötelező.`);
400
+ return {
401
+ method: requiredString(payment, "method", path),
402
+ amount,
403
+ description: optionalString(payment, "description", path)
404
+ };
405
+ }
406
+ function invoiceInputOf(args, extraKeys = []) {
407
+ assertKnownKeys(args, [...INVOICE_INPUT_KEYS, ...extraKeys], "");
408
+ return {
409
+ type: optionalEnum(args, "type", "", MCP_INVOICE_TYPES),
410
+ buyer: buyerOf(args.buyer, optionalBoolean(args, "sendEmail", "") ?? false),
411
+ items: requiredArray(args, "items", "", {
412
+ min: 1,
413
+ max: 100
414
+ }).map(invoiceItemOf),
415
+ paymentMethod: optionalString(args, "paymentMethod", ""),
416
+ currency: optionalString(args, "currency", ""),
417
+ exchangeRate: optionalNumber(args, "exchangeRate", ""),
418
+ exchangeBank: optionalString(args, "exchangeBank", ""),
419
+ language: optionalEnum(args, "language", "", require_create_once.INVOICE_LANGUAGES),
420
+ issueDate: optionalDate(args, "issueDate", ""),
421
+ fulfillmentDate: optionalDate(args, "fulfillmentDate", ""),
422
+ dueDate: optionalDate(args, "dueDate", ""),
423
+ comment: optionalString(args, "comment", ""),
424
+ orderNumber: optionalString(args, "orderNumber", ""),
425
+ externalId: optionalString(args, "externalId", ""),
426
+ prefix: optionalString(args, "prefix", ""),
427
+ paid: optionalBoolean(args, "paid", ""),
428
+ eInvoice: optionalBoolean(args, "eInvoice", ""),
429
+ downloadPdf: false
430
+ };
431
+ }
432
+ function receiptInputOf(args, extraKeys = []) {
433
+ assertKnownKeys(args, [...RECEIPT_INPUT_KEYS, ...extraKeys], "");
434
+ return {
435
+ items: requiredArray(args, "items", "", {
436
+ min: 1,
437
+ max: 100
438
+ }).map(receiptItemOf),
439
+ payments: optionalArray(args, "payments", "")?.map(paymentOf),
440
+ paymentMethod: optionalString(args, "paymentMethod", ""),
441
+ currency: optionalString(args, "currency", ""),
442
+ exchangeRate: optionalNumber(args, "exchangeRate", ""),
443
+ exchangeBank: optionalString(args, "exchangeBank", ""),
444
+ comment: optionalString(args, "comment", ""),
445
+ orderNumber: optionalString(args, "orderNumber", ""),
446
+ prefix: optionalString(args, "prefix", ""),
447
+ downloadPdf: false
448
+ };
449
+ }
450
+ //#endregion
451
+ //#region src/mcp/schemas.ts
452
+ const TEXT = {
453
+ type: "string",
454
+ minLength: 1
455
+ };
456
+ const DATE = {
457
+ type: "string",
458
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$",
459
+ description: "Dátum ÉÉÉÉ-HH-NN formában (Europe/Budapest szerint)."
460
+ };
461
+ const VAT = {
462
+ description: "Áfakulcs: szám (például 27, 18, 5, 0) vagy kód (például \"AAM\" alanyi adómentes, \"TAM\" tárgyi adómentes, \"EUT\", \"EUKT\", \"F.AFA\", \"K.AFA\"). Nyugtán \"ÁKK\", \"MAA\", \"EU\" és \"EUK\" is lehet.",
463
+ anyOf: [{ type: "number" }, {
464
+ type: "string",
465
+ minLength: 1
466
+ }]
467
+ };
468
+ const ITEMS = {
469
+ type: "array",
470
+ items: {
471
+ type: "object",
472
+ properties: {
473
+ name: {
474
+ ...TEXT,
475
+ description: "A tétel megnevezése."
476
+ },
477
+ quantity: {
478
+ type: "number",
479
+ description: "Mennyiség, alapértelmezés: 1."
480
+ },
481
+ unit: {
482
+ ...TEXT,
483
+ description: "Mennyiségi egység, például db, óra."
484
+ },
485
+ netUnitPrice: {
486
+ type: "number",
487
+ description: "Nettó egységár. A netUnitPrice és a grossUnitPrice közül pontosan egyet adj meg."
488
+ },
489
+ grossUnitPrice: {
490
+ type: "number",
491
+ description: "Bruttó egységár. A netUnitPrice és a grossUnitPrice közül pontosan egyet adj meg."
492
+ },
493
+ vat: VAT,
494
+ comment: {
495
+ ...TEXT,
496
+ description: "Megjegyzés a tételhez."
497
+ }
498
+ },
499
+ required: ["name", "vat"],
500
+ additionalProperties: false
501
+ },
502
+ minItems: 1,
503
+ maxItems: 100
504
+ };
505
+ const BUYER = {
506
+ type: "object",
507
+ properties: {
508
+ name: {
509
+ ...TEXT,
510
+ description: "A vevő neve."
511
+ },
512
+ zip: {
513
+ ...TEXT,
514
+ description: "Irányítószám."
515
+ },
516
+ city: {
517
+ ...TEXT,
518
+ description: "Település."
519
+ },
520
+ address: {
521
+ ...TEXT,
522
+ description: "Utca, házszám."
523
+ },
524
+ country: {
525
+ ...TEXT,
526
+ description: "Ország, ha nem Magyarország."
527
+ },
528
+ email: {
529
+ ...TEXT,
530
+ description: "A vevő e-mail címe."
531
+ },
532
+ taxNumber: {
533
+ ...TEXT,
534
+ description: "Magyar adószám, például 12345676-2-42."
535
+ },
536
+ euTaxNumber: {
537
+ ...TEXT,
538
+ description: "Közösségi adószám, például HU12345676."
539
+ }
540
+ },
541
+ required: [
542
+ "name",
543
+ "zip",
544
+ "city",
545
+ "address"
546
+ ],
547
+ additionalProperties: false
548
+ };
549
+ const COMMON_DOCUMENT_PROPERTIES = {
550
+ paymentMethod: {
551
+ ...TEXT,
552
+ description: "Fizetési mód, például átutalás, készpénz, bankkártya."
553
+ },
554
+ currency: {
555
+ ...TEXT,
556
+ description: "Pénznem, alapértelmezés: HUF."
557
+ },
558
+ exchangeRate: {
559
+ type: "number",
560
+ description: "Árfolyam devizás bizonylathoz."
561
+ },
562
+ exchangeBank: {
563
+ ...TEXT,
564
+ description: "Az árfolyamot jegyző bank, például MNB."
565
+ },
566
+ comment: {
567
+ ...TEXT,
568
+ description: "Megjegyzés a bizonylaton."
569
+ },
570
+ orderNumber: {
571
+ ...TEXT,
572
+ description: "Rendelésszám (a bizonylaton megjelenik)."
573
+ },
574
+ prefix: {
575
+ ...TEXT,
576
+ description: "A Számlázz.hu fiókban rögzített előtag."
577
+ }
578
+ };
579
+ function objectSchema(properties, required = []) {
580
+ return {
581
+ type: "object",
582
+ properties,
583
+ required: [...required],
584
+ additionalProperties: false
585
+ };
586
+ }
587
+ const INVOICE_PROPERTIES = {
588
+ type: {
589
+ type: "string",
590
+ enum: [...MCP_INVOICE_TYPES],
591
+ description: "invoice (számla, alapértelmezés) vagy proforma (díjbekérő)."
592
+ },
593
+ buyer: BUYER,
594
+ items: ITEMS,
595
+ ...COMMON_DOCUMENT_PROPERTIES,
596
+ language: {
597
+ type: "string",
598
+ enum: [...require_create_once.INVOICE_LANGUAGES],
599
+ description: "A számla nyelve."
600
+ },
601
+ issueDate: {
602
+ ...DATE,
603
+ description: "Kelt, alapértelmezés: ma."
604
+ },
605
+ fulfillmentDate: {
606
+ ...DATE,
607
+ description: "Teljesítés dátuma, alapértelmezés: ma."
608
+ },
609
+ dueDate: {
610
+ ...DATE,
611
+ description: "Fizetési határidő."
612
+ },
613
+ externalId: {
614
+ ...TEXT,
615
+ description: "Saját külső azonosító. Ha megadod, ugyanezzel csak egy számla készül; ha nem, a kassza képez egyet."
616
+ },
617
+ paid: {
618
+ type: "boolean",
619
+ description: "A számla már ki van fizetve."
620
+ },
621
+ eInvoice: {
622
+ type: "boolean",
623
+ description: "Elektronikus számla."
624
+ },
625
+ sendEmail: {
626
+ type: "boolean",
627
+ description: "A Számlázz.hu e-mailben elküldi-e a vevőnek. Alapértelmezés: false."
628
+ }
629
+ };
630
+ const RECEIPT_PROPERTIES = {
631
+ items: ITEMS,
632
+ payments: {
633
+ type: "array",
634
+ description: "Kifizetések fizetőeszközönként; az összegük a nyugta bruttó végösszege.",
635
+ items: objectSchema({
636
+ method: {
637
+ ...TEXT,
638
+ description: "Fizetőeszköz, például készpénz, bankkártya."
639
+ },
640
+ amount: { type: "number" },
641
+ description: TEXT
642
+ }, ["method", "amount"])
643
+ },
644
+ ...COMMON_DOCUMENT_PROPERTIES
645
+ };
646
+ const CONFIRMATION_PROPERTY = {
647
+ ...TEXT,
648
+ description: "Az előnézeti eszköz által adott megerősítő kód. Csak azután add meg, hogy a felhasználó jóváhagyta az előnézetet."
649
+ };
650
+ const TEXT_PROPERTY = TEXT;
651
+ const INVOICE_SCHEMA = objectSchema(INVOICE_PROPERTIES, ["buyer", "items"]);
652
+ const CREATE_INVOICE_SCHEMA = objectSchema({
653
+ ...INVOICE_PROPERTIES,
654
+ confirmation: CONFIRMATION_PROPERTY
655
+ }, [
656
+ "buyer",
657
+ "items",
658
+ "confirmation"
659
+ ]);
660
+ const RECEIPT_SCHEMA = objectSchema(RECEIPT_PROPERTIES, ["items"]);
661
+ const CREATE_RECEIPT_SCHEMA = objectSchema({
662
+ ...RECEIPT_PROPERTIES,
663
+ confirmation: CONFIRMATION_PROPERTY
664
+ }, ["items", "confirmation"]);
665
+ //#endregion
666
+ //#region src/mcp/tools-invoice.ts
667
+ const PREVIEW_INVOICE = "preview_invoice";
668
+ const CREATE_INVOICE = "create_invoice";
669
+ function documentLabel(resolved) {
670
+ return resolved.type === "proforma" ? "Díjbekérő" : "Számla";
671
+ }
672
+ function resolve(input, context) {
673
+ return require_create_once.resolveInvoice(context.defaults.invoice ?? {}, input, context.now());
674
+ }
675
+ function previewData(input, resolved) {
676
+ const totals = require_money.summarizeItems(resolved.items.map((item) => item.amounts));
677
+ return {
678
+ document: resolved.type,
679
+ buyer: input.buyer,
680
+ issueDate: resolved.issueDate,
681
+ fulfillmentDate: resolved.fulfillmentDate,
682
+ dueDate: resolved.dueDate,
683
+ paymentMethod: resolved.paymentMethod,
684
+ currency: resolved.currency,
685
+ exchangeRate: resolved.exchangeRate,
686
+ exchangeBank: resolved.exchangeBank,
687
+ language: resolved.language,
688
+ prefix: resolved.prefix,
689
+ eInvoice: resolved.eInvoice,
690
+ sendEmail: resolved.sendEmail,
691
+ orderNumber: input.orderNumber,
692
+ comment: input.comment,
693
+ items: resolved.items.map((item) => ({
694
+ name: item.input.name,
695
+ quantity: item.amounts.quantity,
696
+ unit: item.unit,
697
+ netUnitPrice: item.amounts.netUnitPrice,
698
+ vat: item.amounts.vat,
699
+ netAmount: item.amounts.netAmount,
700
+ vatAmount: item.amounts.vatAmount,
701
+ grossAmount: item.amounts.grossAmount
702
+ })),
703
+ totals: {
704
+ netAmount: totals.netAmount,
705
+ vatAmount: totals.vatAmount,
706
+ grossAmount: totals.grossAmount
707
+ }
708
+ };
709
+ }
710
+ async function previewInvoice(args, context) {
711
+ const input = invoiceInputOf(args);
712
+ const resolved = resolve(input, context);
713
+ const data = previewData(input, resolved);
714
+ const totals = require_money.summarizeItems(resolved.items.map((item) => item.amounts));
715
+ const confirmation = await context.confirmations.issue(CREATE_INVOICE, args);
716
+ return {
717
+ summary: lines(`${documentLabel(resolved)} előnézete (még NEM készült el): ${input.buyer.name}, nettó ${money(totals.netAmount, resolved.currency)}, bruttó ${money(totals.grossAmount, resolved.currency)}.`, `Kelt: ${resolved.issueDate}, teljesítés: ${resolved.fulfillmentDate}, fizetési határidő: ${resolved.dueDate}, fizetési mód: ${resolved.paymentMethod}.`, resolved.sendEmail ? "A Számlázz.hu e-mailben elküldi a vevőnek." : "A vevő nem kap e-mailt a Számlázz.hu-tól.", `Mutasd meg az előnézetet a felhasználónak. Ha jóváhagyja, hívd meg a ${CREATE_INVOICE} eszközt pontosan ugyanezekkel az adatokkal, a confirmation mezőben ezzel a kóddal: ${confirmation.token} (lejár: ${confirmation.expiresAt}).`),
718
+ data: {
719
+ ...data,
720
+ confirmation: confirmation.token,
721
+ confirmationExpiresAt: confirmation.expiresAt
722
+ }
723
+ };
724
+ }
725
+ function existingOutput(details, externalId, created) {
726
+ const currency = details.header.currency ?? "HUF";
727
+ return {
728
+ summary: created ? `Kiállítva: ${details.header.number} (bruttó ${money(details.totals.grossAmount, currency)}). A válasz elveszett, de a kassza visszakereste.` : `Ezzel a külső azonosítóval (${externalId}) már létezik bizonylat: ${details.header.number} (bruttó ${money(details.totals.grossAmount, currency)}). Nem állítottam ki újra. Ha valóban még egy ugyanilyen kell, adj meg eltérő externalId értéket.`,
729
+ data: {
730
+ created,
731
+ number: details.header.number,
732
+ externalId,
733
+ netTotal: details.totals.netAmount,
734
+ grossTotal: details.totals.grossAmount,
735
+ currency
736
+ }
737
+ };
738
+ }
739
+ async function createInvoice(args, context) {
740
+ const { payload, confirmation } = splitConfirmation(args);
741
+ await context.confirmations.verify(CREATE_INVOICE, payload, confirmation, PREVIEW_INVOICE);
742
+ const input = invoiceInputOf(payload);
743
+ const resolved = resolve(input, context);
744
+ const externalId = input.externalId ?? `MCP-${await idempotencyKey("create_invoice", resolved.issueDate, payload)}`;
745
+ const kassza = context.client();
746
+ const lookup = () => kassza.invoices.find({ externalId }, { includePdf: false });
747
+ const existing = await lookup();
748
+ if (existing) return existingOutput(existing, externalId, false);
749
+ try {
750
+ const created = await kassza.invoices.create({
751
+ ...input,
752
+ externalId,
753
+ issueDate: resolved.issueDate,
754
+ fulfillmentDate: resolved.fulfillmentDate,
755
+ dueDate: resolved.dueDate
756
+ });
757
+ return {
758
+ summary: `${documentLabel(resolved)} kiállítva: ${created.number} (bruttó ${money(created.grossTotal, resolved.currency)}).`,
759
+ data: {
760
+ created: true,
761
+ number: created.number,
762
+ externalId,
763
+ netTotal: created.netTotal,
764
+ grossTotal: created.grossTotal,
765
+ outstanding: created.outstanding,
766
+ currency: resolved.currency
767
+ }
768
+ };
769
+ } catch (error) {
770
+ if (!require_issue.isUncertainOutcome(error)) throw error;
771
+ const recovered = await require_issue.recoverAfterFailure(lookup, context.recoveryDelayMs, void 0);
772
+ if (!recovered) throw error;
773
+ return existingOutput(recovered, externalId, error.category !== "duplicate");
774
+ }
775
+ }
776
+ const INVOICE_TOOLS = [{
777
+ name: PREVIEW_INVOICE,
778
+ title: "Számla előnézete",
779
+ description: "Kiszámolja egy számla vagy díjbekérő tételeit és végösszegét a Számlázz.hu hívása nélkül, és ad egy megerősítő kódot a create_invoice eszközhöz. Semmit nem állít ki.",
780
+ inputSchema: INVOICE_SCHEMA,
781
+ annotations: LOCAL_READ,
782
+ write: false,
783
+ run: previewInvoice
784
+ }, {
785
+ name: CREATE_INVOICE,
786
+ title: "Számla kiállítása",
787
+ description: "Kiállítja a számlát vagy díjbekérőt a Számlázz.hu-n. Csak a preview_invoice által adott megerősítő kóddal működik, és csak akkor hívd, ha a felhasználó jóváhagyta az előnézetet. Ugyanazzal a kéréssel naponta csak egy bizonylat készül.",
788
+ inputSchema: CREATE_INVOICE_SCHEMA,
789
+ annotations: REMOTE_CREATE,
790
+ write: true,
791
+ run: createInvoice
792
+ }];
793
+ const INVOICE_TYPE_LABELS = {
794
+ invoice: "Számla",
795
+ proforma: "Díjbekérő",
796
+ advance: "Előlegszámla",
797
+ final: "Végszámla",
798
+ corrective: "Helyesbítő számla",
799
+ reversal: "Sztornó számla",
800
+ deliveryNote: "Szállítólevél"
801
+ };
802
+ function exactlyOne(values) {
803
+ const present = Object.entries(values).filter(([, value]) => value !== void 0);
804
+ if (present.length !== 1) throw new ToolInputError(`Pontosan egyet adj meg ezek közül: ${Object.keys(values).join(", ")}.`);
805
+ return present[0]?.[0] ?? "";
806
+ }
807
+ async function getInvoice(args, context) {
808
+ assertKnownKeys(args, [
809
+ "invoiceNumber",
810
+ "orderNumber",
811
+ "externalId"
812
+ ], "");
813
+ const invoiceNumber = optionalString(args, "invoiceNumber", "");
814
+ const orderNumber = optionalString(args, "orderNumber", "");
815
+ const externalId = optionalString(args, "externalId", "");
816
+ const kind = exactlyOne({
817
+ invoiceNumber,
818
+ orderNumber,
819
+ externalId
820
+ });
821
+ const reference = kind === "invoiceNumber" ? invoiceNumber ?? "" : kind === "orderNumber" ? { orderNumber: orderNumber ?? "" } : { externalId: externalId ?? "" };
822
+ const details = await context.client().invoices.find(reference, { includePdf: false });
823
+ if (!details) return {
824
+ summary: "Nincs ilyen számla a Számlázz.hu fiókban.",
825
+ data: { found: false }
826
+ };
827
+ const { header } = details;
828
+ const currency = header.currency ?? "HUF";
829
+ return {
830
+ summary: lines(`${INVOICE_TYPE_LABELS[header.type] ?? "Bizonylat"} ${header.number}: ${details.buyer.name}, bruttó ${money(details.totals.grossAmount, currency)}, kelt: ${header.issueDate}.`, header.reversed === true && "A számlát sztornózták.", header.test === true && "Tesztfiókban készült."),
831
+ data: {
832
+ found: true,
833
+ invoice: plainJson(details)
834
+ }
835
+ };
836
+ }
837
+ async function getReceipt(args, context) {
838
+ assertKnownKeys(args, ["receiptNumber", "orderNumber"], "");
839
+ const receiptNumber = optionalString(args, "receiptNumber", "");
840
+ const orderNumber = optionalString(args, "orderNumber", "");
841
+ const kind = exactlyOne({
842
+ receiptNumber,
843
+ orderNumber
844
+ });
845
+ const receipt = await context.client().receipts.find(kind === "receiptNumber" ? {
846
+ receiptNumber: receiptNumber ?? "",
847
+ downloadPdf: false
848
+ } : {
849
+ orderNumber: orderNumber ?? "",
850
+ downloadPdf: false
851
+ });
852
+ if (!receipt) return {
853
+ summary: "Nincs ilyen nyugta a Számlázz.hu fiókban.",
854
+ data: { found: false }
855
+ };
856
+ return {
857
+ summary: lines(`${receipt.type === "reversal" ? "Sztornónyugta" : "Nyugta"} ${receipt.number}: bruttó ${money(receipt.totals.grossAmount, receipt.currency)}, kelt: ${receipt.issueDate}.`, receipt.isReversed && "A nyugtát sztornózták.", receipt.isTest && "Tesztfiókban készült."),
858
+ data: {
859
+ found: true,
860
+ receipt: plainJson(receipt)
861
+ }
862
+ };
863
+ }
864
+ async function queryTaxpayer(args, context) {
865
+ assertKnownKeys(args, ["taxNumber"], "");
866
+ const taxNumber = requiredString(args, "taxNumber", "");
867
+ const info = await context.client().taxpayer.query(taxNumber);
868
+ return {
869
+ summary: info.valid ? lines(`${info.name ?? "Ismeretlen név"}${info.taxNumber?.formatted ? ` (${info.taxNumber.formatted})` : ""}: a NAV szerint érvényes adószám.`, info.address && `Székhely: ${info.address.formatted}.`) : "A NAV szerint ez az adószám nem érvényes, vagy nem tartozik működő adóalanyhoz.",
870
+ data: plainJson(info)
871
+ };
872
+ }
873
+ function receiptNumbersOf(args) {
874
+ const listed = optionalArray(args, "receiptNumbers", "");
875
+ const series = optionalString(args, "series", "");
876
+ const from = optionalInteger(args, "from", "");
877
+ const to = optionalInteger(args, "to", "");
878
+ if (listed !== void 0) {
879
+ if (series !== void 0 || from !== void 0 || to !== void 0) throw new ToolInputError("A receiptNumbers mellett ne adj meg series, from vagy to mezőt.");
880
+ const numbers = listed.map((value, index) => {
881
+ if (typeof value !== "string" || value.trim() === "") throw new ToolInputError(`A(z) receiptNumbers[${index}] nem érvényes nyugtaszám.`);
882
+ return value.trim();
883
+ });
884
+ return [...new Set(numbers)];
885
+ }
886
+ if (series === void 0 || from === void 0 || to === void 0) throw new ToolInputError("Add meg a nyugtaszámokat (receiptNumbers), vagy a sorozatot és a tartományt (series, from, to), például series: \"NYGT-2026\", from: 1, to: 120.");
887
+ if (from < 1 || to < from) throw new ToolInputError("A from legalább 1 legyen, és nem lehet nagyobb a to értékénél.");
888
+ return Array.from({ length: to - from + 1 }, (_, index) => `${series}-${from + index}`);
889
+ }
890
+ async function navDailySummary(args, context) {
891
+ assertKnownKeys(args, [
892
+ "receiptNumbers",
893
+ "series",
894
+ "from",
895
+ "to",
896
+ "includeTest"
897
+ ], "");
898
+ const numbers = receiptNumbersOf(args);
899
+ if (numbers.length === 0 || numbers.length > 200) throw new ToolInputError(`Egyszerre 1 és 200 közötti számú nyugta összesíthető, kért: ${numbers.length}.`);
900
+ const includeTest = optionalBoolean(args, "includeTest", "") ?? false;
901
+ const kassza = context.client();
902
+ const receipts = [];
903
+ const missing = [];
904
+ for (const receiptNumber of numbers) {
905
+ const receipt = await kassza.receipts.find({
906
+ receiptNumber,
907
+ downloadPdf: false
908
+ });
909
+ if (receipt) receipts.push(receipt);
910
+ else missing.push(receiptNumber);
911
+ }
912
+ const reports = require_nav.navDailyReports(receipts, { includeTest });
913
+ const skippedTest = includeTest ? 0 : receipts.filter((receipt) => receipt.isTest).length;
914
+ return {
915
+ summary: lines(reports.length === 0 ? "Nincs összesíthető nyugta." : reports.map((report) => require_nav.describeNavReport(report)).join("\n\n"), missing.length > 0 && `Nem található nyugták: ${missing.join(", ")}.`, skippedTest > 0 && `${skippedTest} tesztfiókos nyugtát kihagytam (az includeTest: true beveszi őket).`),
916
+ data: {
917
+ reports: plainJson({ reports }).reports,
918
+ missing,
919
+ receiptCount: receipts.length
920
+ }
921
+ };
922
+ }
923
+ const LOOKUP_TOOLS = [
924
+ {
925
+ name: "get_invoice",
926
+ title: "Számla lekérdezése",
927
+ description: "Lekér egy számlát (díjbekérőt, sztornót) a Számlázz.hu-ról számlaszám, rendelésszám vagy külső azonosító alapján.",
928
+ inputSchema: objectSchema({
929
+ invoiceNumber: TEXT_PROPERTY,
930
+ orderNumber: TEXT_PROPERTY,
931
+ externalId: TEXT_PROPERTY
932
+ }),
933
+ annotations: REMOTE_READ,
934
+ write: false,
935
+ run: getInvoice
936
+ },
937
+ {
938
+ name: "get_receipt",
939
+ title: "Nyugta lekérdezése",
940
+ description: "Lekér egy nyugtát a Számlázz.hu-ról nyugtaszám vagy rendelésszám alapján.",
941
+ inputSchema: objectSchema({
942
+ receiptNumber: TEXT_PROPERTY,
943
+ orderNumber: TEXT_PROPERTY
944
+ }),
945
+ annotations: REMOTE_READ,
946
+ write: false,
947
+ run: getReceipt
948
+ },
949
+ {
950
+ name: "query_taxpayer",
951
+ title: "Adószám ellenőrzése",
952
+ description: "A NAV adatai alapján (a Számlázz.hu-n keresztül) ellenőrzi az adószámot, és visszaadja a cég nevét és székhelyét.",
953
+ inputSchema: objectSchema({ taxNumber: {
954
+ ...TEXT_PROPERTY,
955
+ description: "8 jegyű törzsszám vagy 11 jegyű adószám, például 12345676-2-42."
956
+ } }, ["taxNumber"]),
957
+ annotations: REMOTE_READ,
958
+ write: false,
959
+ run: queryTaxpayer
960
+ },
961
+ {
962
+ name: "nav_daily_summary",
963
+ title: "Napi NAV nyugta-összesítő",
964
+ description: `Lekéri a megadott nyugtákat, és elkészíti belőlük a NAV felé teendő napi, áfakategóriánkénti összesítőt (kezdő sorszám, értékesítés, módosító bizonylatok). Egyszerre legfeljebb 200 nyugta.`,
965
+ inputSchema: objectSchema({
966
+ receiptNumbers: {
967
+ type: "array",
968
+ items: TEXT_PROPERTY,
969
+ minItems: 1,
970
+ maxItems: 200
971
+ },
972
+ series: {
973
+ ...TEXT_PROPERTY,
974
+ description: "Sorozat, például NYGT-2026."
975
+ },
976
+ from: {
977
+ type: "integer",
978
+ minimum: 1
979
+ },
980
+ to: {
981
+ type: "integer",
982
+ minimum: 1
983
+ },
984
+ includeTest: {
985
+ type: "boolean",
986
+ description: "A tesztfiókos nyugtákat is összesíti."
987
+ }
988
+ }),
989
+ annotations: REMOTE_READ,
990
+ write: false,
991
+ run: navDailySummary
992
+ }
993
+ ];
994
+ //#endregion
995
+ //#region src/mcp/tools-receipt.ts
996
+ const PREVIEW_RECEIPT = "preview_receipt";
997
+ const CREATE_RECEIPT = "create_receipt";
998
+ const DUPLICATE_CALL_ID = 338;
999
+ function previewOf(input, context) {
1000
+ const defaults = context.defaults.receipt ?? {};
1001
+ require_issue.buildCreateReceiptXml([], defaults, input);
1002
+ const currency = input.currency ?? defaults.currency ?? "HUF";
1003
+ const items = require_issue.calculateReceiptItems(input.items, currency);
1004
+ const totals = require_money.summarizeItems(items.map((item) => item.amounts));
1005
+ return {
1006
+ currency,
1007
+ grossAmount: totals.grossAmount,
1008
+ data: {
1009
+ document: "receipt",
1010
+ prefix: input.prefix ?? defaults.prefix,
1011
+ paymentMethod: input.paymentMethod ?? defaults.paymentMethod,
1012
+ currency,
1013
+ exchangeRate: input.exchangeRate ?? defaults.exchangeRate,
1014
+ orderNumber: input.orderNumber,
1015
+ comment: input.comment,
1016
+ items: items.map((item) => ({
1017
+ name: item.input.name,
1018
+ quantity: item.amounts.quantity,
1019
+ unit: item.input.unit ?? defaults.unit ?? "db",
1020
+ netUnitPrice: item.amounts.netUnitPrice,
1021
+ vat: item.vat,
1022
+ netAmount: item.amounts.netAmount,
1023
+ vatAmount: item.amounts.vatAmount,
1024
+ grossAmount: item.amounts.grossAmount
1025
+ })),
1026
+ payments: input.payments ?? [],
1027
+ totals: {
1028
+ netAmount: totals.netAmount,
1029
+ vatAmount: totals.vatAmount,
1030
+ grossAmount: totals.grossAmount
1031
+ }
1032
+ }
1033
+ };
1034
+ }
1035
+ async function previewReceipt(args, context) {
1036
+ const preview = previewOf(receiptInputOf(args), context);
1037
+ const confirmation = await context.confirmations.issue(CREATE_RECEIPT, args);
1038
+ return {
1039
+ summary: lines(`Nyugta előnézete (még NEM készült el): bruttó ${money(preview.grossAmount, preview.currency)}.`, `Mutasd meg az előnézetet a felhasználónak. Ha jóváhagyja, hívd meg a ${CREATE_RECEIPT} eszközt pontosan ugyanezekkel az adatokkal, a confirmation mezőben ezzel a kóddal: ${confirmation.token} (lejár: ${confirmation.expiresAt}).`),
1040
+ data: {
1041
+ ...preview.data,
1042
+ confirmation: confirmation.token,
1043
+ confirmationExpiresAt: confirmation.expiresAt
1044
+ }
1045
+ };
1046
+ }
1047
+ function receiptOutput(receipt, created) {
1048
+ const total = money(receipt.totals.grossAmount, receipt.currency);
1049
+ return {
1050
+ summary: created ? `Nyugta kiállítva: ${receipt.number} (bruttó ${total}).` : `Ehhez a rendelésszámhoz már létezik nyugta: ${receipt.number} (bruttó ${total}). Nem állítottam ki újra.`,
1051
+ data: {
1052
+ created,
1053
+ number: receipt.number,
1054
+ type: receipt.type,
1055
+ orderNumber: receipt.orderNumber,
1056
+ callId: receipt.callId,
1057
+ issueDate: receipt.issueDate,
1058
+ grossTotal: receipt.totals.grossAmount,
1059
+ currency: receipt.currency
1060
+ }
1061
+ };
1062
+ }
1063
+ function duplicateCallIdError(error, callId) {
1064
+ return new require_errors.SzamlazzError(`Ezekkel az adatokkal ma már készült nyugta ezen az eszközön keresztül (hívásazonosító: ${callId}), ezért nem készült új.`, {
1065
+ category: "duplicate",
1066
+ code: error.code,
1067
+ action: error.action,
1068
+ hint: "A Számla Agent hívásazonosító alapján nem tud nyugtát lekérdezni: a nyugtát a Számlázz.hu felületén találod. Ha valóban még egy ugyanilyen nyugta kell, adj meg rendelésszámot (orderNumber), vagy változtass az adatokon.",
1069
+ cause: error
1070
+ });
1071
+ }
1072
+ async function createReceipt(args, context) {
1073
+ const { payload, confirmation } = splitConfirmation(args);
1074
+ await context.confirmations.verify(CREATE_RECEIPT, payload, confirmation, PREVIEW_RECEIPT);
1075
+ const input = receiptInputOf(payload);
1076
+ previewOf(input, context);
1077
+ const day = require_dates.toBudapestDate(context.now());
1078
+ const callId = `MCP-${await idempotencyKey(CREATE_RECEIPT, day, payload)}`;
1079
+ const kassza = context.client();
1080
+ if (input.orderNumber !== void 0) {
1081
+ const result = await kassza.receipts.createOnce({
1082
+ ...input,
1083
+ callId
1084
+ }, { recoveryDelayMs: context.recoveryDelayMs });
1085
+ return receiptOutput(result.receipt, result.created);
1086
+ }
1087
+ try {
1088
+ return receiptOutput(await kassza.receipts.create({
1089
+ ...input,
1090
+ callId
1091
+ }), true);
1092
+ } catch (error) {
1093
+ if (require_errors.isSzamlazzError(error) && error.code === DUPLICATE_CALL_ID) throw duplicateCallIdError(error, callId);
1094
+ throw error;
1095
+ }
1096
+ }
1097
+ const RECEIPT_TOOLS = [{
1098
+ name: PREVIEW_RECEIPT,
1099
+ title: "Nyugta előnézete",
1100
+ description: "Kiszámolja egy nyugta tételeit és végösszegét a Számlázz.hu hívása nélkül, ellenőrzi a forintos kerekítési szabályokat, és ad egy megerősítő kódot a create_receipt eszközhöz. Semmit nem állít ki.",
1101
+ inputSchema: RECEIPT_SCHEMA,
1102
+ annotations: LOCAL_READ,
1103
+ write: false,
1104
+ run: previewReceipt
1105
+ }, {
1106
+ name: CREATE_RECEIPT,
1107
+ title: "Nyugta kiállítása",
1108
+ description: "Kiállítja a nyugtát a Számlázz.hu-n. Csak a preview_receipt által adott megerősítő kóddal működik, és csak akkor hívd, ha a felhasználó jóváhagyta az előnézetet. Rendelésszámmal egy rendeléshez csak egy nyugta készül.",
1109
+ inputSchema: CREATE_RECEIPT_SCHEMA,
1110
+ annotations: REMOTE_CREATE,
1111
+ write: true,
1112
+ run: createReceipt
1113
+ }];
1114
+ //#endregion
1115
+ //#region src/mcp/tools-reversal.ts
1116
+ const PREVIEW_REVERSAL = "preview_reversal";
1117
+ const REVERSE_INVOICE = "reverse_invoice";
1118
+ const REVERSE_RECEIPT = "reverse_receipt";
1119
+ const DOCUMENT_KINDS = ["invoice", "receipt"];
1120
+ const ALREADY_REVERSED_MESSAGE = "már sztornózták";
1121
+ function assertReversibleInvoice(details) {
1122
+ const { number, type } = details.header;
1123
+ if (type === "reversal") throw new ToolInputError(`A(z) ${number} sztornó számla, nem sztornózható.`);
1124
+ if (type === "proforma") throw new ToolInputError(`A(z) ${number} díjbekérő, nem sztornózható. Díjbekérőt a Számlázz.hu felületén vagy a kassza deleteProforma függvényével lehet törölni.`);
1125
+ if (type === "deliveryNote") throw new ToolInputError(`A(z) ${number} szállítólevél, nem sztornózható.`);
1126
+ }
1127
+ function assertReversibleReceipt(receipt) {
1128
+ if (receipt.type === "reversal") throw new ToolInputError(`A(z) ${receipt.number} sztornónyugta, nem sztornózható.`);
1129
+ }
1130
+ async function previewInvoiceReversal(number, context) {
1131
+ const details = await context.client().invoices.get(number, { includePdf: false });
1132
+ assertReversibleInvoice(details);
1133
+ if (details.header.reversed === true) throw new ToolInputError(`A(z) ${number} számlát már sztornózták.`);
1134
+ const confirmation = await context.confirmations.issue(REVERSE_INVOICE, { invoiceNumber: number });
1135
+ const currency = details.header.currency ?? "HUF";
1136
+ return {
1137
+ summary: lines(`Sztornó előnézete (még NEM készült el): a(z) ${number} számla sztornózása. Vevő: ${details.buyer.name}, bruttó ${money(details.totals.grossAmount, currency)}, kelt: ${details.header.issueDate}.`, `Mutasd meg a felhasználónak. Ha jóváhagyja, hívd meg a ${REVERSE_INVOICE} eszközt az invoiceNumber mezőben a számlaszámmal, a confirmation mezőben ezzel a kóddal: ${confirmation.token} (lejár: ${confirmation.expiresAt}).`),
1138
+ data: {
1139
+ document: "invoice",
1140
+ number,
1141
+ buyer: details.buyer.name,
1142
+ issueDate: details.header.issueDate,
1143
+ grossTotal: details.totals.grossAmount,
1144
+ currency,
1145
+ confirmation: confirmation.token,
1146
+ confirmationExpiresAt: confirmation.expiresAt
1147
+ }
1148
+ };
1149
+ }
1150
+ async function previewReceiptReversal(number, context) {
1151
+ const receipt = await context.client().receipts.get({
1152
+ receiptNumber: number,
1153
+ downloadPdf: false
1154
+ });
1155
+ assertReversibleReceipt(receipt);
1156
+ if (receipt.isReversed) throw new ToolInputError(`A(z) ${number} nyugtát már sztornózták.`);
1157
+ const confirmation = await context.confirmations.issue(REVERSE_RECEIPT, { receiptNumber: number });
1158
+ return {
1159
+ summary: lines(`Sztornó előnézete (még NEM készült el): a(z) ${number} nyugta sztornózása, bruttó ${money(receipt.totals.grossAmount, receipt.currency)}, kelt: ${receipt.issueDate}.`, `Mutasd meg a felhasználónak. Ha jóváhagyja, hívd meg a ${REVERSE_RECEIPT} eszközt a receiptNumber mezőben a nyugtaszámmal, a confirmation mezőben ezzel a kóddal: ${confirmation.token} (lejár: ${confirmation.expiresAt}).`),
1160
+ data: {
1161
+ document: "receipt",
1162
+ number,
1163
+ issueDate: receipt.issueDate,
1164
+ grossTotal: receipt.totals.grossAmount,
1165
+ currency: receipt.currency,
1166
+ confirmation: confirmation.token,
1167
+ confirmationExpiresAt: confirmation.expiresAt
1168
+ }
1169
+ };
1170
+ }
1171
+ async function previewReversal(args, context) {
1172
+ assertKnownKeys(args, ["document", "number"], "");
1173
+ const document = optionalEnum(args, "document", "", DOCUMENT_KINDS);
1174
+ if (document === void 0) throw new ToolInputError("A document mező kötelező: invoice (számla) vagy receipt (nyugta).");
1175
+ const number = requiredString(args, "number", "");
1176
+ return document === "invoice" ? previewInvoiceReversal(number, context) : previewReceiptReversal(number, context);
1177
+ }
1178
+ function reversalOutput(document, reversedNumber, number, created) {
1179
+ const label = document === "invoice" ? "számla" : "nyugta";
1180
+ return {
1181
+ summary: created ? `A(z) ${reversedNumber} ${label} sztornózva${number === void 0 ? "" : `, sztornó: ${number}`}.` : `A(z) ${reversedNumber} ${label} már sztornózva volt${number === void 0 ? "" : ` (sztornó: ${number})`}, nem sztornóztam újra.`,
1182
+ data: {
1183
+ created,
1184
+ document,
1185
+ reversedNumber,
1186
+ number
1187
+ }
1188
+ };
1189
+ }
1190
+ async function reverseInvoice(args, context) {
1191
+ assertKnownKeys(args, ["invoiceNumber", "confirmation"], "");
1192
+ const invoiceNumber = requiredString(args, "invoiceNumber", "");
1193
+ await context.confirmations.verify(REVERSE_INVOICE, { invoiceNumber }, args.confirmation, PREVIEW_REVERSAL);
1194
+ const kassza = context.client();
1195
+ const externalId = `${invoiceNumber}/SS`;
1196
+ const lookup = () => kassza.invoices.find({ externalId }, { includePdf: false });
1197
+ const existing = await lookup();
1198
+ if (existing) return reversalOutput("invoice", invoiceNumber, existing.header.number, false);
1199
+ const original = await kassza.invoices.get(invoiceNumber, { includePdf: false });
1200
+ assertReversibleInvoice(original);
1201
+ if (original.header.reversed === true) return reversalOutput("invoice", invoiceNumber, void 0, false);
1202
+ try {
1203
+ return reversalOutput("invoice", invoiceNumber, (await kassza.invoices.reverse({
1204
+ invoiceNumber,
1205
+ externalId,
1206
+ downloadPdf: false
1207
+ })).number, true);
1208
+ } catch (error) {
1209
+ if (!require_issue.isUncertainOutcome(error)) throw error;
1210
+ const recovered = await require_issue.recoverAfterFailure(lookup, context.recoveryDelayMs, void 0);
1211
+ if (!recovered) throw error;
1212
+ return reversalOutput("invoice", invoiceNumber, recovered.header.number, error.category !== "duplicate");
1213
+ }
1214
+ }
1215
+ async function reverseReceipt(args, context) {
1216
+ assertKnownKeys(args, ["receiptNumber", "confirmation"], "");
1217
+ const receiptNumber = requiredString(args, "receiptNumber", "");
1218
+ await context.confirmations.verify(REVERSE_RECEIPT, { receiptNumber }, args.confirmation, PREVIEW_REVERSAL);
1219
+ const kassza = context.client();
1220
+ const original = await kassza.receipts.get({
1221
+ receiptNumber,
1222
+ downloadPdf: false
1223
+ });
1224
+ assertReversibleReceipt(original);
1225
+ if (original.isReversed) return reversalOutput("receipt", receiptNumber, void 0, false);
1226
+ try {
1227
+ return reversalOutput("receipt", receiptNumber, (await kassza.receipts.reverse({
1228
+ receiptNumber,
1229
+ callId: `${receiptNumber}/SN`,
1230
+ downloadPdf: false
1231
+ })).number, true);
1232
+ } catch (error) {
1233
+ if (!require_issue.isUncertainOutcome(error)) throw error;
1234
+ if (!(await kassza.receipts.get({
1235
+ receiptNumber,
1236
+ downloadPdf: false
1237
+ })).isReversed) throw error;
1238
+ return reversalOutput("receipt", receiptNumber, void 0, !(error.category === "duplicate" || error.message.includes(ALREADY_REVERSED_MESSAGE)));
1239
+ }
1240
+ }
1241
+ const REVERSAL_TOOLS = [
1242
+ {
1243
+ name: PREVIEW_REVERSAL,
1244
+ title: "Sztornó előnézete",
1245
+ description: "Lekéri a sztornózandó számlát vagy nyugtát, ellenőrzi, hogy sztornózható-e, és ad egy megerősítő kódot a reverse_invoice vagy reverse_receipt eszközhöz. Semmit nem sztornóz.",
1246
+ inputSchema: objectSchema({
1247
+ document: {
1248
+ type: "string",
1249
+ enum: [...DOCUMENT_KINDS],
1250
+ description: "invoice (számla) vagy receipt (nyugta)."
1251
+ },
1252
+ number: {
1253
+ ...TEXT_PROPERTY,
1254
+ description: "A számla- vagy nyugtaszám."
1255
+ }
1256
+ }, ["document", "number"]),
1257
+ annotations: REMOTE_READ,
1258
+ write: false,
1259
+ run: previewReversal
1260
+ },
1261
+ {
1262
+ name: REVERSE_INVOICE,
1263
+ title: "Számla sztornózása",
1264
+ description: "Sztornó számlát állít ki a megadott számlához. Csak a preview_reversal által adott megerősítő kóddal működik, és csak a felhasználó jóváhagyása után hívd. Egy számlát csak egyszer sztornóz.",
1265
+ inputSchema: objectSchema({
1266
+ invoiceNumber: TEXT_PROPERTY,
1267
+ confirmation: CONFIRMATION_PROPERTY
1268
+ }, ["invoiceNumber", "confirmation"]),
1269
+ annotations: REMOTE_REVERSE,
1270
+ write: true,
1271
+ run: reverseInvoice
1272
+ },
1273
+ {
1274
+ name: REVERSE_RECEIPT,
1275
+ title: "Nyugta sztornózása",
1276
+ description: "Sztornónyugtát állít ki a megadott nyugtához. Csak a preview_reversal által adott megerősítő kóddal működik, és csak a felhasználó jóváhagyása után hívd. Egy nyugtát csak egyszer sztornóz.",
1277
+ inputSchema: objectSchema({
1278
+ receiptNumber: TEXT_PROPERTY,
1279
+ confirmation: CONFIRMATION_PROPERTY
1280
+ }, ["receiptNumber", "confirmation"]),
1281
+ annotations: REMOTE_REVERSE,
1282
+ write: true,
1283
+ run: reverseReceipt
1284
+ }
1285
+ ];
1286
+ //#endregion
1287
+ //#region src/mcp/tools.ts
1288
+ const KASSZA_MCP_TOOLS = [
1289
+ ...INVOICE_TOOLS,
1290
+ ...RECEIPT_TOOLS,
1291
+ ...REVERSAL_TOOLS,
1292
+ ...LOOKUP_TOOLS
1293
+ ];
1294
+ //#endregion
1295
+ //#region src/mcp/server.ts
1296
+ const SERVER_INFO = {
1297
+ name: "kassza",
1298
+ title: "kassza: Számlázz.hu számlák és nyugták",
1299
+ version: KASSZA_VERSION
1300
+ };
1301
+ const LIST_TTL_MS = 36e5;
1302
+ const INSTRUCTIONS = [
1303
+ "A kassza a Számlázz.hu Számla Agenten keresztül állít ki és kérdez le számlákat és nyugtákat.",
1304
+ "Kiállítás vagy sztornó előtt mindig hívd meg a megfelelő előnézeti eszközt (preview_invoice, preview_receipt, preview_reversal), mutasd meg az eredményt a felhasználónak, és csak a kifejezett jóváhagyása után hívd az író eszközt a kapott confirmation kóddal.",
1305
+ "Az író eszközök csak akkor érhetők el, ha a szervert KASSZA_MCP_ALLOW_WRITE=1 beállítással indították. Próbához Számlázz.hu tesztfiókot ajánlunk."
1306
+ ].join(" ");
1307
+ const WRITE_DISABLED_MESSAGE = "Az írási eszközök ki vannak kapcsolva. A kiállításhoz és a sztornóhoz indítsd a szervert a KASSZA_MCP_ALLOW_WRITE=1 környezeti változóval (vagy a kassza mcp --allow-write kapcsolóval).";
1308
+ function describeError(error) {
1309
+ if (error instanceof ToolInputError) return error.message;
1310
+ if (require_errors.isSzamlazzError(error)) return error.hint ? `${error.message}\nTipp: ${error.hint}` : error.message;
1311
+ if (error instanceof Error) return `Váratlan hiba: ${error.message}`;
1312
+ return "Váratlan hiba történt.";
1313
+ }
1314
+ function modernVersionOf(params) {
1315
+ const meta = params._meta;
1316
+ if (!isJsonObject(meta) || !("io.modelcontextprotocol/protocolVersion" in meta)) return void 0;
1317
+ const version = meta[META_PROTOCOL_VERSION];
1318
+ if (typeof version !== "string" || version.trim() === "") throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, `A _meta["${META_PROTOCOL_VERSION}"] mezőnek nem üres szövegnek kell lennie.`);
1319
+ if (!MCP_MODERN_VERSIONS.includes(version)) throw new McpProtocolError(MCP_UNSUPPORTED_PROTOCOL_VERSION, "Unsupported protocol version", { data: {
1320
+ supported: [...MCP_SUPPORTED_VERSIONS],
1321
+ requested: version
1322
+ } });
1323
+ if (!isJsonObject(meta["io.modelcontextprotocol/clientCapabilities"])) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, `Hiányzik a kötelező _meta["${META_CLIENT_CAPABILITIES}"] mező.`);
1324
+ return version;
1325
+ }
1326
+ function toolDefinition(tool) {
1327
+ return {
1328
+ name: tool.name,
1329
+ title: tool.title,
1330
+ description: tool.description,
1331
+ inputSchema: tool.inputSchema,
1332
+ annotations: {
1333
+ title: tool.title,
1334
+ ...tool.annotations
1335
+ }
1336
+ };
1337
+ }
1338
+ function createKasszaMcpServer(options = {}) {
1339
+ const allowWrite = options.allowWrite === true;
1340
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
1341
+ const recoveryDelayMs = require_issue.resolveRecoveryDelay(options.recoveryDelayMs ?? 1e3);
1342
+ const confirmations = createConfirmations({
1343
+ secret: options.confirmationSecret,
1344
+ ttlMs: options.confirmationTtlMs,
1345
+ now
1346
+ });
1347
+ let client;
1348
+ const context = {
1349
+ client: () => {
1350
+ client ??= require_client.createKassza(options);
1351
+ return client;
1352
+ },
1353
+ defaults: options.defaults ?? {},
1354
+ confirmations,
1355
+ now,
1356
+ recoveryDelayMs
1357
+ };
1358
+ const visibleTools = KASSZA_MCP_TOOLS.filter((tool) => allowWrite || !tool.write);
1359
+ const listTools = (params) => {
1360
+ if (params.cursor !== void 0) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, "Érvénytelen cursor: az eszközlista egyetlen oldalból áll.");
1361
+ return { tools: visibleTools.map(toolDefinition) };
1362
+ };
1363
+ const callTool = async (params) => {
1364
+ const name = params.name;
1365
+ if (typeof name !== "string") throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, "Hiányzik az eszköz neve (name).");
1366
+ const tool = KASSZA_MCP_TOOLS.find((candidate) => candidate.name === name);
1367
+ if (!tool) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, `Ismeretlen eszköz: ${name}`);
1368
+ const args = params.arguments ?? {};
1369
+ if (!isJsonObject(args)) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, "Az arguments mezőnek objektumnak kell lennie.");
1370
+ if (tool.write && !allowWrite) return {
1371
+ content: [{
1372
+ type: "text",
1373
+ text: WRITE_DISABLED_MESSAGE
1374
+ }],
1375
+ isError: true
1376
+ };
1377
+ try {
1378
+ const output = await tool.run(args, context);
1379
+ const data = plainJson(output.data);
1380
+ return {
1381
+ content: [{
1382
+ type: "text",
1383
+ text: output.summary
1384
+ }, {
1385
+ type: "text",
1386
+ text: JSON.stringify(data, null, 2)
1387
+ }],
1388
+ structuredContent: data,
1389
+ isError: false
1390
+ };
1391
+ } catch (error) {
1392
+ return {
1393
+ content: [{
1394
+ type: "text",
1395
+ text: describeError(error)
1396
+ }],
1397
+ isError: true
1398
+ };
1399
+ }
1400
+ };
1401
+ const modern = async (request) => {
1402
+ const meta = { [META_SERVER_INFO]: SERVER_INFO };
1403
+ switch (request.method) {
1404
+ case "server/discover": return {
1405
+ resultType: "complete",
1406
+ supportedVersions: [...MCP_SUPPORTED_VERSIONS],
1407
+ capabilities: { tools: {} },
1408
+ instructions: INSTRUCTIONS,
1409
+ ttlMs: LIST_TTL_MS,
1410
+ cacheScope: "private",
1411
+ _meta: meta
1412
+ };
1413
+ case "tools/list": return {
1414
+ resultType: "complete",
1415
+ ...listTools(request.params),
1416
+ ttlMs: LIST_TTL_MS,
1417
+ cacheScope: "private",
1418
+ _meta: meta
1419
+ };
1420
+ case "tools/call": return {
1421
+ resultType: "complete",
1422
+ ...await callTool(request.params),
1423
+ _meta: meta
1424
+ };
1425
+ default: throw new McpProtocolError(JSON_RPC_METHOD_NOT_FOUND, `Ismeretlen metódus: ${request.method}`);
1426
+ }
1427
+ };
1428
+ const initialize = (request, session) => {
1429
+ const requested = request.params.protocolVersion;
1430
+ if (typeof requested !== "string") throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, "Hiányzik a protocolVersion mező.");
1431
+ const version = MCP_LEGACY_VERSIONS.includes(requested) ? requested : MCP_LEGACY_VERSIONS[0] ?? requested;
1432
+ session.legacyVersion = version;
1433
+ return {
1434
+ protocolVersion: version,
1435
+ capabilities: { tools: { listChanged: false } },
1436
+ serverInfo: SERVER_INFO,
1437
+ instructions: INSTRUCTIONS
1438
+ };
1439
+ };
1440
+ const legacy = async (request, session) => {
1441
+ if (request.method === "ping") return {};
1442
+ if (session.legacyVersion === void 0) throw new McpProtocolError(JSON_RPC_INVALID_PARAMS, `Hiányzik a kötelező _meta["${META_PROTOCOL_VERSION}"] mező. 2026-07-28 előtti protokollnál előbb initialize kérést kell küldeni.`);
1443
+ if (request.method === "tools/list") return listTools(request.params);
1444
+ if (request.method === "tools/call") return callTool(request.params);
1445
+ throw new McpProtocolError(JSON_RPC_METHOD_NOT_FOUND, `Ismeretlen metódus: ${request.method}`);
1446
+ };
1447
+ const respond = async (request, session) => {
1448
+ try {
1449
+ if (request.method === "initialize") return success(request.id, initialize(request, session));
1450
+ const result = modernVersionOf(request.params) === void 0 ? await legacy(request, session) : await modern(request);
1451
+ return success(request.id, result);
1452
+ } catch (error) {
1453
+ if (error instanceof McpProtocolError) return failure(request.id, error.code, error.message, error.data);
1454
+ return failure(request.id, JSON_RPC_INTERNAL_ERROR, "Belső hiba a kassza MCP szerverben.");
1455
+ }
1456
+ };
1457
+ const handleSingle = async (message, session) => {
1458
+ try {
1459
+ const parsed = parseMcpMessage(message);
1460
+ if (parsed.kind !== "request") return void 0;
1461
+ return await respond(parsed, session);
1462
+ } catch (error) {
1463
+ if (error instanceof McpProtocolError) return protocolFailure(error);
1464
+ return failure(null, JSON_RPC_INTERNAL_ERROR, "Belső hiba a kassza MCP szerverben.");
1465
+ }
1466
+ };
1467
+ return {
1468
+ tools: KASSZA_MCP_TOOLS.map((tool) => ({
1469
+ name: tool.name,
1470
+ title: tool.title,
1471
+ write: tool.write
1472
+ })),
1473
+ connect() {
1474
+ const session = { legacyVersion: void 0 };
1475
+ const handle = async (message) => {
1476
+ if (!Array.isArray(message)) return handleSingle(message, session);
1477
+ if (message.length === 0) return failure(null, JSON_RPC_INVALID_REQUEST, "Az üres batch érvénytelen.");
1478
+ const responses = [];
1479
+ for (const entry of message) {
1480
+ const response = await handleSingle(entry, session);
1481
+ if (response) responses.push(response);
1482
+ }
1483
+ return responses.length === 0 ? void 0 : responses;
1484
+ };
1485
+ return {
1486
+ handle,
1487
+ async handleLine(line) {
1488
+ const trimmed = line.trim();
1489
+ if (trimmed === "") return void 0;
1490
+ let message;
1491
+ try {
1492
+ message = JSON.parse(trimmed);
1493
+ } catch {
1494
+ return JSON.stringify(failure(null, JSON_RPC_PARSE_ERROR, "Érvénytelen JSON."));
1495
+ }
1496
+ const response = await handle(message);
1497
+ return response === void 0 ? void 0 : JSON.stringify(response);
1498
+ }
1499
+ };
1500
+ }
1501
+ };
1502
+ }
1503
+ //#endregion
1504
+ Object.defineProperty(exports, "DEFAULT_CONFIRMATION_TTL_MS", {
1505
+ enumerable: true,
1506
+ get: function() {
1507
+ return DEFAULT_CONFIRMATION_TTL_MS;
1508
+ }
1509
+ });
1510
+ Object.defineProperty(exports, "KASSZA_VERSION", {
1511
+ enumerable: true,
1512
+ get: function() {
1513
+ return KASSZA_VERSION;
1514
+ }
1515
+ });
1516
+ Object.defineProperty(exports, "MCP_LEGACY_VERSIONS", {
1517
+ enumerable: true,
1518
+ get: function() {
1519
+ return MCP_LEGACY_VERSIONS;
1520
+ }
1521
+ });
1522
+ Object.defineProperty(exports, "MCP_MODERN_VERSIONS", {
1523
+ enumerable: true,
1524
+ get: function() {
1525
+ return MCP_MODERN_VERSIONS;
1526
+ }
1527
+ });
1528
+ Object.defineProperty(exports, "MCP_SUPPORTED_VERSIONS", {
1529
+ enumerable: true,
1530
+ get: function() {
1531
+ return MCP_SUPPORTED_VERSIONS;
1532
+ }
1533
+ });
1534
+ Object.defineProperty(exports, "ToolInputError", {
1535
+ enumerable: true,
1536
+ get: function() {
1537
+ return ToolInputError;
1538
+ }
1539
+ });
1540
+ Object.defineProperty(exports, "canonicalJson", {
1541
+ enumerable: true,
1542
+ get: function() {
1543
+ return canonicalJson;
1544
+ }
1545
+ });
1546
+ Object.defineProperty(exports, "createConfirmations", {
1547
+ enumerable: true,
1548
+ get: function() {
1549
+ return createConfirmations;
1550
+ }
1551
+ });
1552
+ Object.defineProperty(exports, "createKasszaMcpServer", {
1553
+ enumerable: true,
1554
+ get: function() {
1555
+ return createKasszaMcpServer;
1556
+ }
1557
+ });