@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/team.js
CHANGED
|
@@ -17,16 +17,16 @@ export function registerTeamTools(server, client) {
|
|
|
17
17
|
// -- list_team_members --
|
|
18
18
|
server.registerTool("list_team_members", {
|
|
19
19
|
title: "List Team Members",
|
|
20
|
-
description: "List
|
|
21
|
-
"
|
|
22
|
-
"Useful for
|
|
23
|
-
"/ Lista
|
|
24
|
-
"
|
|
25
|
-
"Util para
|
|
20
|
+
description: "List active workspace team members and pending invitations. The workspace owner is NOT a member row and is excluded. " +
|
|
21
|
+
"Each row carries member ID, name, email, role, and invite status (pending/active). " +
|
|
22
|
+
"Useful for reviewing team access and outstanding invitations. " +
|
|
23
|
+
"/ Lista miembros activos del equipo e invitaciones pendientes. El propietario del espacio NO aparece como miembro y queda excluido. " +
|
|
24
|
+
"Cada fila lleva ID, nombre, email, rol y estado de invitacion (pendiente/activo). " +
|
|
25
|
+
"Util para revisar el acceso del equipo y las invitaciones pendientes.",
|
|
26
26
|
annotations: READ_ONLY_ANNOTATIONS,
|
|
27
27
|
inputSchema: {
|
|
28
28
|
role: z
|
|
29
|
-
.enum(["owner", "admin", "
|
|
29
|
+
.enum(["owner", "admin", "editor", "accountant", "viewer"])
|
|
30
30
|
.optional()
|
|
31
31
|
.describe("Filter by role / Filtrar por rol"),
|
|
32
32
|
status: z
|
|
@@ -49,16 +49,18 @@ export function registerTeamTools(server, client) {
|
|
|
49
49
|
title: "Invite Team Member",
|
|
50
50
|
description: "Invite a new member to the workspace by email address. " +
|
|
51
51
|
"An invitation email is sent — the member must accept before gaining access. " +
|
|
52
|
-
"
|
|
53
|
-
"
|
|
52
|
+
"Assignable roles: admin, editor, accountant, viewer. Exact access follows the workspace's current role policy. " +
|
|
53
|
+
"Owner is excluded from invitations and must be transferred via a dedicated flow. " +
|
|
54
|
+
"Example: email='ana@example.com', role='accountant' " +
|
|
54
55
|
"/ Invita a un nuevo miembro al espacio de trabajo por correo electronico. " +
|
|
55
56
|
"Se envia un email de invitacion — el miembro debe aceptar antes de acceder. " +
|
|
56
|
-
"Roles:
|
|
57
|
+
"Roles asignables: admin, editor, accountant, viewer. El acceso exacto depende de la politica de roles vigente del espacio. " +
|
|
58
|
+
"Owner queda excluido de las invitaciones y debe transferirse por un flujo dedicado.",
|
|
57
59
|
annotations: CREATE_ANNOTATIONS,
|
|
58
60
|
inputSchema: {
|
|
59
61
|
email: z.string().email().describe("Email address of the invitee / Email del invitado"),
|
|
60
62
|
role: z
|
|
61
|
-
.enum(["admin", "
|
|
63
|
+
.enum(["admin", "editor", "accountant", "viewer"])
|
|
62
64
|
.describe("Role to assign (owner cannot be invited, must be transferred) / Rol a asignar (owner no se puede invitar, debe transferirse)"),
|
|
63
65
|
name: z
|
|
64
66
|
.string()
|
|
@@ -79,15 +81,17 @@ export function registerTeamTools(server, client) {
|
|
|
79
81
|
description: "Change the role of an existing team member. " +
|
|
80
82
|
"Only workspace admins or owners can change roles. " +
|
|
81
83
|
"Cannot change the owner's role — use a dedicated ownership transfer flow. " +
|
|
82
|
-
"
|
|
84
|
+
"Allowed roles: admin, editor, accountant, viewer. " +
|
|
85
|
+
"Example: memberId='mbr_abc123', role='accountant' " +
|
|
83
86
|
"/ Cambia el rol de un miembro existente del espacio de trabajo. " +
|
|
84
87
|
"Solo administradores o propietarios pueden cambiar roles. " +
|
|
85
|
-
"No se puede cambiar el rol del propietario — usa el flujo de transferencia de propiedad."
|
|
88
|
+
"No se puede cambiar el rol del propietario — usa el flujo de transferencia de propiedad. " +
|
|
89
|
+
"Roles permitidos: admin, editor, accountant, viewer.",
|
|
86
90
|
annotations: UPDATE_ANNOTATIONS,
|
|
87
91
|
inputSchema: {
|
|
88
92
|
memberId: z.string().describe("Team member ID / ID del miembro del equipo"),
|
|
89
93
|
role: z
|
|
90
|
-
.enum(["admin", "
|
|
94
|
+
.enum(["admin", "editor", "accountant", "viewer"])
|
|
91
95
|
.describe("New role to assign / Nuevo rol a asignar"),
|
|
92
96
|
},
|
|
93
97
|
outputSchema: actionResultOutput,
|
package/dist/tools/vendors.js
CHANGED
|
@@ -64,9 +64,9 @@ export function registerVendorTools(server, client) {
|
|
|
64
64
|
"Los proveedores se usan al registrar gastos y pedidos de compra.",
|
|
65
65
|
annotations: CREATE_ANNOTATIONS,
|
|
66
66
|
inputSchema: {
|
|
67
|
-
name: z.string().describe("Vendor/company name / Nombre del proveedor o empresa"),
|
|
68
|
-
email: z.string().optional().describe("Email address / Correo electronico"),
|
|
69
|
-
phone: z.string().optional().describe("Phone number / Telefono"),
|
|
67
|
+
name: z.string().trim().min(1).max(200).describe("Vendor/company name / Nombre del proveedor o empresa"),
|
|
68
|
+
email: z.string().trim().email().max(255).optional().describe("Email address / Correo electronico"),
|
|
69
|
+
phone: z.string().trim().min(1).max(50).optional().describe("Phone number / Telefono"),
|
|
70
70
|
taxId: z.string().optional().describe("Tax ID (NIF/CIF/VAT) / NIF o CIF"),
|
|
71
71
|
address: addressSchema,
|
|
72
72
|
},
|
|
@@ -75,8 +75,8 @@ export function registerVendorTools(server, client) {
|
|
|
75
75
|
const result = await client.createVendor(input);
|
|
76
76
|
const hints = enrichResponse("vendors", "create", result);
|
|
77
77
|
return {
|
|
78
|
-
content: [mutateContent(formatRecord("Vendor created", result))],
|
|
79
|
-
structuredContent: { ...result
|
|
78
|
+
content: [mutateContent(formatRecord("Vendor created", result) + hints)],
|
|
79
|
+
structuredContent: { ...result },
|
|
80
80
|
};
|
|
81
81
|
}));
|
|
82
82
|
// -- update_vendor --
|
|
@@ -87,10 +87,10 @@ export function registerVendorTools(server, client) {
|
|
|
87
87
|
"/ Actualiza un proveedor existente. Solo se modifican los campos proporcionados.",
|
|
88
88
|
annotations: UPDATE_ANNOTATIONS,
|
|
89
89
|
inputSchema: {
|
|
90
|
-
id: z.string().describe("Vendor ID / ID del proveedor"),
|
|
91
|
-
name: z.string().optional().describe("Name / Nombre"),
|
|
92
|
-
email: z.string().optional().describe("Email / Correo"),
|
|
93
|
-
phone: z.string().optional().describe("Phone / Telefono"),
|
|
90
|
+
id: z.string().trim().min(1).max(128).describe("Vendor ID / ID del proveedor"),
|
|
91
|
+
name: z.string().trim().min(1).max(200).optional().describe("Name / Nombre"),
|
|
92
|
+
email: z.string().trim().email().max(255).optional().describe("Email / Correo"),
|
|
93
|
+
phone: z.string().trim().min(1).max(50).optional().describe("Phone / Telefono"),
|
|
94
94
|
taxId: z.string().optional().describe("Tax ID / NIF/CIF"),
|
|
95
95
|
address: addressSchema,
|
|
96
96
|
},
|
package/dist/tools/webhooks.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Webhook management tools for the Frihet MCP server.
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod/v4";
|
|
5
|
-
import { withToolLogging,
|
|
5
|
+
import { withToolLogging, formatRecord, formatUnpaginatedListResponse, listContent, getContent, mutateContent, READ_ONLY_ANNOTATIONS, CREATE_ANNOTATIONS, UPDATE_ANNOTATIONS, DELETE_ANNOTATIONS, deleteResultOutput, webhookCreateOutput, webhookItemOutput, webhookListOutput, webhookTestResultOutput } from "./shared.js";
|
|
6
6
|
export function registerWebhookTools(server, client) {
|
|
7
7
|
// -- list_webhooks --
|
|
8
8
|
server.registerTool("list_webhooks", {
|
|
@@ -10,15 +10,12 @@ export function registerWebhookTools(server, client) {
|
|
|
10
10
|
description: "List all configured webhooks. Webhooks send HTTP POST notifications when events occur in Frihet. " +
|
|
11
11
|
"/ Lista todos los webhooks configurados. Los webhooks envian notificaciones HTTP POST cuando ocurren eventos en Frihet.",
|
|
12
12
|
annotations: READ_ONLY_ANNOTATIONS,
|
|
13
|
-
inputSchema: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
outputSchema: paginatedOutput(webhookItemOutput),
|
|
18
|
-
}, async ({ limit, offset }) => withToolLogging("list_webhooks", async () => {
|
|
19
|
-
const result = await client.listWebhooks({ limit, offset });
|
|
13
|
+
inputSchema: z.object({}).strict(),
|
|
14
|
+
outputSchema: webhookListOutput,
|
|
15
|
+
}, async () => withToolLogging("list_webhooks", async () => {
|
|
16
|
+
const result = await client.listWebhooks();
|
|
20
17
|
return {
|
|
21
|
-
content: [listContent(
|
|
18
|
+
content: [listContent(formatUnpaginatedListResponse("webhooks", result))],
|
|
22
19
|
structuredContent: result,
|
|
23
20
|
};
|
|
24
21
|
}));
|
|
@@ -28,9 +25,9 @@ export function registerWebhookTools(server, client) {
|
|
|
28
25
|
description: "Get a single webhook configuration by its ID. " +
|
|
29
26
|
"/ Obtiene la configuracion de un webhook por su ID.",
|
|
30
27
|
annotations: READ_ONLY_ANNOTATIONS,
|
|
31
|
-
inputSchema: {
|
|
28
|
+
inputSchema: z.object({
|
|
32
29
|
id: z.string().describe("Webhook ID / ID del webhook"),
|
|
33
|
-
},
|
|
30
|
+
}).strict(),
|
|
34
31
|
outputSchema: webhookItemOutput,
|
|
35
32
|
}, async ({ id }) => withToolLogging("get_webhook", async () => {
|
|
36
33
|
const result = await client.getWebhook(id);
|
|
@@ -42,31 +39,37 @@ export function registerWebhookTools(server, client) {
|
|
|
42
39
|
// -- create_webhook --
|
|
43
40
|
server.registerTool("create_webhook", {
|
|
44
41
|
title: "Create Webhook",
|
|
45
|
-
description: "Register a
|
|
42
|
+
description: "Register a named webhook endpoint. You must specify the name, URL, and events to receive notifications " +
|
|
46
43
|
"and which events to subscribe to. " +
|
|
47
|
-
"Available events: invoice.created, invoice.updated, invoice.paid,
|
|
48
|
-
"expense.created, expense.updated,
|
|
44
|
+
"Available events: invoice.created, invoice.updated, invoice.paid, " +
|
|
45
|
+
"expense.created, expense.updated, client.created, client.updated, " +
|
|
49
46
|
"quote.created, quote.updated, quote.accepted. " +
|
|
50
|
-
"Example: url='https://example.com/webhook', events=['invoice.created','invoice.paid'], secret='my-secret' " +
|
|
47
|
+
"Example: name='Invoice events', url='https://example.com/webhook', events=['invoice.created','invoice.paid'], secret='my-secret' " +
|
|
51
48
|
"/ Registra un nuevo endpoint de webhook. Especifica la URL y los eventos a suscribir.",
|
|
52
49
|
annotations: CREATE_ANNOTATIONS,
|
|
53
|
-
inputSchema: {
|
|
54
|
-
|
|
50
|
+
inputSchema: z.object({
|
|
51
|
+
name: z.string().max(200).describe("Webhook name / Nombre del webhook"),
|
|
52
|
+
url: z.string().url().max(2000).describe("Webhook endpoint URL / URL del endpoint del webhook"),
|
|
55
53
|
events: z
|
|
56
|
-
.array(z.string())
|
|
54
|
+
.array(z.string().max(100))
|
|
57
55
|
.min(1)
|
|
58
56
|
.describe("Events to subscribe to (e.g. ['invoice.created', 'invoice.paid']) " +
|
|
59
57
|
"/ Eventos a suscribir"),
|
|
60
|
-
|
|
61
|
-
.
|
|
58
|
+
status: z
|
|
59
|
+
.enum(["active", "inactive"])
|
|
62
60
|
.optional()
|
|
63
|
-
.describe("
|
|
61
|
+
.describe("Webhook status (default: active) / Estado del webhook"),
|
|
62
|
+
metadata: z
|
|
63
|
+
.record(z.string(), z.unknown())
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("Arbitrary webhook metadata / Metadatos del webhook"),
|
|
64
66
|
secret: z
|
|
65
67
|
.string()
|
|
68
|
+
.max(500)
|
|
66
69
|
.optional()
|
|
67
70
|
.describe("Signing secret for payload verification / Secreto para verificar las notificaciones"),
|
|
68
|
-
},
|
|
69
|
-
outputSchema:
|
|
71
|
+
}).strict(),
|
|
72
|
+
outputSchema: webhookCreateOutput,
|
|
70
73
|
}, async (input) => withToolLogging("create_webhook", async () => {
|
|
71
74
|
const result = await client.createWebhook(input);
|
|
72
75
|
return {
|
|
@@ -78,16 +81,18 @@ export function registerWebhookTools(server, client) {
|
|
|
78
81
|
server.registerTool("update_webhook", {
|
|
79
82
|
title: "Update Webhook",
|
|
80
83
|
description: "Update an existing webhook configuration using PATCH semantics. Only provided fields change. " +
|
|
81
|
-
"Example: id='abc123',
|
|
84
|
+
"Example: id='abc123', status='paused' to pause a webhook. " +
|
|
82
85
|
"/ Actualiza la configuracion de un webhook. Solo se modifican los campos proporcionados.",
|
|
83
86
|
annotations: UPDATE_ANNOTATIONS,
|
|
84
|
-
inputSchema: {
|
|
87
|
+
inputSchema: z.object({
|
|
85
88
|
id: z.string().describe("Webhook ID / ID del webhook"),
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
name: z.string().max(200).optional().describe("Webhook name / Nombre del webhook"),
|
|
90
|
+
url: z.string().url().max(2000).optional().describe("Endpoint URL / URL"),
|
|
91
|
+
events: z.array(z.string().max(100)).min(1).optional().describe("Events / Eventos"),
|
|
92
|
+
status: z.enum(["active", "inactive", "paused"]).optional().describe("Status / Estado"),
|
|
93
|
+
metadata: z.record(z.string(), z.unknown()).optional().describe("Metadata / Metadatos"),
|
|
94
|
+
secret: z.string().max(500).optional().describe("Signing secret / Secreto"),
|
|
95
|
+
}).strict(),
|
|
91
96
|
outputSchema: webhookItemOutput,
|
|
92
97
|
}, async ({ id, ...data }) => withToolLogging("update_webhook", async () => {
|
|
93
98
|
const result = await client.updateWebhook(id, data);
|
package/dist/types.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface PaginatedResponse<T> {
|
|
|
11
11
|
export interface ApiError {
|
|
12
12
|
error: string;
|
|
13
13
|
message?: string;
|
|
14
|
+
detail?: string;
|
|
14
15
|
}
|
|
15
16
|
export interface PaginationParams {
|
|
16
17
|
limit?: number;
|
|
@@ -99,13 +100,36 @@ export type CreateQuoteInput = Pick<Quote, "clientName" | "items"> & Partial<Pic
|
|
|
99
100
|
export type UpdateQuoteInput = Partial<CreateQuoteInput>;
|
|
100
101
|
export interface Webhook {
|
|
101
102
|
id: string;
|
|
103
|
+
userId?: string;
|
|
104
|
+
name: string;
|
|
102
105
|
url: string;
|
|
103
106
|
events: string[];
|
|
104
|
-
active
|
|
105
|
-
|
|
107
|
+
status: "active" | "inactive" | "paused";
|
|
108
|
+
metadata?: Record<string, unknown>;
|
|
109
|
+
hasSecret: boolean;
|
|
110
|
+
pausedReason?: string;
|
|
111
|
+
lastTriggeredAt?: string;
|
|
106
112
|
createdAt?: string;
|
|
107
113
|
updatedAt?: string;
|
|
108
114
|
}
|
|
109
|
-
export
|
|
110
|
-
|
|
115
|
+
export interface CreateWebhookInput {
|
|
116
|
+
name: string;
|
|
117
|
+
url: string;
|
|
118
|
+
events: string[];
|
|
119
|
+
status?: "active" | "inactive";
|
|
120
|
+
metadata?: Record<string, unknown>;
|
|
121
|
+
secret?: string;
|
|
122
|
+
}
|
|
123
|
+
export interface UpdateWebhookInput {
|
|
124
|
+
name?: string;
|
|
125
|
+
url?: string;
|
|
126
|
+
events?: string[];
|
|
127
|
+
status?: "active" | "inactive" | "paused";
|
|
128
|
+
metadata?: Record<string, unknown>;
|
|
129
|
+
secret?: string;
|
|
130
|
+
}
|
|
131
|
+
/** Create may echo only the caller-supplied signing secret, once. */
|
|
132
|
+
export type CreateWebhookResult = Webhook & {
|
|
133
|
+
secret?: string;
|
|
134
|
+
};
|
|
111
135
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
{
|
|
2
|
+
"onboardingContractVersion": 1,
|
|
3
|
+
"server": {
|
|
4
|
+
"mcpName": "io.frihet/erp",
|
|
5
|
+
"npmPackage": "@frihet/mcp-server",
|
|
6
|
+
"remoteEndpoint": "https://mcp.frihet.io/mcp",
|
|
7
|
+
"transport": [
|
|
8
|
+
"stdio",
|
|
9
|
+
"streamable-http"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"auth": {
|
|
13
|
+
"envVar": "FRIHET_API_KEY",
|
|
14
|
+
"keyFormat": "fri_<key>",
|
|
15
|
+
"obtainAt": "https://app.frihet.io/settings/api",
|
|
16
|
+
"remoteMethods": [
|
|
17
|
+
"oauth2.1-pkce",
|
|
18
|
+
"bearer"
|
|
19
|
+
],
|
|
20
|
+
"noAuthTrial": {
|
|
21
|
+
"env": {
|
|
22
|
+
"FRIHET_DEMO": "1"
|
|
23
|
+
},
|
|
24
|
+
"persists": false,
|
|
25
|
+
"network": false
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"quickstart": {
|
|
29
|
+
"claude-code": {
|
|
30
|
+
"steps": [
|
|
31
|
+
"claude mcp add frihet -s user -e FRIHET_API_KEY=fri_... -- npx -y @frihet/mcp-server"
|
|
32
|
+
],
|
|
33
|
+
"configFormat": "managed by the CLI (user scope writes ~/.claude.json)",
|
|
34
|
+
"verify": "claude mcp list"
|
|
35
|
+
},
|
|
36
|
+
"codex": {
|
|
37
|
+
"steps": [
|
|
38
|
+
"codex mcp add frihet --env FRIHET_API_KEY=fri_... -- npx -y @frihet/mcp-server"
|
|
39
|
+
],
|
|
40
|
+
"configFormat": "toml (~/.codex/config.toml — JSON in this file is a parse error)",
|
|
41
|
+
"verify": "codex mcp list"
|
|
42
|
+
},
|
|
43
|
+
"generic-mcp-client-stdio": {
|
|
44
|
+
"steps": [
|
|
45
|
+
"mcpServers.frihet = { \"command\": \"npx\", \"args\": [\"-y\", \"@frihet/mcp-server\"], \"env\": { \"FRIHET_API_KEY\": \"fri_...\" } }"
|
|
46
|
+
],
|
|
47
|
+
"configFormat": "json",
|
|
48
|
+
"verify": "initialize → tools/list returns a non-empty catalogue"
|
|
49
|
+
},
|
|
50
|
+
"generic-mcp-client-http": {
|
|
51
|
+
"steps": [
|
|
52
|
+
"mcpServers.frihet = { \"type\": \"streamable-http\", \"url\": \"https://mcp.frihet.io/mcp\", \"headers\": { \"Authorization\": \"Bearer fri_...\" } }"
|
|
53
|
+
],
|
|
54
|
+
"configFormat": "json",
|
|
55
|
+
"verify": "initialize → tools/list returns a non-empty catalogue"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"capabilityDiscovery": {
|
|
59
|
+
"metaKey": "io.frihet/capability",
|
|
60
|
+
"callabilityValues": [
|
|
61
|
+
"api_dependent",
|
|
62
|
+
"runtime_checked",
|
|
63
|
+
"deferred",
|
|
64
|
+
"unavailable",
|
|
65
|
+
"local"
|
|
66
|
+
],
|
|
67
|
+
"groupedModeEnv": {
|
|
68
|
+
"FRIHET_TOOL_MODE": "grouped"
|
|
69
|
+
},
|
|
70
|
+
"counts": {
|
|
71
|
+
"toolNames": 162,
|
|
72
|
+
"readOnly": 82,
|
|
73
|
+
"writesFrihet": 80,
|
|
74
|
+
"externalInteraction": 36,
|
|
75
|
+
"destructive": 61,
|
|
76
|
+
"resources": 11,
|
|
77
|
+
"prompts": 10
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"safeWorkflow": {
|
|
81
|
+
"description": "Discover → orient → retrieve → propose → hand back. No step mutates data or reaches a third party.",
|
|
82
|
+
"steps": [
|
|
83
|
+
{
|
|
84
|
+
"call": "get_business_context",
|
|
85
|
+
"kind": "read",
|
|
86
|
+
"note": "Fiscal zone, currency and defaults. Everything downstream depends on it."
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"call": "resources/read frihet://tax/rates",
|
|
90
|
+
"kind": "read",
|
|
91
|
+
"note": "Authoritative IVA / IGIC / IPSI table. Do not recall a rate from memory."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"call": "list_clients",
|
|
95
|
+
"kind": "read",
|
|
96
|
+
"note": "Resolve the client by name before referencing an id."
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"call": "STOP",
|
|
100
|
+
"kind": "handoff",
|
|
101
|
+
"note": "Present the proposed draft inputs and all disclosed effects. Creating, issuing, sending, or submitting is a separate human decision."
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
"humanAuthority": {
|
|
106
|
+
"rule": "Do not call a tool with non-empty externalSideEffects, and do not set confirm=true, without an explicit human instruction for that specific action.",
|
|
107
|
+
"confirmRequired": [
|
|
108
|
+
"delete_invoice",
|
|
109
|
+
"delete_quote",
|
|
110
|
+
"delete_recurring_invoice",
|
|
111
|
+
"delete_time_entry",
|
|
112
|
+
"match_transaction_to_invoice",
|
|
113
|
+
"period_close",
|
|
114
|
+
"period_reopen",
|
|
115
|
+
"refund_deposit",
|
|
116
|
+
"refund_sale",
|
|
117
|
+
"remove_team_member",
|
|
118
|
+
"send_invoice",
|
|
119
|
+
"send_quote",
|
|
120
|
+
"verifactu_resubmit"
|
|
121
|
+
],
|
|
122
|
+
"externalSideEffects": [
|
|
123
|
+
{
|
|
124
|
+
"tool": "create_client",
|
|
125
|
+
"effects": [
|
|
126
|
+
"webhook_delivery_or_configuration"
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"tool": "create_credit_note",
|
|
131
|
+
"effects": [
|
|
132
|
+
"webhook_delivery_or_configuration"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"tool": "create_expense",
|
|
137
|
+
"effects": [
|
|
138
|
+
"webhook_delivery_or_configuration"
|
|
139
|
+
]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"tool": "create_invoice",
|
|
143
|
+
"effects": [
|
|
144
|
+
"webhook_delivery_or_configuration",
|
|
145
|
+
"fiscal_or_einvoice_submission"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"tool": "create_product",
|
|
150
|
+
"effects": [
|
|
151
|
+
"webhook_delivery_or_configuration"
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"tool": "create_quote",
|
|
156
|
+
"effects": [
|
|
157
|
+
"webhook_delivery_or_configuration"
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"tool": "create_webhook",
|
|
162
|
+
"effects": [
|
|
163
|
+
"webhook_delivery_or_configuration"
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"tool": "delete_invoice",
|
|
168
|
+
"effects": [
|
|
169
|
+
"webhook_delivery_or_configuration",
|
|
170
|
+
"fiscal_or_einvoice_submission"
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"tool": "delete_quote",
|
|
175
|
+
"effects": [
|
|
176
|
+
"webhook_delivery_or_configuration"
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"tool": "delete_webhook",
|
|
181
|
+
"effects": [
|
|
182
|
+
"webhook_delivery_or_configuration"
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"tool": "duplicate_invoice",
|
|
187
|
+
"effects": [
|
|
188
|
+
"webhook_delivery_or_configuration"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"tool": "face_status",
|
|
193
|
+
"effects": [
|
|
194
|
+
"external_provider_read"
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"tool": "face_submit",
|
|
199
|
+
"effects": [
|
|
200
|
+
"fiscal_or_einvoice_submission"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"tool": "frihet_portal_domain_add",
|
|
205
|
+
"effects": [
|
|
206
|
+
"external_provider_configuration"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"tool": "frihet_portal_domain_remove",
|
|
211
|
+
"effects": [
|
|
212
|
+
"external_provider_configuration"
|
|
213
|
+
]
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"tool": "frihet_portal_domain_verify",
|
|
217
|
+
"effects": [
|
|
218
|
+
"external_provider_read",
|
|
219
|
+
"external_provider_configuration"
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"tool": "frihet_tax_id_vies_lookup",
|
|
224
|
+
"effects": [
|
|
225
|
+
"external_provider_read"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"tool": "gestoria_message_send",
|
|
230
|
+
"effects": [
|
|
231
|
+
"email_or_invitation"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"tool": "gestoria_template_bulk_send",
|
|
236
|
+
"effects": [
|
|
237
|
+
"email_or_invitation"
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"tool": "invite_team_member",
|
|
242
|
+
"effects": [
|
|
243
|
+
"email_or_invitation"
|
|
244
|
+
]
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"tool": "log_client_activity",
|
|
248
|
+
"effects": [
|
|
249
|
+
"webhook_delivery_or_configuration"
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"tool": "mark_invoice_paid",
|
|
254
|
+
"effects": [
|
|
255
|
+
"webhook_delivery_or_configuration",
|
|
256
|
+
"fiscal_or_einvoice_submission"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"tool": "refund_sale",
|
|
261
|
+
"effects": [
|
|
262
|
+
"money_movement"
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"tool": "send_einvoice",
|
|
267
|
+
"effects": [
|
|
268
|
+
"fiscal_or_einvoice_submission"
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"tool": "send_invoice",
|
|
273
|
+
"effects": [
|
|
274
|
+
"email_or_invitation",
|
|
275
|
+
"webhook_delivery_or_configuration",
|
|
276
|
+
"fiscal_or_einvoice_submission"
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"tool": "send_quote",
|
|
281
|
+
"effects": [
|
|
282
|
+
"email_or_invitation",
|
|
283
|
+
"webhook_delivery_or_configuration"
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"tool": "sync_channel",
|
|
288
|
+
"effects": [
|
|
289
|
+
"channel_sync"
|
|
290
|
+
]
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"tool": "test_webhook",
|
|
294
|
+
"effects": [
|
|
295
|
+
"webhook_delivery_or_configuration"
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"tool": "ticketbai_submit",
|
|
300
|
+
"effects": [
|
|
301
|
+
"fiscal_or_einvoice_submission"
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"tool": "update_client",
|
|
306
|
+
"effects": [
|
|
307
|
+
"webhook_delivery_or_configuration"
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"tool": "update_expense",
|
|
312
|
+
"effects": [
|
|
313
|
+
"webhook_delivery_or_configuration"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"tool": "update_invoice",
|
|
318
|
+
"effects": [
|
|
319
|
+
"webhook_delivery_or_configuration",
|
|
320
|
+
"fiscal_or_einvoice_submission"
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"tool": "update_product",
|
|
325
|
+
"effects": [
|
|
326
|
+
"webhook_delivery_or_configuration"
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"tool": "update_quote",
|
|
331
|
+
"effects": [
|
|
332
|
+
"webhook_delivery_or_configuration"
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"tool": "update_webhook",
|
|
337
|
+
"effects": [
|
|
338
|
+
"webhook_delivery_or_configuration"
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"tool": "verifactu_resubmit",
|
|
343
|
+
"effects": [
|
|
344
|
+
"fiscal_or_einvoice_submission"
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
},
|
|
349
|
+
"errors": [
|
|
350
|
+
{
|
|
351
|
+
"condition": "startup exits 1 with code FRIHET_API_KEY_MISSING",
|
|
352
|
+
"meaning": "No credential in the environment.",
|
|
353
|
+
"agentAction": "Ask the human for a key from https://app.frihet.io/settings/api, or re-launch with FRIHET_DEMO=1 to explore without one."
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"condition": "HTTP 401",
|
|
357
|
+
"meaning": "Key missing, malformed or revoked.",
|
|
358
|
+
"agentAction": "Stop and ask for a new key. Do not retry."
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"condition": "HTTP 403",
|
|
362
|
+
"meaning": "The key is valid but lacks the scope, or the plan excludes it.",
|
|
363
|
+
"agentAction": "Report which operation was refused. Do not try a different tool to route around it."
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"condition": "HTTP 429",
|
|
367
|
+
"meaning": "Rate limited.",
|
|
368
|
+
"agentAction": "Wait the Retry-After seconds, then retry once."
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"condition": "HTTP 409 IDEMPOTENCY_REQUEST_IN_PROGRESS",
|
|
372
|
+
"meaning": "The first attempt's outcome could not be recorded; the server refuses to execute twice.",
|
|
373
|
+
"agentAction": "Read the resource back and reconcile from its actual state. Never retry with a fresh Idempotency-Key."
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"condition": "capability.callability is deferred or unavailable",
|
|
377
|
+
"meaning": "The tool is registered but the backing API is not serving it.",
|
|
378
|
+
"agentAction": "Do not call it. Tell the human the capability is not live for this workspace."
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
}
|