@useyona/einvoice-mcp 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +201 -2
- package/bin/cli.js +2 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +73 -0
- package/dist/cli.js.map +1 -0
- package/dist/http.d.ts +16 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +41 -0
- package/dist/http.js.map +1 -0
- package/dist/idempotency.d.ts +16 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +31 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +5 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +72 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +16 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +65 -0
- package/dist/resources.js.map +1 -0
- package/dist/result.d.ts +42 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +83 -0
- package/dist/result.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +68 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/index.d.ts +34 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +284 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/schemas.d.ts +877 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +192 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +82 -4
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CODE_LIST_OF = exports.RESOURCE_URIS = void 0;
|
|
4
|
+
exports.registerResources = registerResources;
|
|
5
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
const einvoice_js_1 = require("@useyona/einvoice-js");
|
|
8
|
+
const result_1 = require("./result");
|
|
9
|
+
const tools_1 = require("./tools");
|
|
10
|
+
/** The resource URIs this server serves. */
|
|
11
|
+
exports.RESOURCE_URIS = {
|
|
12
|
+
taxCategories: 'yona://reference/tax-categories',
|
|
13
|
+
units: 'yona://reference/units',
|
|
14
|
+
hsCodes: 'yona://reference/hs-codes',
|
|
15
|
+
organization: 'yona://organization',
|
|
16
|
+
};
|
|
17
|
+
/** The jurisdiction's code-list type behind each reference resource (`reference.getResource`). */
|
|
18
|
+
exports.CODE_LIST_OF = {
|
|
19
|
+
[exports.RESOURCE_URIS.taxCategories]: 'tax-categories',
|
|
20
|
+
[exports.RESOURCE_URIS.units]: 'invoice-quantity-codes',
|
|
21
|
+
};
|
|
22
|
+
function json(uri, mode, data) {
|
|
23
|
+
return { contents: [{ uri, mimeType: 'application/json', text: (0, result_1.redact)(JSON.stringify({ mode, data: (0, result_1.compact)(data) }, null, 2)) }] };
|
|
24
|
+
}
|
|
25
|
+
/** An SDK failure as an MCP error: the code, the message and the request id, never a key or token. */
|
|
26
|
+
function asMcpError(error) {
|
|
27
|
+
if (error instanceof einvoice_js_1.EInvoiceApiError) {
|
|
28
|
+
const parts = [error.errorCode, error.message, error.requestId ? `requestId ${error.requestId}` : undefined];
|
|
29
|
+
return new types_js_1.McpError(types_js_1.ErrorCode.InternalError, (0, result_1.redact)(parts.filter(Boolean).join(' — ')));
|
|
30
|
+
}
|
|
31
|
+
return new types_js_1.McpError(types_js_1.ErrorCode.InternalError, (0, result_1.redact)(error?.message ?? String(error)));
|
|
32
|
+
}
|
|
33
|
+
async function guarded(read) {
|
|
34
|
+
try {
|
|
35
|
+
return await read();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw asMcpError(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function registerResources(server, client) {
|
|
42
|
+
for (const [uri, type] of Object.entries(exports.CODE_LIST_OF)) {
|
|
43
|
+
const units = type === 'invoice-quantity-codes';
|
|
44
|
+
server.registerResource(units ? 'units' : 'tax-categories', uri, {
|
|
45
|
+
title: units ? 'Units of measure' : 'Tax categories',
|
|
46
|
+
description: units
|
|
47
|
+
? 'The unit codes an invoice line or item may use (unitCode), e.g. EA.'
|
|
48
|
+
: 'The tax category ids a line or item may use (taxCategory), e.g. STANDARD_VAT, with their rates.',
|
|
49
|
+
mimeType: 'application/json',
|
|
50
|
+
}, (resourceUri, extra) => guarded(async () => json(resourceUri.href, client.mode, await client.reference.getResource(type, { signal: extra.signal }))));
|
|
51
|
+
}
|
|
52
|
+
const readHsCodes = (href, q, signal) => guarded(async () => {
|
|
53
|
+
const result = await client.reference.listHsCodes({ search: q || undefined, limit: 50 }, { signal });
|
|
54
|
+
return json(href, client.mode, { items: result.data, pagination: result.pagination });
|
|
55
|
+
});
|
|
56
|
+
const hsDescription = 'Harmonised System codes for goods (hsnCode). Add ?q=<words> to search, e.g. yona://reference/hs-codes?q=laptop. First 50 matches.';
|
|
57
|
+
server.registerResource('hs-codes', exports.RESOURCE_URIS.hsCodes, { title: 'HS codes', description: hsDescription, mimeType: 'application/json' }, (resourceUri, extra) => readHsCodes(resourceUri.href, undefined, extra.signal));
|
|
58
|
+
server.registerResource('hs-codes-search', new mcp_js_1.ResourceTemplate(`${exports.RESOURCE_URIS.hsCodes}{?q}`, { list: undefined }), { title: 'HS code search', description: hsDescription, mimeType: 'application/json' }, (resourceUri, variables, extra) => readHsCodes(resourceUri.href, Array.isArray(variables.q) ? variables.q[0] : variables.q, extra.signal));
|
|
59
|
+
server.registerResource('organization', exports.RESOURCE_URIS.organization, {
|
|
60
|
+
title: 'Organisation',
|
|
61
|
+
description: 'The organisation the API key belongs to: profile and readiness to report invoices.',
|
|
62
|
+
mimeType: 'application/json',
|
|
63
|
+
}, (resourceUri, extra) => guarded(async () => json(resourceUri.href, client.mode, await (0, tools_1.readOrganization)(client, { signal: extra.signal }))));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import type { ApiMode } from '@useyona/einvoice-js';
|
|
3
|
+
/** Replaces anything that looks like a key or token with `[redacted]`. */
|
|
4
|
+
export declare function redact(text: string): string;
|
|
5
|
+
/** Drops `null` and `undefined` fields recursively, so a model reads what is set. */
|
|
6
|
+
export declare function compact<T>(value: T): T;
|
|
7
|
+
/** The JSON a tool returns: the key's mode, the data, and the request id when the SDK exposes it. */
|
|
8
|
+
export interface ToolPayload {
|
|
9
|
+
mode: ApiMode;
|
|
10
|
+
data?: unknown;
|
|
11
|
+
requestId?: string;
|
|
12
|
+
note?: string;
|
|
13
|
+
}
|
|
14
|
+
/** A successful tool result. */
|
|
15
|
+
export declare function ok(mode: ApiMode, data: unknown, extra?: {
|
|
16
|
+
requestId?: string;
|
|
17
|
+
note?: string;
|
|
18
|
+
}): CallToolResult;
|
|
19
|
+
/** What a model sees of a refused call: the code, the message and the request id, never a key or token. */
|
|
20
|
+
export interface ToolErrorPayload {
|
|
21
|
+
mode: ApiMode;
|
|
22
|
+
error: {
|
|
23
|
+
errorCode?: string;
|
|
24
|
+
status?: number;
|
|
25
|
+
message: string;
|
|
26
|
+
requestId?: string;
|
|
27
|
+
/** Field-level reasons (`field`, `message`), so a model can correct its input. */
|
|
28
|
+
errors?: Array<{
|
|
29
|
+
field: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}>;
|
|
32
|
+
retryAfter?: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Maps any thrown value to a tool error result. */
|
|
36
|
+
export declare function fail(mode: ApiMode, error: unknown): CallToolResult;
|
|
37
|
+
/** A refusal decided by the MCP server itself (not the API), e.g. a destructive call without `confirm`. */
|
|
38
|
+
export declare class ToolRefusal extends Error {
|
|
39
|
+
readonly code: string;
|
|
40
|
+
constructor(code: string, message: string);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oCAAoC,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAC;AAalD,0EAA0E;AAC1E,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3C;AAED,qFAAqF;AACrF,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAWtC;AAED,qGAAqG;AACrG,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gCAAgC;AAChC,wBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,GAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAM,GAAG,cAAc,CAIhH;AAED,2GAA2G;AAC3G,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,kFAAkF;QAClF,MAAM,CAAC,EAAE,KAAK,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAC,CAAC,CAAC;QACjD,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACL;AAED,oDAAoD;AACpD,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,cAAc,CAoBlE;AAED,2GAA2G;AAC3G,qBAAa,WAAY,SAAQ,KAAK;aACN,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI5D"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToolRefusal = void 0;
|
|
4
|
+
exports.redact = redact;
|
|
5
|
+
exports.compact = compact;
|
|
6
|
+
exports.ok = ok;
|
|
7
|
+
exports.fail = fail;
|
|
8
|
+
const einvoice_js_1 = require("@useyona/einvoice-js");
|
|
9
|
+
/**
|
|
10
|
+
* Anything that looks like a credential: an API key, a bearer token, a JWT. Every text the server
|
|
11
|
+
* returns passes through {@link redact}, so a value that slipped into an upstream message is never
|
|
12
|
+
* shown to the model.
|
|
13
|
+
*/
|
|
14
|
+
const SECRET_PATTERNS = [
|
|
15
|
+
/sk_(?:test|live)_[A-Za-z0-9_-]+/g,
|
|
16
|
+
/Bearer\s+[A-Za-z0-9._~+/=-]+/gi,
|
|
17
|
+
/eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]*/g,
|
|
18
|
+
];
|
|
19
|
+
/** Replaces anything that looks like a key or token with `[redacted]`. */
|
|
20
|
+
function redact(text) {
|
|
21
|
+
let out = text;
|
|
22
|
+
for (const pattern of SECRET_PATTERNS)
|
|
23
|
+
out = out.replace(pattern, '[redacted]');
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/** Drops `null` and `undefined` fields recursively, so a model reads what is set. */
|
|
27
|
+
function compact(value) {
|
|
28
|
+
if (Array.isArray(value))
|
|
29
|
+
return value.map((v) => compact(v));
|
|
30
|
+
if (value && typeof value === 'object' && !(value instanceof Date)) {
|
|
31
|
+
const out = {};
|
|
32
|
+
for (const [k, v] of Object.entries(value)) {
|
|
33
|
+
if (v === null || v === undefined)
|
|
34
|
+
continue;
|
|
35
|
+
out[k] = compact(v);
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/** A successful tool result. */
|
|
42
|
+
function ok(mode, data, extra = {}) {
|
|
43
|
+
const payload = { mode, ...(extra.note ? { note: extra.note } : {}), data: compact(data) };
|
|
44
|
+
if (extra.requestId)
|
|
45
|
+
payload.requestId = extra.requestId;
|
|
46
|
+
return { content: [{ type: 'text', text: redact(JSON.stringify(payload, null, 2)) }] };
|
|
47
|
+
}
|
|
48
|
+
/** Maps any thrown value to a tool error result. */
|
|
49
|
+
function fail(mode, error) {
|
|
50
|
+
let body;
|
|
51
|
+
if (error instanceof einvoice_js_1.EInvoiceApiError) {
|
|
52
|
+
body = {
|
|
53
|
+
errorCode: error.errorCode,
|
|
54
|
+
status: error.status,
|
|
55
|
+
message: error.message,
|
|
56
|
+
requestId: error.requestId,
|
|
57
|
+
...(error.errors.length ? { errors: error.errors.map((e) => ({ field: e.field, message: e.message })) } : {}),
|
|
58
|
+
...(error.retryAfter !== undefined ? { retryAfter: error.retryAfter } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else if (error instanceof einvoice_js_1.EInvoiceError) {
|
|
62
|
+
body = { errorCode: error.name, message: error.message };
|
|
63
|
+
}
|
|
64
|
+
else if (error instanceof ToolRefusal) {
|
|
65
|
+
body = { errorCode: error.code, message: error.message };
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
body = { message: `Unexpected error: ${error?.message ?? String(error)}` };
|
|
69
|
+
}
|
|
70
|
+
const payload = { mode, error: compact(body) };
|
|
71
|
+
return { isError: true, content: [{ type: 'text', text: redact(JSON.stringify(payload, null, 2)) }] };
|
|
72
|
+
}
|
|
73
|
+
/** A refusal decided by the MCP server itself (not the API), e.g. a destructive call without `confirm`. */
|
|
74
|
+
class ToolRefusal extends Error {
|
|
75
|
+
code;
|
|
76
|
+
constructor(code, message) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.code = code;
|
|
79
|
+
this.name = 'ToolRefusal';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.ToolRefusal = ToolRefusal;
|
|
83
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":";;;AAgBA,wBAIC;AAGD,0BAWC;AAWD,gBAIC;AAiBD,oBAoBC;AArFD,sDAAqE;AAGrE;;;;GAIG;AACH,MAAM,eAAe,GAAa;IAC9B,kCAAkC;IAClC,gCAAgC;IAChC,0DAA0D;CAC7D,CAAC;AAEF,0EAA0E;AAC1E,SAAgB,MAAM,CAAC,IAAY;IAC/B,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,OAAO,IAAI,eAAe;QAAE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,SAAgB,OAAO,CAAI,KAAQ;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAiB,CAAC;IAC9E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,EAAE,CAAC;QACjE,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAS;YAC5C,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,GAAQ,CAAC;IACpB,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAUD,gCAAgC;AAChC,SAAgB,EAAE,CAAC,IAAa,EAAE,IAAa,EAAE,QAA6C,EAAE;IAC5F,MAAM,OAAO,GAAgB,EAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAC,CAAC;IACpG,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACzD,OAAO,EAAC,OAAO,EAAE,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC;AACvF,CAAC;AAgBD,oDAAoD;AACpD,SAAgB,IAAI,CAAC,IAAa,EAAE,KAAc;IAC9C,IAAI,IAA+B,CAAC;IACpC,IAAI,KAAK,YAAY,8BAAgB,EAAE,CAAC;QACpC,IAAI,GAAG;YACH,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAC,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzG,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,UAAU,EAAE,KAAK,CAAC,UAAU,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACN,CAAC;SAAM,IAAI,KAAK,YAAY,2BAAa,EAAE,CAAC;QACxC,IAAI,GAAG,EAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAC,CAAC;IAC3D,CAAC;SAAM,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACtC,IAAI,GAAG,EAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACJ,IAAI,GAAG,EAAC,OAAO,EAAE,qBAAsB,KAAe,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,EAAC,CAAC;IACxF,CAAC;IACD,MAAM,OAAO,GAAqB,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,EAAC,CAAC;IAC/D,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC;AACtG,CAAC;AAED,2GAA2G;AAC3G,MAAa,WAAY,SAAQ,KAAK;IACN;IAA5B,YAA4B,IAAY,EAAE,OAAe;QACrD,KAAK,CAAC,OAAO,CAAC,CAAC;QADS,SAAI,GAAJ,IAAI,CAAQ;QAEpC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC9B,CAAC;CACJ;AALD,kCAKC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { EInvoice } from '@useyona/einvoice-js';
|
|
3
|
+
/** Options of {@link createYonaMcpServer}. */
|
|
4
|
+
export interface YonaMcpServerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The Yona API client. Locally it is `new EInvoice({ apiKey })`; a host that holds its own
|
|
7
|
+
* credentials builds it with a custom transport. Its `mode` is reported in every result.
|
|
8
|
+
*/
|
|
9
|
+
client: EInvoice;
|
|
10
|
+
/**
|
|
11
|
+
* Allow a live client. A live client is refused unless this is true: locally the binary sets it
|
|
12
|
+
* from `YONA_ALLOW_LIVE=true`, hosted from the `developers.mcp_live` flag.
|
|
13
|
+
*/
|
|
14
|
+
allowLive?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Thrown by {@link createYonaMcpServer} for a live client without `allowLive`. */
|
|
17
|
+
export declare class LiveModeRefusedError extends Error {
|
|
18
|
+
constructor();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Builds the Yona MCP server: the tools, resources and prompts of the spec, over the given client.
|
|
22
|
+
* Connect it to any transport (stdio, streamable HTTP). Throws {@link LiveModeRefusedError} for a
|
|
23
|
+
* live client unless `allowLive` is true.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createYonaMcpServer({ client, allowLive }: YonaMcpServerOptions): McpServer;
|
|
26
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAClE,OAAO,KAAK,EAAC,QAAQ,EAAiB,MAAM,sBAAsB,CAAC;AAQnE,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,MAAM,EAAE,QAAQ,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,mFAAmF;AACnF,qBAAa,oBAAqB,SAAQ,KAAK;;CAQ9C;AAYD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAC,MAAM,EAAE,SAAiB,EAAC,EAAE,oBAAoB,GAAG,SAAS,CAwChG"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LiveModeRefusedError = void 0;
|
|
4
|
+
exports.createYonaMcpServer = createYonaMcpServer;
|
|
5
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
|
+
const idempotency_1 = require("./idempotency");
|
|
7
|
+
const prompts_1 = require("./prompts");
|
|
8
|
+
const resources_1 = require("./resources");
|
|
9
|
+
const result_1 = require("./result");
|
|
10
|
+
const tools_1 = require("./tools");
|
|
11
|
+
const version_1 = require("./version");
|
|
12
|
+
/** Thrown by {@link createYonaMcpServer} for a live client without `allowLive`. */
|
|
13
|
+
class LiveModeRefusedError extends Error {
|
|
14
|
+
constructor() {
|
|
15
|
+
super('This is a live API key: live calls report real invoices to the tax authority and charge real credits. ' +
|
|
16
|
+
'Live mode is refused unless it is explicitly allowed (YONA_ALLOW_LIVE=true). Use a sandbox key (sk_test_…) to try things.');
|
|
17
|
+
this.name = 'LiveModeRefusedError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.LiveModeRefusedError = LiveModeRefusedError;
|
|
21
|
+
function instructions(mode) {
|
|
22
|
+
return [
|
|
23
|
+
`Yona e-invoicing (${mode} mode). Tools create buyers, items and invoices, validate them, and report them to the tax authority.`,
|
|
24
|
+
'Usual flow: get_organization → search_buyers / create_buyer → create_invoice (a draft) → validate_invoice → finalise_invoice → submit_invoice → get_submission_status.',
|
|
25
|
+
'submit_invoice, cancel_invoice and issue_credit_note cannot be undone and need confirm: true, which you set only after the user approved that exact action.',
|
|
26
|
+
'Every result carries "mode": in "live" mode a submission is a legal filing and spends real credits.',
|
|
27
|
+
'Reference data: yona://reference/tax-categories, yona://reference/units, yona://reference/hs-codes?q=…',
|
|
28
|
+
].join('\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds the Yona MCP server: the tools, resources and prompts of the spec, over the given client.
|
|
32
|
+
* Connect it to any transport (stdio, streamable HTTP). Throws {@link LiveModeRefusedError} for a
|
|
33
|
+
* live client unless `allowLive` is true.
|
|
34
|
+
*/
|
|
35
|
+
function createYonaMcpServer({ client, allowLive = false }) {
|
|
36
|
+
if (client.mode === 'live' && !allowLive)
|
|
37
|
+
throw new LiveModeRefusedError();
|
|
38
|
+
const mode = client.mode;
|
|
39
|
+
const server = new mcp_js_1.McpServer({ name: version_1.SERVER_NAME, version: version_1.VERSION }, { instructions: instructions(mode) });
|
|
40
|
+
for (const tool of tools_1.TOOLS) {
|
|
41
|
+
server.registerTool(tool.name, {
|
|
42
|
+
title: tool.title,
|
|
43
|
+
description: tool.description,
|
|
44
|
+
inputSchema: tool.inputSchema,
|
|
45
|
+
annotations: tool.annotations,
|
|
46
|
+
}, async (input, extra) => {
|
|
47
|
+
try {
|
|
48
|
+
const { confirm, ...args } = input;
|
|
49
|
+
if (tool.destructive && confirm !== true) {
|
|
50
|
+
throw new result_1.ToolRefusal('MCP_CONFIRM_REQUIRED', `${tool.name} cannot be undone. Ask the user to approve it, then call it again with confirm: true.`);
|
|
51
|
+
}
|
|
52
|
+
const options = { signal: extra.signal };
|
|
53
|
+
if (tool.keyed) {
|
|
54
|
+
options.idempotencyKey = (0, idempotency_1.deriveIdempotencyKey)(tool.name, { requestId: extra.requestId, sessionId: extra.sessionId }, args);
|
|
55
|
+
}
|
|
56
|
+
const out = await tool.run({ client, options }, args);
|
|
57
|
+
return (0, result_1.ok)(mode, out.data, { requestId: out.requestId, note: out.note });
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return (0, result_1.fail)(mode, error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
(0, resources_1.registerResources)(server, client);
|
|
65
|
+
(0, prompts_1.registerPrompts)(server, client);
|
|
66
|
+
return server;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;AAiDA,kDAwCC;AAzFD,oEAAkE;AAElE,+CAAmD;AACnD,uCAA0C;AAC1C,2CAA8C;AAC9C,qCAA+C;AAC/C,mCAA8B;AAC9B,uCAA+C;AAgB/C,mFAAmF;AACnF,MAAa,oBAAqB,SAAQ,KAAK;IAC3C;QACI,KAAK,CACD,wGAAwG;YACpG,2HAA2H,CAClI,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACvC,CAAC;CACJ;AARD,oDAQC;AAED,SAAS,YAAY,CAAC,IAAY;IAC9B,OAAO;QACH,qBAAqB,IAAI,uGAAuG;QAChI,wKAAwK;QACxK,6JAA6J;QAC7J,qGAAqG;QACrG,wGAAwG;KAC3G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,EAAC,MAAM,EAAE,SAAS,GAAG,KAAK,EAAuB;IACjF,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,oBAAoB,EAAE,CAAC;IAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAEzB,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC,EAAC,IAAI,EAAE,qBAAW,EAAE,OAAO,EAAE,iBAAO,EAAC,EAAE,EAAC,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,EAAC,CAAC,CAAC;IAExG,KAAK,MAAM,IAAI,IAAI,aAAK,EAAE,CAAC;QACvB,MAAM,CAAC,YAAY,CACf,IAAI,CAAC,IAAI,EACT;YACI,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAChC,EACD,KAAK,EAAE,KAA8B,EAAE,KAAK,EAAE,EAAE;YAC5C,IAAI,CAAC;gBACD,MAAM,EAAC,OAAO,EAAE,GAAG,IAAI,EAAC,GAAG,KAAK,CAAC;gBACjC,IAAI,IAAI,CAAC,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACvC,MAAM,IAAI,oBAAW,CACjB,sBAAsB,EACtB,GAAG,IAAI,CAAC,IAAI,uFAAuF,CACtG,CAAC;gBACN,CAAC;gBACD,MAAM,OAAO,GAAmB,EAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAC,CAAC;gBACvD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACb,OAAO,CAAC,cAAc,GAAG,IAAA,kCAAoB,EAAC,IAAI,CAAC,IAAI,EAAE,EAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAC,EAAE,IAAI,CAAC,CAAC;gBAC7H,CAAC;gBACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAC,MAAM,EAAE,OAAO,EAAC,EAAE,IAAI,CAAC,CAAC;gBACpD,OAAO,IAAA,WAAE,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAC,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAC,CAAC,CAAC;YAC1E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,OAAO,IAAA,aAAI,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7B,CAAC;QACL,CAAC,CACJ,CAAC;IACN,CAAC;IAED,IAAA,6BAAiB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAA,yBAAe,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import type { EInvoice, RequestOptions } from '@useyona/einvoice-js';
|
|
4
|
+
/** What a tool's handler receives besides its arguments. */
|
|
5
|
+
export interface ToolContext {
|
|
6
|
+
client: EInvoice;
|
|
7
|
+
/** Request options for every SDK call: the abort signal, and the derived `Idempotency-Key` on writes. */
|
|
8
|
+
options: RequestOptions;
|
|
9
|
+
}
|
|
10
|
+
/** What a tool's handler returns: the data and, when the SDK exposed it, the request id. */
|
|
11
|
+
export interface ToolOutput {
|
|
12
|
+
data: unknown;
|
|
13
|
+
requestId?: string;
|
|
14
|
+
note?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ToolDefinition {
|
|
17
|
+
name: string;
|
|
18
|
+
title: string;
|
|
19
|
+
/** Written for a model: what it does, when to use it, what it costs, what it cannot undo. */
|
|
20
|
+
description: string;
|
|
21
|
+
inputSchema: z.ZodRawShape;
|
|
22
|
+
annotations: ToolAnnotations;
|
|
23
|
+
/** The SDK methods the tool may call (`invoices.create`); the contract test checks each exists. */
|
|
24
|
+
sdk: readonly string[];
|
|
25
|
+
/** Requires `confirm: true` (and is annotated `destructiveHint: true`). */
|
|
26
|
+
destructive: boolean;
|
|
27
|
+
/** Sends a derived `Idempotency-Key` (writes, and charged calls the API keys). */
|
|
28
|
+
keyed: boolean;
|
|
29
|
+
run(ctx: ToolContext, args: any): Promise<ToolOutput>;
|
|
30
|
+
}
|
|
31
|
+
/** The organisation, its readiness and its profile; shared with the yona://organization resource. */
|
|
32
|
+
export declare function readOrganization(client: EInvoice, options: RequestOptions): Promise<unknown>;
|
|
33
|
+
export declare const TOOLS: readonly ToolDefinition[];
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAC,QAAQ,EAAQ,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAoBzE,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IACxB,MAAM,EAAE,QAAQ,CAAC;IACjB,yGAAyG;IACzG,OAAO,EAAE,cAAc,CAAC;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,mGAAmG;IACnG,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,2EAA2E;IAC3E,WAAW,EAAE,OAAO,CAAC;IACrB,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;IAEf,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACzD;AAqCD,qGAAqG;AACrG,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAKlG;AAED,eAAO,MAAM,KAAK,EAAE,SAAS,cAAc,EA4Q1C,CAAC"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOOLS = void 0;
|
|
4
|
+
exports.readOrganization = readOrganization;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const schemas_1 = require("./schemas");
|
|
7
|
+
const result_1 = require("../result");
|
|
8
|
+
const READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
9
|
+
/** A read that the API charges for (or that asks the tax authority): not read-only for a client's auto-approval. */
|
|
10
|
+
const CHARGED_READ = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true };
|
|
11
|
+
const WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
12
|
+
const DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true };
|
|
13
|
+
function define(def) {
|
|
14
|
+
const destructive = def.destructive ?? false;
|
|
15
|
+
return {
|
|
16
|
+
...def,
|
|
17
|
+
inputSchema: destructive ? { ...def.inputSchema, confirm: schemas_1.confirm } : def.inputSchema,
|
|
18
|
+
annotations: { title: def.title, ...def.annotations },
|
|
19
|
+
destructive,
|
|
20
|
+
keyed: def.keyed ?? false,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** A list answer as a model reads it. */
|
|
24
|
+
function page(result) {
|
|
25
|
+
return { data: { items: result.data, pagination: result.pagination }, requestId: result.requestId };
|
|
26
|
+
}
|
|
27
|
+
const DESTRUCTIVE_NOTE = ' Requires confirm: true. Before calling, show the user what will happen and get their explicit approval in the conversation.';
|
|
28
|
+
/** The organisation, its readiness and its profile; shared with the yona://organization resource. */
|
|
29
|
+
async function readOrganization(client, options) {
|
|
30
|
+
const readiness = await client.organization.getReadiness(options);
|
|
31
|
+
const account = await client.billing.accounts.getMine(undefined, options);
|
|
32
|
+
const organization = await client.organization.get(account.organizationId, options);
|
|
33
|
+
return { organization, readiness };
|
|
34
|
+
}
|
|
35
|
+
exports.TOOLS = [
|
|
36
|
+
define({
|
|
37
|
+
name: 'get_organization',
|
|
38
|
+
title: 'Get organisation',
|
|
39
|
+
description: 'The organisation the API key belongs to: its profile (name, tax id, address) and its readiness to report invoices (what onboarding step is next, whether live mode is enabled). Call this first to know who is invoicing and whether invoices can be submitted. Free.',
|
|
40
|
+
inputSchema: {},
|
|
41
|
+
annotations: READ,
|
|
42
|
+
sdk: ['organization.getReadiness', 'billing.accounts.getMine', 'organization.get'],
|
|
43
|
+
run: async ({ client, options }) => ({ data: await readOrganization(client, options) }),
|
|
44
|
+
}),
|
|
45
|
+
define({
|
|
46
|
+
name: 'lookup_tin',
|
|
47
|
+
title: 'Look up a tax id',
|
|
48
|
+
description: 'Looks up a tax id (TIN) with the tax authority and returns the registered name and whether it can receive e-invoices. Use it before creating a buyer or when the user is unsure of a TIN. Charged per lookup (refunded when the authority cannot answer).',
|
|
49
|
+
inputSchema: schemas_1.lookupTinFields,
|
|
50
|
+
annotations: CHARGED_READ,
|
|
51
|
+
sdk: ['reference.lookupTaxId'],
|
|
52
|
+
keyed: true,
|
|
53
|
+
run: async ({ client, options }, { taxId, type }) => ({
|
|
54
|
+
data: await client.reference.lookupTaxId(taxId, type ? { type } : undefined, options),
|
|
55
|
+
}),
|
|
56
|
+
}),
|
|
57
|
+
define({
|
|
58
|
+
name: 'search_buyers',
|
|
59
|
+
title: 'Search buyers',
|
|
60
|
+
description: 'Lists the organisation’s saved buyers (customers), optionally filtered by text or tax-id verification status. Use it to find a buyerId before creating an invoice, and before create_buyer to avoid duplicates. Free.',
|
|
61
|
+
inputSchema: schemas_1.searchBuyersFields,
|
|
62
|
+
annotations: READ,
|
|
63
|
+
sdk: ['buyers.list'],
|
|
64
|
+
run: async ({ client, options }, args) => page(await client.buyers.list(args, options)),
|
|
65
|
+
}),
|
|
66
|
+
define({
|
|
67
|
+
name: 'get_buyer',
|
|
68
|
+
title: 'Get a buyer',
|
|
69
|
+
description: 'One saved buyer by id, with its tax id, address and verification status. Free.',
|
|
70
|
+
inputSchema: { buyerId: (0, schemas_1.id)('buyer') },
|
|
71
|
+
annotations: READ,
|
|
72
|
+
sdk: ['buyers.get'],
|
|
73
|
+
run: async ({ client, options }, { buyerId }) => ({ data: await client.buyers.get(buyerId, options) }),
|
|
74
|
+
}),
|
|
75
|
+
define({
|
|
76
|
+
name: 'create_buyer',
|
|
77
|
+
title: 'Create a buyer',
|
|
78
|
+
description: 'Saves a new buyer (customer) to invoice. B2B and B2G invoices need a buyer with a tax id; search_buyers first to avoid a duplicate. Charged per buyer created.',
|
|
79
|
+
inputSchema: schemas_1.buyerFields,
|
|
80
|
+
annotations: WRITE,
|
|
81
|
+
sdk: ['buyers.create'],
|
|
82
|
+
keyed: true,
|
|
83
|
+
run: async ({ client, options }, args) => ({ data: await client.buyers.create(args, options) }),
|
|
84
|
+
}),
|
|
85
|
+
define({
|
|
86
|
+
name: 'search_items',
|
|
87
|
+
title: 'Search items',
|
|
88
|
+
description: 'Lists the organisation’s saved items (goods and services with their codes, unit, price and tax category). An invoice line that names an itemId takes all of these from the item. Free.',
|
|
89
|
+
inputSchema: schemas_1.searchItemsFields,
|
|
90
|
+
annotations: READ,
|
|
91
|
+
sdk: ['items.list'],
|
|
92
|
+
run: async ({ client, options }, args) => page(await client.items.list(args, options)),
|
|
93
|
+
}),
|
|
94
|
+
define({
|
|
95
|
+
name: 'create_item',
|
|
96
|
+
title: 'Create an item',
|
|
97
|
+
description: 'Saves a good or service for reuse on invoice lines. Goods need an HS code (yona://reference/hs-codes), services an ISIC service code. The price is in MINOR units (kobo). Free.',
|
|
98
|
+
inputSchema: schemas_1.itemFields,
|
|
99
|
+
annotations: WRITE,
|
|
100
|
+
sdk: ['items.create'],
|
|
101
|
+
keyed: true,
|
|
102
|
+
run: async ({ client, options }, args) => ({ data: await client.items.create(args, options) }),
|
|
103
|
+
}),
|
|
104
|
+
define({
|
|
105
|
+
name: 'list_invoices',
|
|
106
|
+
title: 'List invoices',
|
|
107
|
+
description: 'Lists invoices the organisation issued, newest first, filtered by status, reporting state, payment status (e.g. unpaid), buyer, date or text. Use it to find an invoiceId or to answer questions about what was invoiced. Free.',
|
|
108
|
+
inputSchema: schemas_1.listInvoicesFields,
|
|
109
|
+
annotations: READ,
|
|
110
|
+
sdk: ['invoices.list'],
|
|
111
|
+
run: async ({ client, options }, args) => page(await client.invoices.list(args, options)),
|
|
112
|
+
}),
|
|
113
|
+
define({
|
|
114
|
+
name: 'get_invoice',
|
|
115
|
+
title: 'Get an invoice',
|
|
116
|
+
description: 'One invoice by id: its lines, totals, status, buyer, seller and reporting state. Free.',
|
|
117
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice') },
|
|
118
|
+
annotations: READ,
|
|
119
|
+
sdk: ['invoices.get'],
|
|
120
|
+
run: async ({ client, options }, { invoiceId }) => ({ data: await client.invoices.get(invoiceId, options) }),
|
|
121
|
+
}),
|
|
122
|
+
define({
|
|
123
|
+
name: 'create_invoice',
|
|
124
|
+
title: 'Create a draft invoice',
|
|
125
|
+
description: 'Creates a DRAFT invoice. Nothing is reported to the tax authority until finalise_invoice and submit_invoice. Prefer lines with an itemId; otherwise give description, unitCode, unitPrice (major units) and taxCategory per line. Then call validate_invoice. Charged as one invoice creation.',
|
|
126
|
+
inputSchema: schemas_1.invoiceFields,
|
|
127
|
+
annotations: WRITE,
|
|
128
|
+
sdk: ['invoices.create'],
|
|
129
|
+
keyed: true,
|
|
130
|
+
run: async ({ client, options }, args) => ({ data: await client.invoices.create(args, options) }),
|
|
131
|
+
}),
|
|
132
|
+
define({
|
|
133
|
+
name: 'update_invoice',
|
|
134
|
+
title: 'Update a draft invoice',
|
|
135
|
+
description: 'Changes a DRAFT invoice; only the fields given change, and lineItems, when given, replaces every line. A finalised or submitted invoice cannot be updated. Free.',
|
|
136
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice'), ...schemas_1.updateInvoiceFields },
|
|
137
|
+
annotations: { ...WRITE, idempotentHint: true },
|
|
138
|
+
sdk: ['invoices.update'],
|
|
139
|
+
run: async ({ client, options }, { invoiceId, ...changes }) => ({
|
|
140
|
+
data: await client.invoices.update(invoiceId, changes, options),
|
|
141
|
+
}),
|
|
142
|
+
}),
|
|
143
|
+
define({
|
|
144
|
+
name: 'validate_invoice',
|
|
145
|
+
title: 'Validate an invoice',
|
|
146
|
+
description: 'Checks an invoice with the tax authority’s rules without storing or submitting anything: give an invoiceId (a stored draft) or the document fields. Answers whether it is valid and, if not, why. Call it before finalise_invoice. Charged per validation (refunded when the authority cannot answer).',
|
|
147
|
+
inputSchema: schemas_1.validateInvoiceFields,
|
|
148
|
+
annotations: CHARGED_READ,
|
|
149
|
+
sdk: ['reference.validateInvoice'],
|
|
150
|
+
keyed: true,
|
|
151
|
+
run: async ({ client, options }, args) => {
|
|
152
|
+
if (!args.invoiceId && !args.lineItems) {
|
|
153
|
+
throw new result_1.ToolRefusal('MCP_INPUT', 'Give an invoiceId, or the document fields with lineItems.');
|
|
154
|
+
}
|
|
155
|
+
return { data: await client.reference.validateInvoice(args, options) };
|
|
156
|
+
},
|
|
157
|
+
}),
|
|
158
|
+
define({
|
|
159
|
+
name: 'finalise_invoice',
|
|
160
|
+
title: 'Finalise an invoice',
|
|
161
|
+
description: 'Finalises a draft: freezes the seller and buyer onto it and checks it against the jurisdiction’s rules. After this the invoice can no longer be changed with update_invoice (this server has no tool to reopen it). It is not yet reported: submit_invoice does that. Free.',
|
|
162
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice') },
|
|
163
|
+
annotations: { ...WRITE, idempotentHint: true },
|
|
164
|
+
sdk: ['invoices.finalise'],
|
|
165
|
+
run: async ({ client, options }, { invoiceId }) => ({ data: await client.invoices.finalise(invoiceId, options) }),
|
|
166
|
+
}),
|
|
167
|
+
define({
|
|
168
|
+
name: 'submit_invoice',
|
|
169
|
+
title: 'Submit an invoice to the tax authority',
|
|
170
|
+
description: 'Reports a finalised invoice to the tax authority (in live mode this is a legal filing; in sandbox it goes to the authority’s test environment). Charges credits. It cannot be withdrawn: a reported invoice is corrected only by cancel_invoice or issue_credit_note. Submission is asynchronous: follow it with get_submission_status. finalise: true finalises a draft first.' +
|
|
171
|
+
DESTRUCTIVE_NOTE,
|
|
172
|
+
inputSchema: {
|
|
173
|
+
invoiceId: (0, schemas_1.id)('invoice'),
|
|
174
|
+
finalise: zod_1.z.boolean().optional().describe('true: finalise the draft first, then submit.'),
|
|
175
|
+
},
|
|
176
|
+
annotations: DESTRUCTIVE,
|
|
177
|
+
destructive: true,
|
|
178
|
+
sdk: ['submissions.submit'],
|
|
179
|
+
keyed: true,
|
|
180
|
+
run: async ({ client, options }, { invoiceId, finalise }) => ({
|
|
181
|
+
data: await client.submissions.submit(invoiceId, finalise ? { finalise: 'true' } : undefined, options),
|
|
182
|
+
}),
|
|
183
|
+
}),
|
|
184
|
+
define({
|
|
185
|
+
name: 'get_submission_status',
|
|
186
|
+
title: 'Get submission status',
|
|
187
|
+
description: 'Where an invoice’s report to the tax authority stands: queued, transmitted, accepted, rejected or parked, with the authority’s reference and, when it failed or parked, the reason. Poll it after submit_invoice. Free.',
|
|
188
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice') },
|
|
189
|
+
annotations: READ,
|
|
190
|
+
sdk: ['submissions.getStatus'],
|
|
191
|
+
run: async ({ client, options }, { invoiceId }) => ({ data: await client.submissions.getStatus(invoiceId, options) }),
|
|
192
|
+
}),
|
|
193
|
+
define({
|
|
194
|
+
name: 'cancel_invoice',
|
|
195
|
+
title: 'Cancel an invoice',
|
|
196
|
+
description: 'Cancels an issued invoice: voided when the tax authority does not hold it, otherwise reversed by a credit note reported to the authority. Cannot be undone. A draft cannot be cancelled (it is simply never submitted).' +
|
|
197
|
+
DESTRUCTIVE_NOTE,
|
|
198
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice'), reason: zod_1.z.string().min(1).describe('Why the invoice is cancelled.') },
|
|
199
|
+
annotations: DESTRUCTIVE,
|
|
200
|
+
destructive: true,
|
|
201
|
+
sdk: ['invoices.cancel'],
|
|
202
|
+
keyed: true,
|
|
203
|
+
run: async ({ client, options }, { invoiceId, reason }) => ({
|
|
204
|
+
data: await client.invoices.cancel(invoiceId, { reason }, options),
|
|
205
|
+
}),
|
|
206
|
+
}),
|
|
207
|
+
define({
|
|
208
|
+
name: 'issue_credit_note',
|
|
209
|
+
title: 'Issue a credit note',
|
|
210
|
+
description: 'Issues a credit note against a reported invoice, in full, for some lines, or for an amount; it is reported to the tax authority and charges credits. Cannot be undone. Use preview: true first to show the user the result without writing or charging anything.' +
|
|
211
|
+
DESTRUCTIVE_NOTE,
|
|
212
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice'), ...schemas_1.creditNoteFields },
|
|
213
|
+
annotations: DESTRUCTIVE,
|
|
214
|
+
destructive: true,
|
|
215
|
+
sdk: ['invoices.issueCreditNote'],
|
|
216
|
+
keyed: true,
|
|
217
|
+
run: async ({ client, options }, { invoiceId, ...body }) => ({
|
|
218
|
+
data: await client.invoices.issueCreditNote(invoiceId, body, options),
|
|
219
|
+
}),
|
|
220
|
+
}),
|
|
221
|
+
define({
|
|
222
|
+
name: 'get_download_link',
|
|
223
|
+
title: 'Get a PDF download link',
|
|
224
|
+
description: 'A short-lived link to the invoice PDF, to give the user. The link expires (see expiresAt). Charged as one download.',
|
|
225
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice') },
|
|
226
|
+
annotations: CHARGED_READ,
|
|
227
|
+
sdk: ['output.getDownloadLink'],
|
|
228
|
+
keyed: true,
|
|
229
|
+
run: async ({ client, options }, { invoiceId }) => ({ data: await client.output.getDownloadLink(invoiceId, options) }),
|
|
230
|
+
}),
|
|
231
|
+
define({
|
|
232
|
+
name: 'create_share_link',
|
|
233
|
+
title: 'Create a share link',
|
|
234
|
+
description: 'Creates a public, revocable link to view an invoice, to send to the buyer. Anyone with the link can view the invoice until it expires or reaches maxViews. Free.',
|
|
235
|
+
inputSchema: { invoiceId: (0, schemas_1.id)('invoice'), ...schemas_1.shareLinkFields },
|
|
236
|
+
annotations: WRITE,
|
|
237
|
+
sdk: ['shareLinks.create'],
|
|
238
|
+
run: async ({ client, options }, { invoiceId, ...body }) => ({
|
|
239
|
+
data: await client.shareLinks.create(invoiceId, body, options),
|
|
240
|
+
}),
|
|
241
|
+
}),
|
|
242
|
+
define({
|
|
243
|
+
name: 'list_received_invoices',
|
|
244
|
+
title: 'List received invoices',
|
|
245
|
+
description: 'Lists invoices other businesses issued TO the organisation and reported to the tax authority (purchases), filtered by seller, payment status, date or text. Free.',
|
|
246
|
+
inputSchema: schemas_1.listInboundFields,
|
|
247
|
+
annotations: READ,
|
|
248
|
+
sdk: ['inboundInvoices.list'],
|
|
249
|
+
run: async ({ client, options }, args) => {
|
|
250
|
+
const result = await client.inboundInvoices.list(args, options);
|
|
251
|
+
return { data: { ...result.data, pagination: result.pagination }, requestId: result.requestId };
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
define({
|
|
255
|
+
name: 'get_received_invoice',
|
|
256
|
+
title: 'Get a received invoice',
|
|
257
|
+
description: 'One received (purchase) invoice by id, with the seller and the document as the tax authority holds it. Free.',
|
|
258
|
+
inputSchema: { receivedInvoiceId: (0, schemas_1.id)('received invoice') },
|
|
259
|
+
annotations: READ,
|
|
260
|
+
sdk: ['inboundInvoices.get'],
|
|
261
|
+
run: async ({ client, options }, { receivedInvoiceId }) => ({
|
|
262
|
+
data: await client.inboundInvoices.get(receivedInvoiceId, options),
|
|
263
|
+
}),
|
|
264
|
+
}),
|
|
265
|
+
define({
|
|
266
|
+
name: 'get_balance',
|
|
267
|
+
title: 'Get credit balance',
|
|
268
|
+
description: 'The organisation’s credit balance for this key’s mode. Check it before charged actions (creating invoices or buyers, submitting, validating). Free.',
|
|
269
|
+
inputSchema: {},
|
|
270
|
+
annotations: READ,
|
|
271
|
+
sdk: ['billing.accounts.getMine'],
|
|
272
|
+
run: async ({ client, options }) => ({ data: await client.billing.accounts.getMine(undefined, options) }),
|
|
273
|
+
}),
|
|
274
|
+
define({
|
|
275
|
+
name: 'list_webhook_deliveries',
|
|
276
|
+
title: 'List webhook deliveries',
|
|
277
|
+
description: 'Lists the webhook deliveries Yona made to the organisation’s endpoints, by status, endpoint or event type, to debug an integration that missed an event. Free.',
|
|
278
|
+
inputSchema: schemas_1.listDeliveriesFields,
|
|
279
|
+
annotations: READ,
|
|
280
|
+
sdk: ['webhooks.deliveries.list'],
|
|
281
|
+
run: async ({ client, options }, args) => page(await client.webhooks.deliveries.list(args, options)),
|
|
282
|
+
}),
|
|
283
|
+
];
|
|
284
|
+
//# sourceMappingURL=index.js.map
|