@codemill-solutions/yuki-mcp 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -15
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/tools/accounting-info.d.ts +19 -0
- package/dist/tools/accounting-info.d.ts.map +1 -0
- package/dist/tools/accounting-info.js +366 -0
- package/dist/tools/accounting-info.js.map +1 -0
- package/dist/tools/accounting.d.ts +6 -0
- package/dist/tools/accounting.d.ts.map +1 -1
- package/dist/tools/accounting.js +121 -0
- package/dist/tools/accounting.js.map +1 -1
- package/dist/tools/administrations.d.ts +10 -0
- package/dist/tools/administrations.d.ts.map +1 -1
- package/dist/tools/administrations.js +46 -0
- package/dist/tools/administrations.js.map +1 -1
- package/dist/tools/documents.d.ts.map +1 -1
- package/dist/tools/documents.js +369 -0
- package/dist/tools/documents.js.map +1 -1
- package/dist/yuki-client.d.ts.map +1 -1
- package/dist/yuki-client.js +23 -3
- package/dist/yuki-client.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/accounting.js
CHANGED
|
@@ -80,6 +80,127 @@ export function registerAccountingTools(server, client) {
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Register additional accounting tools (fiscal variants and revenue).
|
|
85
|
+
* Called separately from registerAccountingTools so each can be exported
|
|
86
|
+
* and imported individually if needed.
|
|
87
|
+
*/
|
|
88
|
+
export function registerAccountingExtendedTools(server, client) {
|
|
89
|
+
// ── get_gl_accounts_fiscal ─────────────────────────────────────────────────
|
|
90
|
+
/**
|
|
91
|
+
* get_gl_accounts_fiscal
|
|
92
|
+
*
|
|
93
|
+
* Retrieve all GL accounts with their balance at a given date, *including*
|
|
94
|
+
* fiscal corrections (e.g. end-of-year accruals, depreciation entries posted
|
|
95
|
+
* after the commercial year-end).
|
|
96
|
+
*
|
|
97
|
+
* Use this instead of get_gl_accounts when you need a balance that matches
|
|
98
|
+
* Yuki's fiscal reporting view rather than the commercial/operational view.
|
|
99
|
+
*
|
|
100
|
+
* Rate cost: 1 request.
|
|
101
|
+
*/
|
|
102
|
+
server.registerTool('get_gl_accounts_fiscal', {
|
|
103
|
+
description: 'Retrieve all GL accounts with their balance including fiscal corrections (fiscale stand). ' +
|
|
104
|
+
'Use this for balance sheet and P&L views that must match Yuki fiscal reports. ' +
|
|
105
|
+
'For the commercial/operational view use get_gl_accounts instead.',
|
|
106
|
+
inputSchema: {
|
|
107
|
+
date: z
|
|
108
|
+
.string()
|
|
109
|
+
.optional()
|
|
110
|
+
.describe("Date for the balance snapshot in YYYY-MM-DD format. Defaults to today."),
|
|
111
|
+
administrationId: z
|
|
112
|
+
.string()
|
|
113
|
+
.optional()
|
|
114
|
+
.describe('Administration ID (GUID). Defaults to YUKI_DOMAIN_ID env var.'),
|
|
115
|
+
},
|
|
116
|
+
}, async ({ date, administrationId }) => {
|
|
117
|
+
try {
|
|
118
|
+
const adminId = administrationId ?? client.defaultDomainId;
|
|
119
|
+
if (!adminId)
|
|
120
|
+
throw new Error('administrationId is required (or set YUKI_DOMAIN_ID env var)');
|
|
121
|
+
const sessionID = await client.getSessionID();
|
|
122
|
+
const transactionDate = date ?? new Date().toISOString().split('T')[0];
|
|
123
|
+
const result = await client.callSoap({
|
|
124
|
+
service: 'Accounting.asmx',
|
|
125
|
+
method: 'GLAccountBalanceFiscal',
|
|
126
|
+
params: { sessionID, administrationID: adminId, transactionDate },
|
|
127
|
+
});
|
|
128
|
+
const accounts = normalizeGLAccounts(result);
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: 'text',
|
|
133
|
+
text: JSON.stringify({ success: true, count: accounts.length, balanceDate: transactionDate, fiscal: true, accounts }, null, 2),
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
142
|
+
isError: true,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// ── get_net_revenue ────────────────────────────────────────────────────────
|
|
147
|
+
/**
|
|
148
|
+
* get_net_revenue
|
|
149
|
+
*
|
|
150
|
+
* Retrieve the net revenue (netto-omzet) for an administration within a
|
|
151
|
+
* date range. Optionally includes fiscal corrections.
|
|
152
|
+
*
|
|
153
|
+
* Use this for revenue dashboards, period comparisons, and quick P&L checks
|
|
154
|
+
* without having to sum individual GL account balances manually.
|
|
155
|
+
*
|
|
156
|
+
* Rate cost: 1 request.
|
|
157
|
+
*/
|
|
158
|
+
server.registerTool('get_net_revenue', {
|
|
159
|
+
description: 'Retrieve net revenue (netto-omzet) for an administration within a date range. ' +
|
|
160
|
+
'Set fiscal=true to include fiscal corrections (matches Yuki fiscal reports).',
|
|
161
|
+
inputSchema: {
|
|
162
|
+
startDate: z.string().describe('Start date in YYYY-MM-DD format (inclusive)'),
|
|
163
|
+
endDate: z.string().describe('End date in YYYY-MM-DD format (inclusive)'),
|
|
164
|
+
fiscal: z
|
|
165
|
+
.boolean()
|
|
166
|
+
.optional()
|
|
167
|
+
.default(false)
|
|
168
|
+
.describe('Include fiscal corrections. Default false (commercial view).'),
|
|
169
|
+
administrationId: z
|
|
170
|
+
.string()
|
|
171
|
+
.optional()
|
|
172
|
+
.describe('Administration ID (GUID). Defaults to YUKI_DOMAIN_ID env var.'),
|
|
173
|
+
},
|
|
174
|
+
}, async ({ startDate, endDate, fiscal, administrationId }) => {
|
|
175
|
+
try {
|
|
176
|
+
const adminId = administrationId ?? client.defaultDomainId;
|
|
177
|
+
if (!adminId)
|
|
178
|
+
throw new Error('administrationId is required (or set YUKI_DOMAIN_ID env var)');
|
|
179
|
+
const sessionID = await client.getSessionID();
|
|
180
|
+
const method = fiscal ? 'NetRevenueFiscal' : 'NetRevenue';
|
|
181
|
+
const result = await client.callSoap({
|
|
182
|
+
service: 'Accounting.asmx',
|
|
183
|
+
method,
|
|
184
|
+
params: { sessionID, administrationID: adminId, StartDate: startDate, EndDate: endDate },
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
content: [
|
|
188
|
+
{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: JSON.stringify({ success: true, period: { startDate, endDate }, fiscal: fiscal ?? false, result }, null, 2),
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
197
|
+
return {
|
|
198
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
199
|
+
isError: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
83
204
|
/** Unwrap the parsed SOAP GL account balance result into a flat array. */
|
|
84
205
|
function normalizeGLAccounts(result) {
|
|
85
206
|
if (!result)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounting.js","sourceRoot":"","sources":["../../src/tools/accounting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"accounting.js","sourceRoot":"","sources":["../../src/tools/accounting.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,4 +11,14 @@ import { YukiClient } from '../yuki-client.js';
|
|
|
11
11
|
* Auth flow: Authenticate(accessKey) → sessionID → Administrations(sessionID)
|
|
12
12
|
*/
|
|
13
13
|
export declare function registerAdministrationTools(server: McpServer, client: YukiClient): void;
|
|
14
|
+
/**
|
|
15
|
+
* get_administration_id
|
|
16
|
+
*
|
|
17
|
+
* Look up an administration's GUID by its exact name.
|
|
18
|
+
* Useful when you know the administration name from the Yuki UI but don't
|
|
19
|
+
* have the GUID — avoids having to call get_administrations and scan the list.
|
|
20
|
+
*
|
|
21
|
+
* Rate cost: 1 request.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerAdministrationLookupTools(server: McpServer, client: YukiClient): void;
|
|
14
24
|
//# sourceMappingURL=administrations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"administrations.d.ts","sourceRoot":"","sources":["../../src/tools/administrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"administrations.d.ts","sourceRoot":"","sources":["../../src/tools/administrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAqDvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAyC7F"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
/**
|
|
2
3
|
* Register tools related to Yuki administrations.
|
|
3
4
|
*
|
|
@@ -55,6 +56,51 @@ export function registerAdministrationTools(server, client) {
|
|
|
55
56
|
}
|
|
56
57
|
});
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* get_administration_id
|
|
61
|
+
*
|
|
62
|
+
* Look up an administration's GUID by its exact name.
|
|
63
|
+
* Useful when you know the administration name from the Yuki UI but don't
|
|
64
|
+
* have the GUID — avoids having to call get_administrations and scan the list.
|
|
65
|
+
*
|
|
66
|
+
* Rate cost: 1 request.
|
|
67
|
+
*/
|
|
68
|
+
export function registerAdministrationLookupTools(server, client) {
|
|
69
|
+
server.registerTool('get_administration_id', {
|
|
70
|
+
description: 'Look up the GUID of a Yuki administration by its exact name. ' +
|
|
71
|
+
'Use this to resolve an administration name to the ID required by other tools. ' +
|
|
72
|
+
'For a full list of administrations and IDs use get_administrations.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
administrationName: z
|
|
75
|
+
.string()
|
|
76
|
+
.describe('Exact name of the administration as shown in Yuki (case-sensitive).'),
|
|
77
|
+
},
|
|
78
|
+
}, async ({ administrationName }) => {
|
|
79
|
+
try {
|
|
80
|
+
const sessionID = await client.getSessionID();
|
|
81
|
+
const result = await client.callSoap({
|
|
82
|
+
service: 'Accounting.asmx',
|
|
83
|
+
method: 'AdministrationID',
|
|
84
|
+
params: { sessionID, administrationName },
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: 'text',
|
|
90
|
+
text: JSON.stringify({ success: true, administrationName, administrationId: result }, null, 2),
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
58
104
|
/** Normalise the parsed SOAP result into a flat array of administration objects. */
|
|
59
105
|
function normalizeAdministrations(result) {
|
|
60
106
|
if (!result)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"administrations.js","sourceRoot":"","sources":["../../src/tools/administrations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"administrations.js","sourceRoot":"","sources":["../../src/tools/administrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA0rBjF"}
|
package/dist/tools/documents.js
CHANGED
|
@@ -219,6 +219,344 @@ export function registerDocumentTools(server, client) {
|
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
});
|
|
222
|
+
// ── list_documents ──────────────────────────────────────────────────────────
|
|
223
|
+
/**
|
|
224
|
+
* list_documents
|
|
225
|
+
*
|
|
226
|
+
* List documents stored in a specific archive folder.
|
|
227
|
+
* Session-scoped: no administrationID needed (determined by the API key / domain).
|
|
228
|
+
*
|
|
229
|
+
* WSDL signature (Archive.asmx · DocumentsInFolder):
|
|
230
|
+
* sessionID, folderID, sortOrder, startDate, endDate, numberOfRecords, startRecord
|
|
231
|
+
*
|
|
232
|
+
* Rate cost: 1 request.
|
|
233
|
+
*/
|
|
234
|
+
server.registerTool('list_documents', {
|
|
235
|
+
description: 'List documents in a Yuki archive folder. ' +
|
|
236
|
+
'Returns document IDs, file names, dates, and amounts. ' +
|
|
237
|
+
'Call get_document_folders first to find the correct folder ID. ' +
|
|
238
|
+
'Use the returned document ID with get_document or download_document.',
|
|
239
|
+
inputSchema: {
|
|
240
|
+
folderId: z
|
|
241
|
+
.number()
|
|
242
|
+
.int()
|
|
243
|
+
.describe('Archive folder ID. Use get_document_folders to list available folders.'),
|
|
244
|
+
sortOrder: z
|
|
245
|
+
.enum(['DocumentDateDesc', 'DocumentDateAsc', 'CreatedDesc', 'CreatedAsc', 'ModifiedDesc', 'ModifiedAsc', 'ContactNameAsc', 'ContactNameDesc'])
|
|
246
|
+
.optional()
|
|
247
|
+
.default('DocumentDateDesc')
|
|
248
|
+
.describe('Sort order for results.'),
|
|
249
|
+
startDate: z
|
|
250
|
+
.string()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe('Filter documents from this date (YYYY-MM-DD). Defaults to 2000-01-01.'),
|
|
253
|
+
endDate: z
|
|
254
|
+
.string()
|
|
255
|
+
.optional()
|
|
256
|
+
.describe('Filter documents up to this date (YYYY-MM-DD). Defaults to today.'),
|
|
257
|
+
numberOfRecords: z
|
|
258
|
+
.number()
|
|
259
|
+
.int()
|
|
260
|
+
.optional()
|
|
261
|
+
.default(50)
|
|
262
|
+
.describe('Maximum number of records to return (default 50).'),
|
|
263
|
+
startRecord: z
|
|
264
|
+
.number()
|
|
265
|
+
.int()
|
|
266
|
+
.optional()
|
|
267
|
+
.default(1)
|
|
268
|
+
.describe('1-based offset for pagination (default 1).'),
|
|
269
|
+
},
|
|
270
|
+
}, async ({ folderId, sortOrder, startDate, endDate, numberOfRecords, startRecord }) => {
|
|
271
|
+
try {
|
|
272
|
+
const sessionID = await client.getSessionID();
|
|
273
|
+
const start = startDate ? `${startDate}T00:00:00` : '0001-01-01T00:00:00';
|
|
274
|
+
const end = endDate ? `${endDate}T23:59:59` : `${new Date().toISOString().split('T')[0]}T23:59:59`;
|
|
275
|
+
const result = await client.callSoap({
|
|
276
|
+
service: 'Archive.asmx',
|
|
277
|
+
method: 'DocumentsInFolder',
|
|
278
|
+
params: {
|
|
279
|
+
sessionID,
|
|
280
|
+
folderID: folderId,
|
|
281
|
+
sortOrder: sortOrder ?? 'DocumentDateDesc',
|
|
282
|
+
startDate: start,
|
|
283
|
+
endDate: end,
|
|
284
|
+
numberOfRecords: numberOfRecords ?? 50,
|
|
285
|
+
startRecord: startRecord ?? 1,
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
const documents = normalizeDocuments(result);
|
|
289
|
+
return {
|
|
290
|
+
content: [
|
|
291
|
+
{
|
|
292
|
+
type: 'text',
|
|
293
|
+
text: JSON.stringify({ success: true, folderId, count: documents.length, documents }, null, 2),
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
300
|
+
return {
|
|
301
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
302
|
+
isError: true,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
// ── search_documents ────────────────────────────────────────────────────────
|
|
307
|
+
/**
|
|
308
|
+
* search_documents
|
|
309
|
+
*
|
|
310
|
+
* Search archived documents by text within a specific folder (and optionally tab).
|
|
311
|
+
* Session-scoped: no administrationID needed.
|
|
312
|
+
*
|
|
313
|
+
* WSDL signature (Archive.asmx · SearchDocuments):
|
|
314
|
+
* sessionID, searchOption, searchText, folderID, tabID,
|
|
315
|
+
* sortOrder, startDate, endDate, numberOfRecords, startRecord
|
|
316
|
+
*
|
|
317
|
+
* SearchOption values: All, Creator, Contact, Subject, Tag, Type
|
|
318
|
+
* tabID: obtain valid IDs via get_document_folders (tab IDs are folder-specific).
|
|
319
|
+
* Pass 0 to search all tabs within the folder.
|
|
320
|
+
*
|
|
321
|
+
* Rate cost: 1 request.
|
|
322
|
+
*/
|
|
323
|
+
server.registerTool('search_documents', {
|
|
324
|
+
description: 'Search for documents in a Yuki archive folder by text. ' +
|
|
325
|
+
'Call get_document_folders first to find the folderID. ' +
|
|
326
|
+
'searchOption filters which field to match: All (default), Contact, Subject, Tag, Creator, or Type. ' +
|
|
327
|
+
'tabID scopes the search to a folder tab — use 0 to search all tabs.',
|
|
328
|
+
inputSchema: {
|
|
329
|
+
searchText: z
|
|
330
|
+
.string()
|
|
331
|
+
.describe('Text to search for (e.g. supplier name, invoice number, subject).'),
|
|
332
|
+
folderId: z
|
|
333
|
+
.number()
|
|
334
|
+
.int()
|
|
335
|
+
.optional()
|
|
336
|
+
.default(-1)
|
|
337
|
+
.describe('Archive folder ID to search within. Use -1 to search all folders (default). Use get_document_folders to find specific folder IDs.'),
|
|
338
|
+
tabId: z
|
|
339
|
+
.number()
|
|
340
|
+
.int()
|
|
341
|
+
.optional()
|
|
342
|
+
.default(-1)
|
|
343
|
+
.describe('Tab ID within the folder. Use -1 to search all tabs (default).'),
|
|
344
|
+
searchOption: z
|
|
345
|
+
.enum(['All', 'Creator', 'Contact', 'Subject', 'Tag', 'Type'])
|
|
346
|
+
.optional()
|
|
347
|
+
.default('All')
|
|
348
|
+
.describe("Field to search in. 'All' searches across all fields (default)."),
|
|
349
|
+
sortOrder: z
|
|
350
|
+
.enum(['DocumentDateDesc', 'DocumentDateAsc', 'CreatedDesc', 'CreatedAsc', 'ModifiedDesc', 'ModifiedAsc', 'ContactNameAsc', 'ContactNameDesc'])
|
|
351
|
+
.optional()
|
|
352
|
+
.default('DocumentDateDesc')
|
|
353
|
+
.describe('Sort order for results.'),
|
|
354
|
+
startDate: z
|
|
355
|
+
.string()
|
|
356
|
+
.optional()
|
|
357
|
+
.describe('Filter documents from this date (YYYY-MM-DD). Defaults to 2000-01-01.'),
|
|
358
|
+
endDate: z
|
|
359
|
+
.string()
|
|
360
|
+
.optional()
|
|
361
|
+
.describe('Filter documents up to this date (YYYY-MM-DD). Defaults to today.'),
|
|
362
|
+
numberOfRecords: z
|
|
363
|
+
.number()
|
|
364
|
+
.int()
|
|
365
|
+
.optional()
|
|
366
|
+
.default(50)
|
|
367
|
+
.describe('Maximum number of records to return (default 50).'),
|
|
368
|
+
startRecord: z
|
|
369
|
+
.number()
|
|
370
|
+
.int()
|
|
371
|
+
.optional()
|
|
372
|
+
.default(1)
|
|
373
|
+
.describe('1-based offset for pagination (default 1).'),
|
|
374
|
+
},
|
|
375
|
+
}, async ({ searchText, folderId, tabId, searchOption, sortOrder, startDate, endDate, numberOfRecords, startRecord }) => {
|
|
376
|
+
try {
|
|
377
|
+
const sessionID = await client.getSessionID();
|
|
378
|
+
// Use '0001-01-01' as Yuki's sentinel for "all dates" (no date filter).
|
|
379
|
+
// Use -1 for folderID/tabID to search across all folders/tabs.
|
|
380
|
+
const start = startDate ? `${startDate}T00:00:00` : '0001-01-01T00:00:00';
|
|
381
|
+
const end = endDate ? `${endDate}T23:59:59` : `${new Date().toISOString().split('T')[0]}T23:59:59`;
|
|
382
|
+
const result = await client.callSoap({
|
|
383
|
+
service: 'Archive.asmx',
|
|
384
|
+
method: 'SearchDocuments',
|
|
385
|
+
params: {
|
|
386
|
+
sessionID,
|
|
387
|
+
searchOption: searchOption ?? 'All',
|
|
388
|
+
searchText,
|
|
389
|
+
folderID: folderId ?? -1,
|
|
390
|
+
tabID: tabId ?? -1,
|
|
391
|
+
sortOrder: sortOrder ?? 'DocumentDateDesc',
|
|
392
|
+
startDate: start,
|
|
393
|
+
endDate: end,
|
|
394
|
+
numberOfRecords: numberOfRecords ?? 50,
|
|
395
|
+
startRecord: startRecord ?? 1,
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
const documents = normalizeDocuments(result);
|
|
399
|
+
return {
|
|
400
|
+
content: [
|
|
401
|
+
{
|
|
402
|
+
type: 'text',
|
|
403
|
+
text: JSON.stringify({ success: true, searchText, folderId, count: documents.length, documents }, null, 2),
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
410
|
+
return {
|
|
411
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
412
|
+
isError: true,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
// ── get_document ────────────────────────────────────────────────────────────
|
|
417
|
+
/**
|
|
418
|
+
* get_document
|
|
419
|
+
*
|
|
420
|
+
* Retrieve metadata for a single archived document by its ID.
|
|
421
|
+
* Returns file name, folder, date, amount, status, and other metadata.
|
|
422
|
+
*
|
|
423
|
+
* Use list_documents or search_documents to find document IDs.
|
|
424
|
+
* To download the actual file content, use download_document.
|
|
425
|
+
*
|
|
426
|
+
* Rate cost: 1 request.
|
|
427
|
+
*/
|
|
428
|
+
server.registerTool('get_document', {
|
|
429
|
+
description: 'Retrieve metadata for a single archived document by its Yuki document ID. ' +
|
|
430
|
+
'Returns file name, folder, date, amount, and status. ' +
|
|
431
|
+
'Use list_documents or search_documents to find document IDs. ' +
|
|
432
|
+
'To download the file binary use download_document.',
|
|
433
|
+
inputSchema: {
|
|
434
|
+
documentId: z.string().describe('Yuki document ID (GUID or integer, from list_documents or search_documents).'),
|
|
435
|
+
administrationId: z
|
|
436
|
+
.string()
|
|
437
|
+
.optional()
|
|
438
|
+
.describe('Administration ID (GUID). Defaults to YUKI_DOMAIN_ID env var.'),
|
|
439
|
+
},
|
|
440
|
+
}, async ({ documentId, administrationId }) => {
|
|
441
|
+
try {
|
|
442
|
+
const adminId = administrationId ?? client.defaultDomainId;
|
|
443
|
+
if (!adminId)
|
|
444
|
+
throw new Error('administrationId is required (or set YUKI_DOMAIN_ID env var)');
|
|
445
|
+
const sessionID = await client.getSessionID();
|
|
446
|
+
const result = await client.callSoap({
|
|
447
|
+
service: 'Archive.asmx',
|
|
448
|
+
method: 'FindDocument',
|
|
449
|
+
params: { sessionID, administrationID: adminId, documentID: documentId },
|
|
450
|
+
});
|
|
451
|
+
return {
|
|
452
|
+
content: [
|
|
453
|
+
{
|
|
454
|
+
type: 'text',
|
|
455
|
+
text: JSON.stringify({ success: true, documentId, result }, null, 2),
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
catch (err) {
|
|
461
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
462
|
+
return {
|
|
463
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
464
|
+
isError: true,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
// ── download_document ───────────────────────────────────────────────────────
|
|
469
|
+
/**
|
|
470
|
+
* download_document
|
|
471
|
+
*
|
|
472
|
+
* Download the binary content of an archived document, returned as a
|
|
473
|
+
* base64-encoded string. The caller can decode and save the file.
|
|
474
|
+
*
|
|
475
|
+
* Rate cost: 1 request.
|
|
476
|
+
*/
|
|
477
|
+
server.registerTool('download_document', {
|
|
478
|
+
description: 'Download an archived document from Yuki as a base64-encoded string. ' +
|
|
479
|
+
'Use list_documents or search_documents to find the document ID first. ' +
|
|
480
|
+
'Returns fileName and fileDataBase64.',
|
|
481
|
+
inputSchema: {
|
|
482
|
+
documentId: z.string().describe('Yuki document ID (from list_documents or search_documents).'),
|
|
483
|
+
},
|
|
484
|
+
}, async ({ documentId }) => {
|
|
485
|
+
try {
|
|
486
|
+
const sessionID = await client.getSessionID();
|
|
487
|
+
// DocumentBinaryData does not take administrationID
|
|
488
|
+
const result = await client.callSoap({
|
|
489
|
+
service: 'Archive.asmx',
|
|
490
|
+
method: 'DocumentBinaryData',
|
|
491
|
+
params: { sessionID, documentID: documentId },
|
|
492
|
+
});
|
|
493
|
+
const doc = result;
|
|
494
|
+
const fileName = doc['fileName'] ?? doc['FileName'] ?? null;
|
|
495
|
+
const fileData = doc['fileData'] ?? doc['filedata'] ?? doc['FileData'] ?? result;
|
|
496
|
+
return {
|
|
497
|
+
content: [
|
|
498
|
+
{
|
|
499
|
+
type: 'text',
|
|
500
|
+
text: JSON.stringify({ success: true, documentId, fileName, fileDataBase64: fileData }, null, 2),
|
|
501
|
+
},
|
|
502
|
+
],
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
507
|
+
return {
|
|
508
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
509
|
+
isError: true,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
// ── get_cost_categories ──────────────────────────────────────────────────────
|
|
514
|
+
/**
|
|
515
|
+
* get_cost_categories
|
|
516
|
+
*
|
|
517
|
+
* Retrieve the available cost categories (kostenrekeningen) for document
|
|
518
|
+
* uploads. These are the GL account codes that can be passed as
|
|
519
|
+
* `costCategory` when calling upload_document or upload_document_from_path.
|
|
520
|
+
*
|
|
521
|
+
* Rate cost: 1 request.
|
|
522
|
+
*/
|
|
523
|
+
server.registerTool('get_cost_categories', {
|
|
524
|
+
description: 'List available cost categories (GL cost accounts) for document uploads. ' +
|
|
525
|
+
'Use the returned GL codes as the costCategory parameter in upload_document.',
|
|
526
|
+
inputSchema: {
|
|
527
|
+
administrationId: z
|
|
528
|
+
.string()
|
|
529
|
+
.optional()
|
|
530
|
+
.describe('Administration ID (GUID). Defaults to YUKI_DOMAIN_ID env var.'),
|
|
531
|
+
},
|
|
532
|
+
}, async ({ administrationId }) => {
|
|
533
|
+
try {
|
|
534
|
+
const adminId = administrationId ?? client.defaultDomainId;
|
|
535
|
+
if (!adminId)
|
|
536
|
+
throw new Error('administrationId is required (or set YUKI_DOMAIN_ID env var)');
|
|
537
|
+
const sessionID = await client.getSessionID();
|
|
538
|
+
const result = await client.callSoap({
|
|
539
|
+
service: 'Archive.asmx',
|
|
540
|
+
method: 'CostCategories',
|
|
541
|
+
params: { sessionID, administrationID: adminId },
|
|
542
|
+
});
|
|
543
|
+
return {
|
|
544
|
+
content: [
|
|
545
|
+
{
|
|
546
|
+
type: 'text',
|
|
547
|
+
text: JSON.stringify({ success: true, result }, null, 2),
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
catch (err) {
|
|
553
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
554
|
+
return {
|
|
555
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: message }, null, 2) }],
|
|
556
|
+
isError: true,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
});
|
|
222
560
|
/**
|
|
223
561
|
* get_document_folders
|
|
224
562
|
*
|
|
@@ -274,4 +612,35 @@ export function registerDocumentTools(server, client) {
|
|
|
274
612
|
}
|
|
275
613
|
});
|
|
276
614
|
}
|
|
615
|
+
/** Unwrap a parsed SOAP documents result into a flat array. */
|
|
616
|
+
function normalizeDocuments(result) {
|
|
617
|
+
if (!result)
|
|
618
|
+
return [];
|
|
619
|
+
if (Array.isArray(result))
|
|
620
|
+
return result;
|
|
621
|
+
const rec = result;
|
|
622
|
+
const wrappers = ['Documents', 'SearchResults', 'Rows'];
|
|
623
|
+
const itemTags = ['Document', 'SearchResult', 'Row'];
|
|
624
|
+
for (const wrapper of wrappers) {
|
|
625
|
+
const c = rec[wrapper];
|
|
626
|
+
if (!c)
|
|
627
|
+
continue;
|
|
628
|
+
if (Array.isArray(c))
|
|
629
|
+
return c;
|
|
630
|
+
const inner = c;
|
|
631
|
+
for (const tag of itemTags) {
|
|
632
|
+
if (Array.isArray(inner[tag]))
|
|
633
|
+
return inner[tag];
|
|
634
|
+
if (inner[tag])
|
|
635
|
+
return [inner[tag]];
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
for (const tag of itemTags) {
|
|
639
|
+
if (Array.isArray(rec[tag]))
|
|
640
|
+
return rec[tag];
|
|
641
|
+
if (rec[tag])
|
|
642
|
+
return [rec[tag]];
|
|
643
|
+
}
|
|
644
|
+
return [result];
|
|
645
|
+
}
|
|
277
646
|
//# sourceMappingURL=documents.js.map
|