@frihet/mcp-server 1.16.5 → 1.17.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 +92 -31
- package/dist/agent-onboarding.d.ts +98 -0
- package/dist/agent-onboarding.js +275 -0
- package/dist/api-origin.d.ts +9 -0
- package/dist/api-origin.js +41 -0
- package/dist/canary/mcp-harness.d.ts +77 -0
- package/dist/canary/mcp-harness.js +549 -0
- package/dist/capability-truth.d.ts +29 -0
- package/dist/capability-truth.js +254 -0
- package/dist/client-interface.d.ts +22 -14
- package/dist/client.d.ts +114 -18
- package/dist/client.js +520 -58
- package/dist/demo-client.d.ts +16 -13
- package/dist/demo-client.js +209 -29
- package/dist/demo-fixtures.d.ts +3 -3
- package/dist/demo-fixtures.js +7 -7
- package/dist/fiscal-aliases.d.ts +44 -0
- package/dist/fiscal-aliases.js +62 -0
- package/dist/index.js +41 -56
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +140 -8
- package/dist/observability.d.ts +18 -29
- package/dist/observability.js +192 -105
- package/dist/openai-profile.d.ts +27 -15
- package/dist/openai-profile.js +1191 -145
- package/dist/openai-review-contract.d.ts +49 -0
- package/dist/openai-review-contract.js +919 -0
- package/dist/openai-review-oauth.d.ts +98 -0
- package/dist/openai-review-oauth.js +136 -0
- package/dist/prompts/register-all.d.ts +2 -0
- package/dist/prompts/register-all.js +2 -0
- package/dist/public-capability-contract.d.ts +39 -0
- package/dist/public-capability-contract.js +186 -0
- package/dist/redaction.d.ts +10 -0
- package/dist/redaction.js +74 -0
- package/dist/resources/register-all.js +6 -12
- package/dist/server-composition.d.ts +16 -0
- package/dist/server-composition.js +44 -0
- package/dist/tool-exposure.d.ts +25 -22
- package/dist/tool-exposure.js +199 -77
- package/dist/tools/accountingClose.d.ts +14 -5
- package/dist/tools/accountingClose.js +41 -23
- package/dist/tools/backend-availability.d.ts +3 -3
- package/dist/tools/backend-availability.js +3 -3
- package/dist/tools/clients.js +9 -9
- package/dist/tools/crm.js +22 -21
- package/dist/tools/deposits.js +30 -11
- package/dist/tools/einvoice.d.ts +1 -1
- package/dist/tools/expenses.d.ts +16 -0
- package/dist/tools/expenses.js +47 -27
- package/dist/tools/hr.d.ts +2 -3
- package/dist/tools/hr.js +8 -9
- package/dist/tools/intelligence.js +95 -4
- package/dist/tools/invoices.js +150 -47
- package/dist/tools/payroll.d.ts +5 -8
- package/dist/tools/payroll.js +19 -32
- package/dist/tools/permissions.d.ts +4 -7
- package/dist/tools/permissions.js +11 -14
- package/dist/tools/products.js +6 -6
- package/dist/tools/quotes.js +109 -24
- package/dist/tools/shared.d.ts +1431 -75
- package/dist/tools/shared.js +386 -76
- package/dist/tools/team.js +18 -14
- package/dist/tools/vendors.js +9 -9
- package/dist/tools/webhooks.js +35 -30
- package/dist/types.d.ts +28 -4
- package/docs/agent-onboarding.json +381 -0
- package/package.json +32 -7
package/dist/tools/products.js
CHANGED
|
@@ -67,9 +67,9 @@ export function registerProductTools(server, client) {
|
|
|
67
67
|
"Los productos se pueden usar al crear facturas y presupuestos para entrada rapida de datos.",
|
|
68
68
|
annotations: CREATE_ANNOTATIONS,
|
|
69
69
|
inputSchema: {
|
|
70
|
-
name: z.string().describe("Product/service name / Nombre del producto o servicio"),
|
|
71
|
-
unitPrice: z.number().describe("Unit price in EUR / Precio unitario en EUR"),
|
|
72
|
-
description: z.string().optional().describe("Product description / Descripcion"),
|
|
70
|
+
name: z.string().trim().min(1).max(200).describe("Product/service name / Nombre del producto o servicio"),
|
|
71
|
+
unitPrice: z.number().finite().min(0).max(10_000_000).describe("Unit price in EUR / Precio unitario en EUR"),
|
|
72
|
+
description: z.string().max(2000).optional().describe("Product description / Descripcion"),
|
|
73
73
|
taxRate: z
|
|
74
74
|
.number()
|
|
75
75
|
.min(0)
|
|
@@ -94,9 +94,9 @@ export function registerProductTools(server, client) {
|
|
|
94
94
|
annotations: UPDATE_ANNOTATIONS,
|
|
95
95
|
inputSchema: {
|
|
96
96
|
id: z.string().describe("Product ID / ID del producto"),
|
|
97
|
-
name: z.string().optional().describe("Name / Nombre"),
|
|
98
|
-
unitPrice: z.number().optional().describe("Unit price / Precio unitario"),
|
|
99
|
-
description: z.string().optional().describe("Description / Descripcion"),
|
|
97
|
+
name: z.string().trim().min(1).max(200).optional().describe("Name / Nombre"),
|
|
98
|
+
unitPrice: z.number().finite().min(0).max(10_000_000).optional().describe("Unit price / Precio unitario"),
|
|
99
|
+
description: z.string().max(2000).optional().describe("Description / Descripcion"),
|
|
100
100
|
taxRate: z.number().min(0).max(100).optional().describe("Tax rate % / IVA %"),
|
|
101
101
|
},
|
|
102
102
|
outputSchema: productItemOutput,
|
package/dist/tools/quotes.js
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
* Quote tools for the Frihet MCP server.
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod/v4";
|
|
5
|
-
import { withToolLogging, formatPaginatedResponse, formatRecord, listContent, getContent, mutateContent, enrichResponse, READ_ONLY_ANNOTATIONS, CREATE_ANNOTATIONS, UPDATE_ANNOTATIONS, DELETE_ANNOTATIONS, paginatedOutput,
|
|
5
|
+
import { withToolLogging, formatPaginatedResponse, formatRecord, listContent, getContent, mutateContent, enrichResponse, READ_ONLY_ANNOTATIONS, CREATE_ANNOTATIONS, UPDATE_ANNOTATIONS, DELETE_ANNOTATIONS, paginatedOutput, documentDeleteResultOutput, quoteItemOutput, actionResultOutput } from "./shared.js";
|
|
6
6
|
const quoteItemSchema = z.object({
|
|
7
|
-
description: z.string().describe("Description of the line item / Descripcion del concepto"),
|
|
8
|
-
quantity: z.number().describe("Quantity / Cantidad"),
|
|
9
|
-
unitPrice: z.number().describe("Unit price in EUR / Precio unitario en EUR"),
|
|
10
|
-
});
|
|
7
|
+
description: z.string().trim().min(1).max(500).describe("Description of the line item / Descripcion del concepto"),
|
|
8
|
+
quantity: z.number().finite().min(0.0001).max(1_000_000).describe("Quantity / Cantidad"),
|
|
9
|
+
unitPrice: z.number().finite().min(0).max(10_000_000).describe("Unit price in EUR / Precio unitario en EUR"),
|
|
10
|
+
}).strict();
|
|
11
11
|
// Optional client-identity + ES fiscal fields the Frihet API accepts on quote
|
|
12
12
|
// create+update (mirrors the invoice subset the backend supports for quotes).
|
|
13
13
|
const quoteOptionalFields = {
|
|
14
14
|
clientId: z
|
|
15
15
|
.string()
|
|
16
16
|
.optional()
|
|
17
|
-
.describe("Existing client ID —
|
|
17
|
+
.describe("Existing client ID — stored client details are used for the document / ID de cliente existente"),
|
|
18
18
|
clientTaxId: z
|
|
19
19
|
.string()
|
|
20
20
|
.optional()
|
|
@@ -24,11 +24,11 @@ const quoteOptionalFields = {
|
|
|
24
24
|
.optional()
|
|
25
25
|
.describe("Client billing address / Direccion fiscal del cliente"),
|
|
26
26
|
issueDate: z
|
|
27
|
-
.
|
|
27
|
+
.iso.date()
|
|
28
28
|
.optional()
|
|
29
29
|
.describe("Issue date in ISO 8601 (YYYY-MM-DD), defaults to today / Fecha de emision"),
|
|
30
30
|
dueDate: z
|
|
31
|
-
.
|
|
31
|
+
.iso.date()
|
|
32
32
|
.optional()
|
|
33
33
|
.describe("Due date in ISO 8601 (YYYY-MM-DD) / Fecha de vencimiento"),
|
|
34
34
|
taxRate: z
|
|
@@ -132,17 +132,17 @@ export function registerQuoteTools(server, client) {
|
|
|
132
132
|
"Los presupuestos se pueden convertir en facturas despues.",
|
|
133
133
|
annotations: CREATE_ANNOTATIONS,
|
|
134
134
|
inputSchema: {
|
|
135
|
-
clientName: z.string().describe("Client name / Nombre del cliente"),
|
|
135
|
+
clientName: z.string().trim().min(1).max(200).describe("Client name / Nombre del cliente"),
|
|
136
136
|
...quoteOptionalFields,
|
|
137
137
|
items: z
|
|
138
138
|
.array(quoteItemSchema)
|
|
139
139
|
.min(1)
|
|
140
140
|
.describe("Line items (each with description, quantity, unitPrice) / Conceptos del presupuesto"),
|
|
141
141
|
validUntil: z
|
|
142
|
-
.
|
|
142
|
+
.iso.date()
|
|
143
143
|
.optional()
|
|
144
144
|
.describe("Expiry date in ISO 8601 (YYYY-MM-DD) / Fecha de validez"),
|
|
145
|
-
notes: z.string().optional().describe("Additional notes shown on the quote / Notas adicionales"),
|
|
145
|
+
notes: z.string().max(10_000).optional().describe("Additional notes shown on the quote / Notas adicionales"),
|
|
146
146
|
status: z
|
|
147
147
|
.enum(["draft", "sent", "accepted", "rejected", "expired"])
|
|
148
148
|
.optional()
|
|
@@ -153,8 +153,8 @@ export function registerQuoteTools(server, client) {
|
|
|
153
153
|
const result = await client.createQuote(input);
|
|
154
154
|
const hints = enrichResponse("quotes", "create", result);
|
|
155
155
|
return {
|
|
156
|
-
content: [mutateContent(formatRecord("Quote created", result))],
|
|
157
|
-
structuredContent: { ...result
|
|
156
|
+
content: [mutateContent(formatRecord("Quote created", result) + hints)],
|
|
157
|
+
structuredContent: { ...result },
|
|
158
158
|
};
|
|
159
159
|
}));
|
|
160
160
|
// -- update_quote --
|
|
@@ -187,34 +187,119 @@ export function registerQuoteTools(server, client) {
|
|
|
187
187
|
// -- delete_quote --
|
|
188
188
|
server.registerTool("delete_quote", {
|
|
189
189
|
title: "Delete Quote",
|
|
190
|
-
description: "
|
|
191
|
-
"
|
|
190
|
+
description: "Delete a quote by its ID. Requires confirm=true. " +
|
|
191
|
+
"Only a clean DRAFT with no delivery, response, attachment, or conversion evidence is removed permanently; a protected draft is refused and left unchanged. A sent/accepted/rejected/expired quote is NOT " +
|
|
192
|
+
"destroyed: the backend CANCELS it (status=cancelled) — the same non-destructive path invoices " +
|
|
193
|
+
"take — and it stays readable via get_quote. The result reports which happened in `outcome` " +
|
|
194
|
+
"(\"deleted\" or \"cancelled\"). " +
|
|
195
|
+
"/ Elimina un presupuesto por su ID. Requiere confirm=true. Solo un BORRADOR limpio sin evidencia de entrega, respuesta, adjuntos o conversion se " +
|
|
196
|
+
"elimina de forma permanente; un borrador protegido se rechaza sin cambios. Uno ya enviado/aceptado/rechazado NO se destruye: se CANCELA " +
|
|
197
|
+
"(status=cancelled) y sigue consultable con get_quote.",
|
|
192
198
|
annotations: DELETE_ANNOTATIONS,
|
|
193
199
|
inputSchema: {
|
|
194
200
|
id: z.string().describe("Quote ID / ID del presupuesto"),
|
|
201
|
+
confirm: z
|
|
202
|
+
.boolean()
|
|
203
|
+
.describe("Must be true to confirm deletion / Debe ser true para confirmar la eliminacion"),
|
|
195
204
|
},
|
|
196
|
-
outputSchema:
|
|
197
|
-
}, async ({ id }) => withToolLogging("delete_quote", async () => {
|
|
198
|
-
|
|
205
|
+
outputSchema: documentDeleteResultOutput,
|
|
206
|
+
}, async ({ id, confirm }) => withToolLogging("delete_quote", async () => {
|
|
207
|
+
if (!confirm) {
|
|
208
|
+
return {
|
|
209
|
+
content: [
|
|
210
|
+
{
|
|
211
|
+
type: "text",
|
|
212
|
+
text: "Error: confirm=true is required to delete a quote. " +
|
|
213
|
+
"A clean draft without delivery, response, attachment, or conversion evidence is removed permanently; a protected draft is refused; a sent/accepted quote is CANCELLED " +
|
|
214
|
+
"(status=cancelled) instead and remains in the record. " +
|
|
215
|
+
"Set confirm=true to proceed. / " +
|
|
216
|
+
"Se requiere confirm=true para eliminar un presupuesto.",
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
isError: true,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// 204 → undefined (draft row destroyed). 200 → soft-cancel body. See GAP-12.
|
|
223
|
+
const outcome = await client.deleteQuote(id);
|
|
224
|
+
const cancelled = !!outcome && typeof outcome === "object";
|
|
225
|
+
const body = cancelled ? outcome : {};
|
|
226
|
+
const previous = typeof body["previousStatus"] === "string" ? ` (was ${body["previousStatus"]})` : "";
|
|
199
227
|
return {
|
|
200
|
-
content: [mutateContent(
|
|
201
|
-
|
|
228
|
+
content: [mutateContent(cancelled
|
|
229
|
+
? `Quote ${id} was CANCELLED, not deleted${previous}: it still exists with status=cancelled. / ` +
|
|
230
|
+
`Presupuesto ${id} CANCELADO, no eliminado: sigue existiendo con status=cancelled.`
|
|
231
|
+
: `Quote ${id} deleted permanently (it was a draft). / ` +
|
|
232
|
+
`Presupuesto ${id} eliminado permanentemente (era un borrador).`)],
|
|
233
|
+
structuredContent: {
|
|
234
|
+
success: true,
|
|
235
|
+
id,
|
|
236
|
+
...body,
|
|
237
|
+
outcome: cancelled ? "cancelled" : "deleted",
|
|
238
|
+
},
|
|
202
239
|
};
|
|
203
240
|
}));
|
|
204
241
|
// -- send_quote --
|
|
205
242
|
server.registerTool("send_quote", {
|
|
206
243
|
title: "Send Quote",
|
|
207
|
-
description: "Send a quote/estimate to the client via email.
|
|
244
|
+
description: "Send a quote/estimate to the client via email. Requires confirm=true. " +
|
|
245
|
+
"Optionally override the recipient email address. " +
|
|
208
246
|
"The quote must exist and should not already be expired or rejected. " +
|
|
209
|
-
"
|
|
247
|
+
"Sending reaches a third party and cannot be recalled. " +
|
|
248
|
+
"/ Envia un presupuesto al cliente por email. Requiere confirm=true. " +
|
|
249
|
+
"Opcionalmente se puede cambiar el email destinatario. El envio llega a un tercero y no se puede anular.",
|
|
210
250
|
annotations: UPDATE_ANNOTATIONS,
|
|
211
251
|
inputSchema: {
|
|
212
252
|
id: z.string().describe("Quote ID / ID del presupuesto"),
|
|
213
253
|
to: z.string().optional().describe("Override recipient email / Email destinatario alternativo"),
|
|
254
|
+
confirm: z
|
|
255
|
+
.boolean()
|
|
256
|
+
.describe("Must be true to confirm sending / Debe ser true para confirmar el envio"),
|
|
214
257
|
},
|
|
215
258
|
outputSchema: actionResultOutput,
|
|
216
|
-
}, async ({ id, to }) => withToolLogging("send_quote", async () => {
|
|
217
|
-
|
|
259
|
+
}, async ({ id, to, confirm }) => withToolLogging("send_quote", async () => {
|
|
260
|
+
if (!confirm) {
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{
|
|
264
|
+
type: "text",
|
|
265
|
+
text: "Error: confirm=true is required to send a quote. " +
|
|
266
|
+
"This delivers an email to the client — a third party outside this workspace — " +
|
|
267
|
+
"and it cannot be recalled once sent. Set confirm=true to proceed. / " +
|
|
268
|
+
"Se requiere confirm=true para enviar un presupuesto por email a un tercero.",
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
isError: true,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const quote = await client.getQuote(id);
|
|
275
|
+
const status = typeof quote["status"] === "string" ? quote["status"] : undefined;
|
|
276
|
+
if (status && ["expired", "rejected", "cancelled"].includes(status)) {
|
|
277
|
+
return {
|
|
278
|
+
content: [{ type: "text", text: `Error: a ${status} quote cannot be sent.` }],
|
|
279
|
+
isError: true,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
let recipientEmail = to;
|
|
283
|
+
if (!recipientEmail) {
|
|
284
|
+
const clientId = typeof quote["clientId"] === "string" ? quote["clientId"] : undefined;
|
|
285
|
+
if (!clientId) {
|
|
286
|
+
return {
|
|
287
|
+
content: [{ type: "text", text: "Error: this quote has no linked client with a saved email address." }],
|
|
288
|
+
isError: true,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const linkedClient = await client.getClient(clientId);
|
|
292
|
+
recipientEmail = typeof linkedClient["email"] === "string" && linkedClient["email"].trim()
|
|
293
|
+
? linkedClient["email"].trim()
|
|
294
|
+
: undefined;
|
|
295
|
+
if (!recipientEmail) {
|
|
296
|
+
return {
|
|
297
|
+
content: [{ type: "text", text: "Error: the linked client has no saved email address." }],
|
|
298
|
+
isError: true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const result = await client.sendQuote(id, recipientEmail);
|
|
218
303
|
return {
|
|
219
304
|
content: [mutateContent(formatRecord("Quote sent", result))],
|
|
220
305
|
structuredContent: result,
|