@frihet/mcp-server 1.16.6 → 2.0.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 +168 -82
- 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 +552 -0
- package/dist/capability-truth.d.ts +29 -0
- package/dist/capability-truth.js +262 -0
- package/dist/claude-candidate-contract.d.ts +482 -0
- package/dist/claude-candidate-contract.js +87 -0
- package/dist/claude-output-privacy.d.ts +17 -0
- package/dist/claude-output-privacy.js +240 -0
- package/dist/claude-profile.d.ts +18 -0
- package/dist/claude-profile.js +260 -0
- package/dist/client-interface.d.ts +47 -33
- package/dist/client.d.ts +172 -40
- package/dist/client.js +708 -165
- package/dist/demo-client.d.ts +41 -32
- package/dist/demo-client.js +202 -31
- package/dist/demo-fixtures.d.ts +3 -3
- package/dist/demo-fixtures.js +7 -7
- package/dist/deposit-contract.d.ts +29 -0
- package/dist/deposit-contract.js +76 -0
- package/dist/fetch-no-redirect.d.ts +3 -0
- package/dist/fetch-no-redirect.js +16 -0
- package/dist/fiscal-aliases.d.ts +44 -0
- package/dist/fiscal-aliases.js +62 -0
- package/dist/fiscal-period.d.ts +26 -0
- package/dist/fiscal-period.js +31 -0
- package/dist/google-profile.d.ts +19 -0
- package/dist/google-profile.js +122 -0
- package/dist/index.js +68 -59
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +140 -8
- package/dist/muse-profile.d.ts +19 -0
- package/dist/muse-profile.js +122 -0
- package/dist/observability.d.ts +18 -29
- package/dist/observability.js +194 -106
- package/dist/openai-profile.d.ts +26 -22
- package/dist/openai-profile.js +1193 -157
- package/dist/openai-review-contract.d.ts +15 -6
- package/dist/openai-review-contract.js +714 -41
- package/dist/openai-review-oauth.d.ts +149 -2
- package/dist/openai-review-oauth.js +220 -6
- package/dist/prompts/register-all.d.ts +2 -0
- package/dist/prompts/register-all.js +34 -78
- package/dist/public-capability-contract.d.ts +39 -0
- package/dist/public-capability-contract.js +186 -0
- package/dist/redaction.d.ts +15 -0
- package/dist/redaction.js +83 -0
- package/dist/resources/register-all.js +154 -64
- package/dist/retry-after.d.ts +19 -0
- package/dist/retry-after.js +84 -0
- package/dist/server-composition.d.ts +19 -0
- package/dist/server-composition.js +74 -0
- package/dist/tool-exposure.d.ts +31 -27
- package/dist/tool-exposure.js +211 -87
- package/dist/tools/accountingClose.d.ts +14 -5
- package/dist/tools/accountingClose.js +41 -23
- package/dist/tools/audit_gl.js +8 -8
- package/dist/tools/backend-availability.d.ts +8 -29
- package/dist/tools/backend-availability.js +31 -30
- package/dist/tools/bank_rules.js +66 -15
- package/dist/tools/banking.js +5 -13
- package/dist/tools/clients.js +261 -15
- package/dist/tools/crm.js +22 -21
- package/dist/tools/deposits.js +114 -85
- package/dist/tools/einvoice.d.ts +16 -2
- package/dist/tools/einvoice.js +59 -12
- package/dist/tools/expenses.d.ts +16 -0
- package/dist/tools/expenses.js +47 -27
- package/dist/tools/fiscal.d.ts +3 -4
- package/dist/tools/fiscal.js +93 -60
- package/dist/tools/gestoria.js +15 -7
- package/dist/tools/hr.d.ts +2 -3
- package/dist/tools/hr.js +49 -20
- package/dist/tools/igic.d.ts +9 -8
- package/dist/tools/igic.js +34 -64
- package/dist/tools/impuesto_sociedades.d.ts +4 -5
- package/dist/tools/impuesto_sociedades.js +16 -37
- package/dist/tools/intelligence.js +166 -12
- package/dist/tools/invoices.js +224 -54
- package/dist/tools/kitchen.js +19 -9
- 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 +172 -26
- package/dist/tools/recurring.js +26 -25
- package/dist/tools/register-all.d.ts +2 -2
- package/dist/tools/register-all.js +9 -6
- package/dist/tools/search.d.ts +19 -0
- package/dist/tools/search.js +84 -0
- package/dist/tools/shared.d.ts +1445 -109
- package/dist/tools/shared.js +478 -102
- package/dist/tools/team.js +24 -28
- package/dist/tools/time.js +4 -12
- package/dist/tools/vendors.js +249 -15
- package/dist/tools/webhooks.js +35 -30
- package/dist/types.d.ts +31 -5
- package/dist/workflows/daily-operational-brief.d.ts +163 -0
- package/dist/workflows/daily-operational-brief.js +881 -0
- package/docs/agent-onboarding.json +391 -0
- package/package.json +49 -12
- package/dist/tools/onboarding.d.ts +0 -19
- package/dist/tools/onboarding.js +0 -64
|
@@ -14,7 +14,12 @@ export const MCP_RESOURCE_COUNT = MCP_STATIC_RESOURCE_COUNT + MCP_DYNAMIC_RESOUR
|
|
|
14
14
|
/* ------------------------------------------------------------------ */
|
|
15
15
|
/* Static data */
|
|
16
16
|
/* ------------------------------------------------------------------ */
|
|
17
|
-
const API_SCHEMA_SUMMARY = `Frihet ERP REST API —
|
|
17
|
+
const API_SCHEMA_SUMMARY = `Frihet ERP REST API — Informational Reference Summary Snapshot
|
|
18
|
+
=============================================================
|
|
19
|
+
Notice: This resource is an informational, non-exhaustive reference snapshot
|
|
20
|
+
of core REST endpoints for LLM context. The canonical, authoritative live
|
|
21
|
+
contract is the OpenAPI 3.1 specification at https://api.frihet.io/v1/openapi.json.
|
|
22
|
+
|
|
18
23
|
Base URL: https://api.frihet.io/v1
|
|
19
24
|
Docs: https://docs.frihet.io/desarrolladores/api-reference
|
|
20
25
|
|
|
@@ -58,13 +63,13 @@ Endpoints:
|
|
|
58
63
|
PATCH /quotes/:id — Update quote
|
|
59
64
|
DELETE /quotes/:id — Delete quote
|
|
60
65
|
|
|
61
|
-
GET /webhooks — List webhooks (
|
|
66
|
+
GET /webhooks — List webhooks (unpaginated)
|
|
62
67
|
GET /webhooks/:id — Get webhook by ID
|
|
63
68
|
POST /webhooks — Create webhook
|
|
64
69
|
PATCH /webhooks/:id — Update webhook
|
|
65
70
|
DELETE /webhooks/:id — Delete webhook
|
|
66
71
|
|
|
67
|
-
Pagination:
|
|
72
|
+
Pagination (list families that expose limit/offset; webhooks are unpaginated):
|
|
68
73
|
Query params: limit (1-100, default 50), offset (default 0)
|
|
69
74
|
Response: { data: [...], total: number, limit: number, offset: number }
|
|
70
75
|
|
|
@@ -77,10 +82,20 @@ Error responses:
|
|
|
77
82
|
500 — Internal server error
|
|
78
83
|
|
|
79
84
|
Content-Type: application/json
|
|
80
|
-
|
|
85
|
+
Monetary values use the currency declared by each record; amounts are decimal major units.
|
|
81
86
|
Dates in ISO 8601 format (YYYY-MM-DD or full datetime).`;
|
|
82
|
-
const TAX_RATES = `Spanish Tax Rates
|
|
83
|
-
|
|
87
|
+
const TAX_RATES = `Spanish Tax Rates & Fiscal Zones — Informational Reference Schedule
|
|
88
|
+
===================================================================
|
|
89
|
+
Authority:
|
|
90
|
+
- Peninsula & Balearics (IVA): Ley 37/1992 del IVA (AEAT)
|
|
91
|
+
- Canary Islands (IGIC): Ley 20/1991 del IGIC (Agencia Tributaria Canaria)
|
|
92
|
+
- Ceuta & Melilla (IPSI): Ley 8/1991 del IPSI (Servicios Tributarios locales)
|
|
93
|
+
- Withholding (IRPF): Ley 35/2006 del IRPF (AEAT)
|
|
94
|
+
- EU Intra-community: Council Directive 2006/112/EC (Reverse Charge / OSS)
|
|
95
|
+
|
|
96
|
+
Notice: This resource provides reference rate schedules and classification guidelines.
|
|
97
|
+
It is NOT a dynamic tax engine. Transaction rates must be validated against the operation
|
|
98
|
+
date, place of supply, and fiscal status. Server endpoints validate fiscal rules server-side.
|
|
84
99
|
|
|
85
100
|
PENINSULA & BALEARIC ISLANDS — IVA (Impuesto sobre el Valor Añadido)
|
|
86
101
|
General: 21% — Most goods and services
|
|
@@ -121,8 +136,15 @@ SPECIAL REGIMES
|
|
|
121
136
|
Applies to: Retail businesses (comercio minorista) buying from wholesalers
|
|
122
137
|
Simplified regime: Fixed quarterly quotas based on activity modules
|
|
123
138
|
Agriculture: 12% / 10.5% flat-rate compensation`;
|
|
124
|
-
const TAX_CALENDAR = `Spanish
|
|
125
|
-
|
|
139
|
+
const TAX_CALENDAR = `Spanish Tax Calendar — Statutory Filing Deadlines Reference
|
|
140
|
+
===========================================================
|
|
141
|
+
Authority: Calendario del Contribuyente (Agencia Tributaria AEAT / ATC)
|
|
142
|
+
|
|
143
|
+
Notice: Informational reference of general quarterly and annual statutory filing
|
|
144
|
+
deadlines in Spain. Deadlines shifting to next business day on weekends/holidays
|
|
145
|
+
or direct-debit (domiciliación bancaria) advance deadlines (typically 5 days earlier)
|
|
146
|
+
are not modeled here. Always verify filing dates with your gestoría or official
|
|
147
|
+
AEAT/ATC electronic office.
|
|
126
148
|
|
|
127
149
|
All deadlines apply to the corresponding fiscal quarter unless noted.
|
|
128
150
|
|
|
@@ -163,19 +185,21 @@ CANARY ISLANDS (IGIC instead of IVA)
|
|
|
163
185
|
Modelo 425 — Annual IGIC summary (same deadline as Modelo 390)
|
|
164
186
|
Filed with ATC (Administración Tributaria Canaria), NOT AEAT
|
|
165
187
|
|
|
166
|
-
VERIFACTU (mandatory e-invoicing, phased rollout)
|
|
167
|
-
2026: Voluntary adoption
|
|
168
|
-
2027: Mandatory for large companies
|
|
169
|
-
2028: Mandatory for all businesses
|
|
170
|
-
|
|
171
188
|
KEY DATES SUMMARY
|
|
172
189
|
Apr 20 — Q1 filings
|
|
173
190
|
Jul 20 — Q2 filings
|
|
174
191
|
Oct 20 — Q3 filings
|
|
175
192
|
Jan 30 — Q4 filings + annual summaries (390, 180, 190)
|
|
176
193
|
Apr 1–Jun 30 — Annual income tax (Modelo 100)`;
|
|
177
|
-
const EXPENSE_CATEGORIES = `Frihet Expense Categories & Deductibility
|
|
178
|
-
|
|
194
|
+
const EXPENSE_CATEGORIES = `Frihet Expense Categories & Statutory Deductibility Guidelines
|
|
195
|
+
==============================================================
|
|
196
|
+
Authority: Statutory deductibility rules derived from Ley 35/2006 (IRPF, art. 30)
|
|
197
|
+
and Ley 37/1992 (IVA, arts. 92-96).
|
|
198
|
+
|
|
199
|
+
Notice: Frihet standard business category mapping with statutory deductibility rules.
|
|
200
|
+
Deductibility requires valid invoices, direct correlation with business activity
|
|
201
|
+
(afectación exclusiva), and accounting registration. Consult your tax advisor
|
|
202
|
+
(gestoría) for specific amortizations or mixed-use deductions.
|
|
179
203
|
|
|
180
204
|
1. OFFICE (oficina)
|
|
181
205
|
Examples: Rent, utilities, internet, phone, office supplies, cleaning
|
|
@@ -232,13 +256,25 @@ const INVOICE_STATUSES = `Frihet Invoice Status Flow
|
|
|
232
256
|
Statuses and transitions:
|
|
233
257
|
|
|
234
258
|
DRAFT ──────► SENT ──────► PAID
|
|
235
|
-
│ │
|
|
236
|
-
│
|
|
237
|
-
│
|
|
238
|
-
│
|
|
239
|
-
│
|
|
259
|
+
│ │ ▲
|
|
260
|
+
│ ├──────► PARTIAL ────┤
|
|
261
|
+
│ │ │ │
|
|
262
|
+
│ └──────► OVERDUE ────┤
|
|
263
|
+
│ │ │
|
|
264
|
+
│ └────────┼───► CANCELLED
|
|
265
|
+
│ │
|
|
266
|
+
│ ▼
|
|
267
|
+
│ REFUND / RECTIFICATIVE
|
|
240
268
|
└─────────────────────────────────► CANCELLED
|
|
241
269
|
|
|
270
|
+
Legal transition paths:
|
|
271
|
+
draft -> sent | cancelled
|
|
272
|
+
sent -> paid | partial | overdue | cancelled
|
|
273
|
+
partial -> paid | overdue | cancelled
|
|
274
|
+
overdue -> paid | partial | cancelled
|
|
275
|
+
paid -> refund (via credit note / rectificative invoice)
|
|
276
|
+
partial -> refund (via credit note / rectificative invoice)
|
|
277
|
+
|
|
242
278
|
Status definitions:
|
|
243
279
|
|
|
244
280
|
draft — Invoice created but not yet sent to client.
|
|
@@ -249,31 +285,40 @@ Status definitions:
|
|
|
249
285
|
Payment is expected. The invoice number and date become
|
|
250
286
|
fiscally relevant — avoid modifications after this point.
|
|
251
287
|
|
|
252
|
-
|
|
288
|
+
partial — Invoice partially paid. A partial payment has been recorded,
|
|
289
|
+
with a remaining positive balance due. Can transition to
|
|
290
|
+
paid upon full payment, overdue if dueDate passes with
|
|
291
|
+
remaining balance, or cancelled/credit note.
|
|
292
|
+
|
|
293
|
+
paid — Payment received in full. Terminal state for settlement.
|
|
253
294
|
Records the payment date. Invoice is complete.
|
|
254
295
|
|
|
255
|
-
overdue — Payment deadline (dueDate) has passed without payment.
|
|
256
|
-
|
|
257
|
-
|
|
296
|
+
overdue — Payment deadline (dueDate) has passed without full payment.
|
|
297
|
+
Applies to sent or partial invoices. Triggers follow-up
|
|
298
|
+
workflows. Can transition to paid (late payment), partial,
|
|
299
|
+
or cancelled (write-off / bad debt).
|
|
258
300
|
|
|
259
301
|
cancelled — Invoice voided. Requires a corrective invoice or
|
|
260
302
|
credit note for fiscal compliance if previously sent.
|
|
261
303
|
Terminal state. Cannot transition to other statuses.
|
|
262
304
|
|
|
263
305
|
Automation rules (when configured):
|
|
264
|
-
- Auto-transition sent → overdue when dueDate passes (daily check)
|
|
265
|
-
- Webhook events: invoice.created, invoice.
|
|
266
|
-
invoice.overdue, invoice.
|
|
306
|
+
- Auto-transition sent/partial → overdue when dueDate passes (daily check)
|
|
307
|
+
- Webhook events: invoice.created, invoice.updated, invoice.generated,
|
|
308
|
+
invoice.one_off_created, invoice.paid, invoice.overdue, invoice.voided,
|
|
309
|
+
invoice.payment_status_updated, invoice.payment_failure
|
|
310
|
+
- A partial payment is reported via invoice.payment_status_updated;
|
|
311
|
+
cancellation is reported via invoice.voided
|
|
267
312
|
- Overdue reminders can be configured per-client
|
|
268
313
|
|
|
269
314
|
Best practices:
|
|
270
315
|
- Always set a dueDate when creating invoices (default: 30 days)
|
|
271
316
|
- Use draft status while iterating with the client
|
|
272
317
|
- Once sent, create a new corrective invoice rather than editing
|
|
273
|
-
- For partial payments,
|
|
318
|
+
- For partial payments, invoice transitions to partial with remaining balance tracked
|
|
274
319
|
- cancelled requires a reason (notes field) for audit trail`;
|
|
275
320
|
const CURRENCIES = JSON.stringify({
|
|
276
|
-
EUR: { name: "Euro", symbol: "\u20ac", decimals: 2, format: "1.234,56 \u20ac", countries: ["ES", "DE", "FR", "IT", "NL", "PT", "BE", "AT", "IE", "FI", "GR", "LU", "SK", "SI", "EE", "LV", "LT", "CY", "MT"] },
|
|
321
|
+
EUR: { name: "Euro", symbol: "\u20ac", decimals: 2, format: "1.234,56 \u20ac", countries: ["ES", "DE", "FR", "IT", "NL", "PT", "BE", "AT", "IE", "FI", "GR", "LU", "SK", "SI", "EE", "LV", "LT", "CY", "MT", "BG", "HR"] },
|
|
277
322
|
USD: { name: "US Dollar", symbol: "$", decimals: 2, format: "$1,234.56", countries: ["US"] },
|
|
278
323
|
GBP: { name: "British Pound", symbol: "\u00a3", decimals: 2, format: "\u00a31,234.56", countries: ["GB"] },
|
|
279
324
|
CHF: { name: "Swiss Franc", symbol: "CHF", decimals: 2, format: "CHF 1'234.56", countries: ["CH"] },
|
|
@@ -289,8 +334,8 @@ const CURRENCIES = JSON.stringify({
|
|
|
289
334
|
CZK: { name: "Czech Koruna", symbol: "K\u010d", decimals: 2, format: "1 234,56 K\u010d", countries: ["CZ"] },
|
|
290
335
|
HUF: { name: "Hungarian Forint", symbol: "Ft", decimals: 0, format: "1 234 Ft", countries: ["HU"] },
|
|
291
336
|
RON: { name: "Romanian Leu", symbol: "lei", decimals: 2, format: "1.234,56 lei", countries: ["RO"] },
|
|
292
|
-
BGN: { name: "Bulgarian Lev", symbol: "\u043b\u0432", decimals: 2, format: "1 234,56 \u043b\u0432", countries: [
|
|
293
|
-
HRK: { name: "Croatian Kuna", symbol: "kn", decimals: 2, format: "1.234,56 kn", countries: [
|
|
337
|
+
BGN: { name: "Bulgarian Lev", symbol: "\u043b\u0432", decimals: 2, format: "1 234,56 \u043b\u0432", countries: [] },
|
|
338
|
+
HRK: { name: "Croatian Kuna", symbol: "kn", decimals: 2, format: "1.234,56 kn", countries: [] },
|
|
294
339
|
ISK: { name: "Icelandic Kr\u00f3na", symbol: "kr", decimals: 0, format: "1.234 kr", countries: ["IS"] },
|
|
295
340
|
TRY: { name: "Turkish Lira", symbol: "\u20ba", decimals: 2, format: "\u20ba1.234,56", countries: ["TR"] },
|
|
296
341
|
ILS: { name: "Israeli Shekel", symbol: "\u20aa", decimals: 2, format: "\u20aa1,234.56", countries: ["IL"] },
|
|
@@ -327,12 +372,12 @@ const COUNTRIES = JSON.stringify([
|
|
|
327
372
|
{ name: "Portugal", code: "PT", fiscalZone: "eu", defaultTaxRate: 23, taxName: "IVA", currency: "EUR", invoicePrefix: "FT" },
|
|
328
373
|
{ name: "Austria", code: "AT", fiscalZone: "eu", defaultTaxRate: 20, taxName: "USt", currency: "EUR", invoicePrefix: "RE" },
|
|
329
374
|
{ name: "Ireland", code: "IE", fiscalZone: "eu", defaultTaxRate: 23, taxName: "VAT", currency: "EUR", invoicePrefix: "INV" },
|
|
330
|
-
{ name: "Finland", code: "FI", fiscalZone: "eu", defaultTaxRate:
|
|
375
|
+
{ name: "Finland", code: "FI", fiscalZone: "eu", defaultTaxRate: 25.5, taxName: "ALV", currency: "EUR", invoicePrefix: "INV" },
|
|
331
376
|
{ name: "Greece", code: "GR", fiscalZone: "eu", defaultTaxRate: 24, taxName: "FPA", currency: "EUR", invoicePrefix: "TIM" },
|
|
332
377
|
{ name: "Luxembourg", code: "LU", fiscalZone: "eu", defaultTaxRate: 17, taxName: "TVA", currency: "EUR", invoicePrefix: "F" },
|
|
333
|
-
{ name: "Slovakia", code: "SK", fiscalZone: "eu", defaultTaxRate:
|
|
378
|
+
{ name: "Slovakia", code: "SK", fiscalZone: "eu", defaultTaxRate: 23, taxName: "DPH", currency: "EUR", invoicePrefix: "F" },
|
|
334
379
|
{ name: "Slovenia", code: "SI", fiscalZone: "eu", defaultTaxRate: 22, taxName: "DDV", currency: "EUR", invoicePrefix: "F" },
|
|
335
|
-
{ name: "Estonia", code: "EE", fiscalZone: "eu", defaultTaxRate:
|
|
380
|
+
{ name: "Estonia", code: "EE", fiscalZone: "eu", defaultTaxRate: 24, taxName: "KM", currency: "EUR", invoicePrefix: "INV" },
|
|
336
381
|
{ name: "Latvia", code: "LV", fiscalZone: "eu", defaultTaxRate: 21, taxName: "PVN", currency: "EUR", invoicePrefix: "INV" },
|
|
337
382
|
{ name: "Lithuania", code: "LT", fiscalZone: "eu", defaultTaxRate: 21, taxName: "PVM", currency: "EUR", invoicePrefix: "SF" },
|
|
338
383
|
{ name: "Cyprus", code: "CY", fiscalZone: "eu", defaultTaxRate: 19, taxName: "VAT", currency: "EUR", invoicePrefix: "INV" },
|
|
@@ -342,8 +387,8 @@ const COUNTRIES = JSON.stringify([
|
|
|
342
387
|
{ name: "Poland", code: "PL", fiscalZone: "eu", defaultTaxRate: 23, taxName: "VAT", currency: "PLN", invoicePrefix: "FV" },
|
|
343
388
|
{ name: "Czech Republic", code: "CZ", fiscalZone: "eu", defaultTaxRate: 21, taxName: "DPH", currency: "CZK", invoicePrefix: "F" },
|
|
344
389
|
{ name: "Hungary", code: "HU", fiscalZone: "eu", defaultTaxRate: 27, taxName: "\u00c1FA", currency: "HUF", invoicePrefix: "SZ" },
|
|
345
|
-
{ name: "Romania", code: "RO", fiscalZone: "eu", defaultTaxRate:
|
|
346
|
-
{ name: "Bulgaria", code: "BG", fiscalZone: "eu", defaultTaxRate: 20, taxName: "DDS", currency: "
|
|
390
|
+
{ name: "Romania", code: "RO", fiscalZone: "eu", defaultTaxRate: 21, taxName: "TVA", currency: "RON", invoicePrefix: "F" },
|
|
391
|
+
{ name: "Bulgaria", code: "BG", fiscalZone: "eu", defaultTaxRate: 20, taxName: "DDS", currency: "EUR", invoicePrefix: "F" },
|
|
347
392
|
{ name: "Croatia", code: "HR", fiscalZone: "eu", defaultTaxRate: 25, taxName: "PDV", currency: "EUR", invoicePrefix: "R" },
|
|
348
393
|
{ name: "United Kingdom", code: "GB", fiscalZone: "international", defaultTaxRate: 20, taxName: "VAT", currency: "GBP", invoicePrefix: "INV" },
|
|
349
394
|
{ name: "United States", code: "US", fiscalZone: "international", defaultTaxRate: 0, taxName: "Sales Tax", currency: "USD", invoicePrefix: "INV" },
|
|
@@ -382,8 +427,9 @@ const COUNTRIES = JSON.stringify([
|
|
|
382
427
|
/* ------------------------------------------------------------------ */
|
|
383
428
|
export function registerAllResources(server, client) {
|
|
384
429
|
server.registerResource("api-schema", "frihet://api/schema", {
|
|
385
|
-
description: "
|
|
386
|
-
"
|
|
430
|
+
description: "Informational snapshot summary of selected core REST endpoints, auth, and rate limits. " +
|
|
431
|
+
"Canonical contract: https://api.frihet.io/v1/openapi.json. " +
|
|
432
|
+
"/ Resumen informativo no exhaustivo de endpoints REST principales; el contrato canónico reside en openapi.json.",
|
|
387
433
|
mimeType: "text/plain",
|
|
388
434
|
}, async () => ({
|
|
389
435
|
contents: [
|
|
@@ -395,9 +441,9 @@ export function registerAllResources(server, client) {
|
|
|
395
441
|
],
|
|
396
442
|
}));
|
|
397
443
|
server.registerResource("tax-rates", "frihet://tax/rates", {
|
|
398
|
-
description: "
|
|
399
|
-
"
|
|
400
|
-
"/
|
|
444
|
+
description: "Spanish statutory tax rate reference (AEAT/ATC/IPSI, IVA/IGIC/IPSI/IRPF). " +
|
|
445
|
+
"Informational reference schedule; server validates tax math per transaction. " +
|
|
446
|
+
"/ Referencia normativa de tipos impositivos por zona fiscal en España.",
|
|
401
447
|
mimeType: "text/plain",
|
|
402
448
|
}, async () => ({
|
|
403
449
|
contents: [
|
|
@@ -409,9 +455,9 @@ export function registerAllResources(server, client) {
|
|
|
409
455
|
],
|
|
410
456
|
}));
|
|
411
457
|
server.registerResource("tax-calendar", "frihet://tax/calendar", {
|
|
412
|
-
description: "Spanish
|
|
413
|
-
"
|
|
414
|
-
"/ Calendario fiscal trimestral español con plazos de presentación de modelos
|
|
458
|
+
description: "Spanish tax filing calendar reference (Calendario del Contribuyente AEAT/ATC). " +
|
|
459
|
+
"Informational reference for statutory filing deadlines. " +
|
|
460
|
+
"/ Calendario fiscal trimestral español con plazos de presentación de modelos.",
|
|
415
461
|
mimeType: "text/plain",
|
|
416
462
|
}, async () => ({
|
|
417
463
|
contents: [
|
|
@@ -423,8 +469,8 @@ export function registerAllResources(server, client) {
|
|
|
423
469
|
],
|
|
424
470
|
}));
|
|
425
471
|
server.registerResource("expense-categories", "frihet://config/expense-categories", {
|
|
426
|
-
description: "
|
|
427
|
-
"
|
|
472
|
+
description: "Frihet standard expense categories and statutory deductibility guidelines (LIRPF/LIVA). " +
|
|
473
|
+
"Informational classification guide. " +
|
|
428
474
|
"/ Las 8 categorías de gastos con reglas de deducibilidad, IVA y amortización.",
|
|
429
475
|
mimeType: "text/plain",
|
|
430
476
|
}, async () => ({
|
|
@@ -451,9 +497,9 @@ export function registerAllResources(server, client) {
|
|
|
451
497
|
],
|
|
452
498
|
}));
|
|
453
499
|
server.registerResource("currencies", "frihet://config/currencies", {
|
|
454
|
-
description: "
|
|
455
|
-
"
|
|
456
|
-
"/
|
|
500
|
+
description: "Currency codes, symbols and display formatting examples with associated countries, including historical codes. " +
|
|
501
|
+
"Decimals describe these display examples, not authoritative payment precision, conversion rates or API acceptance. " +
|
|
502
|
+
"/ Códigos y ejemplos de formato de divisas; no determinan precisión de pagos ni tipos de cambio.",
|
|
457
503
|
mimeType: "application/json",
|
|
458
504
|
}, async () => ({
|
|
459
505
|
contents: [
|
|
@@ -465,9 +511,9 @@ export function registerAllResources(server, client) {
|
|
|
465
511
|
],
|
|
466
512
|
}));
|
|
467
513
|
server.registerResource("countries", "frihet://config/countries", {
|
|
468
|
-
description: "
|
|
469
|
-
"default tax rates, tax names, default currencies, and invoice prefixes. " +
|
|
470
|
-
"/
|
|
514
|
+
description: "Supported countries with ISO codes, fiscal zones (peninsula, canarias, ceuta, melilla, eu, international), " +
|
|
515
|
+
"default tax rates, tax names, default currencies, and invoice prefixes. Note: default rates are onboarding suggestions only, not legal determination. " +
|
|
516
|
+
"/ Países soportados con zonas fiscales, tipos impositivos por defecto y prefijos de factura.",
|
|
471
517
|
mimeType: "application/json",
|
|
472
518
|
}, async () => ({
|
|
473
519
|
contents: [
|
|
@@ -517,33 +563,77 @@ export function registerAllResources(server, client) {
|
|
|
517
563
|
};
|
|
518
564
|
});
|
|
519
565
|
server.registerResource("overdue-invoices", "frihet://overdue-invoices", {
|
|
520
|
-
description: "Live
|
|
521
|
-
"
|
|
522
|
-
"
|
|
566
|
+
description: "Live invoice records filtered by status overdue (first page up to 100 items). " +
|
|
567
|
+
"Returns stored fields and pagination bounds; does not calculate unpaid balances or days overdue. " +
|
|
568
|
+
"Paginate list_invoices without a status filter and select sent, partial and overdue records client-side for a complete receivables review. " +
|
|
569
|
+
"/ Registros con estado vencida (primera página hasta 100); no calcula saldos pendientes ni días de retraso.",
|
|
523
570
|
mimeType: "application/json",
|
|
524
571
|
}, async () => {
|
|
525
|
-
const
|
|
572
|
+
const response = await client.listInvoices({ status: "overdue", limit: 100 });
|
|
573
|
+
const list = Array.isArray(response)
|
|
574
|
+
? response
|
|
575
|
+
: Array.isArray(response.data)
|
|
576
|
+
? (response.data)
|
|
577
|
+
: [];
|
|
578
|
+
const total = typeof response.total === "number"
|
|
579
|
+
? (response.total)
|
|
580
|
+
: list.length;
|
|
581
|
+
const result = {
|
|
582
|
+
data: list,
|
|
583
|
+
total,
|
|
584
|
+
limit: 100,
|
|
585
|
+
offset: 0,
|
|
586
|
+
hasMore: total > 100 || list.length === 100,
|
|
587
|
+
note: "First 100 records with status overdue; not a complete receivables or unpaid-balance report",
|
|
588
|
+
};
|
|
526
589
|
return {
|
|
527
590
|
contents: [
|
|
528
591
|
{
|
|
529
592
|
uri: "frihet://overdue-invoices",
|
|
530
593
|
mimeType: "application/json",
|
|
531
|
-
text: JSON.stringify(
|
|
594
|
+
text: JSON.stringify(result, null, 2),
|
|
532
595
|
},
|
|
533
596
|
],
|
|
534
597
|
};
|
|
535
598
|
});
|
|
536
599
|
server.registerResource("plan-limits", "frihet://status/plan-limits", {
|
|
537
|
-
description: "Live plan
|
|
538
|
-
"
|
|
539
|
-
"/ Límites del plan y uso actual en vivo — tier, facturas/mes, mensajes IA/día, miembros, integraciones, API req/min.",
|
|
600
|
+
description: "Live plan tier, quotas, and usage counters (invoices, expenses, AI messages) from business context. " +
|
|
601
|
+
"/ Nivel de plan, cuotas y contadores de uso (facturas, gastos, mensajes IA) del contexto del negocio.",
|
|
540
602
|
mimeType: "application/json",
|
|
541
603
|
}, async () => {
|
|
542
604
|
const ctx = await client.getBusinessContext();
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
605
|
+
const planRaw = ctx.plan;
|
|
606
|
+
let plan = "free";
|
|
607
|
+
let limits = ctx.limits;
|
|
608
|
+
let usage = ctx.usage;
|
|
609
|
+
if (typeof planRaw === "string") {
|
|
610
|
+
plan = planRaw;
|
|
611
|
+
}
|
|
612
|
+
else if (typeof planRaw === "object" && planRaw !== null) {
|
|
613
|
+
const planObj = planRaw;
|
|
614
|
+
plan = typeof planObj.name === "string" ? planObj.name : "free";
|
|
615
|
+
if ((!limits || Object.keys(limits).length === 0) && (!usage || Object.keys(usage).length === 0)) {
|
|
616
|
+
const extractedLimits = {};
|
|
617
|
+
const extractedUsage = {};
|
|
618
|
+
for (const [key, val] of Object.entries(planObj)) {
|
|
619
|
+
if (key !== "name" && typeof val === "object" && val !== null) {
|
|
620
|
+
const item = val;
|
|
621
|
+
if ("limit" in item)
|
|
622
|
+
extractedLimits[key] = item.limit;
|
|
623
|
+
if ("used" in item)
|
|
624
|
+
extractedUsage[key] = item.used;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
limits = extractedLimits;
|
|
628
|
+
usage = extractedUsage;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
const result = {
|
|
632
|
+
plan,
|
|
633
|
+
limits: limits ?? {},
|
|
634
|
+
usage: usage ?? {},
|
|
635
|
+
...(typeof planRaw === "object" && planRaw !== null ? { breakdown: planRaw } : {}),
|
|
636
|
+
};
|
|
547
637
|
return {
|
|
548
638
|
contents: [
|
|
549
639
|
{
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Retry-After` parsing per RFC 9110 §10.2.3: either `delay-seconds`
|
|
3
|
+
* (1*DIGIT) or an HTTP-date. Returns the wait in milliseconds, or `null` when
|
|
4
|
+
* the value is absent or malformed so the caller falls back to its own
|
|
5
|
+
* backoff — never NaN, never negative.
|
|
6
|
+
*
|
|
7
|
+
* Semantics:
|
|
8
|
+
* - delay-seconds: strict non-negative integer digits only (no sign, decimal
|
|
9
|
+
* point, exponent or whitespace inside). Values too large to represent
|
|
10
|
+
* safely are clamped to MAX_SAFE_INTEGER ms, which always exceeds any retry
|
|
11
|
+
* budget and therefore defers instead of sleeping.
|
|
12
|
+
* - HTTP-date: IMF-fixdate, obsolete RFC 850 and ANSI C asctime() forms, all
|
|
13
|
+
* read as GMT. The wait is `date - now`; a date already in the past means
|
|
14
|
+
* the server's embargo has expired, so the wait is 0 (not negative). Clock
|
|
15
|
+
* skew is NOT compensated: shortening the wait would retry earlier than the
|
|
16
|
+
* server asked, lengthening it would hide a valid answer.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseRetryAfter(value: string | null | undefined, nowMs: number): number | null;
|
|
19
|
+
//# sourceMappingURL=retry-after.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Retry-After` parsing per RFC 9110 §10.2.3: either `delay-seconds`
|
|
3
|
+
* (1*DIGIT) or an HTTP-date. Returns the wait in milliseconds, or `null` when
|
|
4
|
+
* the value is absent or malformed so the caller falls back to its own
|
|
5
|
+
* backoff — never NaN, never negative.
|
|
6
|
+
*
|
|
7
|
+
* Semantics:
|
|
8
|
+
* - delay-seconds: strict non-negative integer digits only (no sign, decimal
|
|
9
|
+
* point, exponent or whitespace inside). Values too large to represent
|
|
10
|
+
* safely are clamped to MAX_SAFE_INTEGER ms, which always exceeds any retry
|
|
11
|
+
* budget and therefore defers instead of sleeping.
|
|
12
|
+
* - HTTP-date: IMF-fixdate, obsolete RFC 850 and ANSI C asctime() forms, all
|
|
13
|
+
* read as GMT. The wait is `date - now`; a date already in the past means
|
|
14
|
+
* the server's embargo has expired, so the wait is 0 (not negative). Clock
|
|
15
|
+
* skew is NOT compensated: shortening the wait would retry earlier than the
|
|
16
|
+
* server asked, lengthening it would hide a valid answer.
|
|
17
|
+
*/
|
|
18
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
19
|
+
const DAYS_LONG = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
20
|
+
const DAYS_SHORT = DAYS_LONG.map((d) => d.slice(0, 3));
|
|
21
|
+
const IMF_FIXDATE = /^([A-Z][a-z]{2}), (\d{2}) ([A-Z][a-z]{2}) (\d{4}) (\d{2}):(\d{2}):(\d{2}) GMT$/;
|
|
22
|
+
const RFC850_DATE = /^([A-Z][a-z]+day), (\d{2})-([A-Z][a-z]{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) GMT$/;
|
|
23
|
+
const ASCTIME_DATE = /^([A-Z][a-z]{2}) ([A-Z][a-z]{2}) ([ \d]\d) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/;
|
|
24
|
+
function utcMs(year, monthName, day, h, m, s) {
|
|
25
|
+
const month = MONTHS.indexOf(monthName);
|
|
26
|
+
if (month < 0 || h > 23 || m > 59 || s > 60)
|
|
27
|
+
return null;
|
|
28
|
+
const ms = Date.UTC(year, month, day, h, m, s);
|
|
29
|
+
const check = new Date(ms);
|
|
30
|
+
// Reject roll-over such as "31 Feb" that Date.UTC silently normalizes.
|
|
31
|
+
if (check.getUTCFullYear() !== year
|
|
32
|
+
|| check.getUTCMonth() !== month
|
|
33
|
+
|| check.getUTCDate() !== day) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return ms;
|
|
37
|
+
}
|
|
38
|
+
function weekdayMatches(ms, name, list) {
|
|
39
|
+
// getUTCDay: 0 = Sunday; the lists start on Monday.
|
|
40
|
+
return list[(new Date(ms).getUTCDay() + 6) % 7] === name;
|
|
41
|
+
}
|
|
42
|
+
function parseHttpDate(value, nowMs) {
|
|
43
|
+
let m = IMF_FIXDATE.exec(value);
|
|
44
|
+
if (m) {
|
|
45
|
+
const ms = utcMs(+m[4], m[3], +m[2], +m[5], +m[6], +m[7]);
|
|
46
|
+
return ms !== null && weekdayMatches(ms, m[1], DAYS_SHORT) ? ms : null;
|
|
47
|
+
}
|
|
48
|
+
m = RFC850_DATE.exec(value);
|
|
49
|
+
if (m) {
|
|
50
|
+
// RFC 9110 §5.6.7: a two-digit year more than 50 years ahead is the past century.
|
|
51
|
+
const yy = +m[4];
|
|
52
|
+
const nowYear = new Date(nowMs).getUTCFullYear();
|
|
53
|
+
let year = Math.floor(nowYear / 100) * 100 + yy;
|
|
54
|
+
if (year > nowYear + 50)
|
|
55
|
+
year -= 100;
|
|
56
|
+
const ms = utcMs(year, m[3], +m[2], +m[5], +m[6], +m[7]);
|
|
57
|
+
return ms !== null && weekdayMatches(ms, m[1], DAYS_LONG) ? ms : null;
|
|
58
|
+
}
|
|
59
|
+
m = ASCTIME_DATE.exec(value);
|
|
60
|
+
if (m) {
|
|
61
|
+
const ms = utcMs(+m[7], m[2], +m[3].trim(), +m[4], +m[5], +m[6]);
|
|
62
|
+
return ms !== null && weekdayMatches(ms, m[1], DAYS_SHORT) ? ms : null;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
export function parseRetryAfter(value, nowMs) {
|
|
67
|
+
if (value === null || value === undefined)
|
|
68
|
+
return null;
|
|
69
|
+
const v = value.trim();
|
|
70
|
+
if (v === "")
|
|
71
|
+
return null;
|
|
72
|
+
if (/^\d+$/.test(v)) {
|
|
73
|
+
const seconds = Number(v);
|
|
74
|
+
if (!Number.isFinite(seconds) || seconds * 1000 > Number.MAX_SAFE_INTEGER) {
|
|
75
|
+
return Number.MAX_SAFE_INTEGER;
|
|
76
|
+
}
|
|
77
|
+
return seconds * 1000;
|
|
78
|
+
}
|
|
79
|
+
const dateMs = parseHttpDate(v, nowMs);
|
|
80
|
+
if (dateMs === null)
|
|
81
|
+
return null;
|
|
82
|
+
return Math.max(0, dateMs - nowMs);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=retry-after.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registration path shared by the stdio server, remote Worker, and
|
|
3
|
+
* generated public-surface contract. Transport/auth setup stays with each host;
|
|
4
|
+
* the exposed MCP operations/resources/prompts are composed here exactly once.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { IFrihetClient } from "./client-interface.js";
|
|
8
|
+
export interface McpSurfaceComposition {
|
|
9
|
+
readonly openaiMode: boolean;
|
|
10
|
+
readonly groupedMode: boolean;
|
|
11
|
+
readonly includeDynamicResources: boolean;
|
|
12
|
+
readonly claudeMode?: boolean;
|
|
13
|
+
readonly googleMode?: boolean;
|
|
14
|
+
readonly museMode?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function localMcpSurfaceComposition(openaiMode: boolean, groupedMode: boolean, claudeMode?: boolean, googleMode?: boolean, museMode?: boolean): McpSurfaceComposition;
|
|
17
|
+
export declare function remoteMcpSurfaceComposition(openaiMode: boolean, groupedMode: boolean, claudeMode?: boolean, googleMode?: boolean, museMode?: boolean): McpSurfaceComposition;
|
|
18
|
+
export declare function registerMcpSurface(server: McpServer, client: IFrihetClient, options: McpSurfaceComposition): void;
|
|
19
|
+
//# sourceMappingURL=server-composition.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registration path shared by the stdio server, remote Worker, and
|
|
3
|
+
* generated public-surface contract. Transport/auth setup stays with each host;
|
|
4
|
+
* the exposed MCP operations/resources/prompts are composed here exactly once.
|
|
5
|
+
*/
|
|
6
|
+
import { applyPublicCapabilityTruth, buildLocalDiscoveryCapability, CAPABILITY_META_KEY, } from "./capability-truth.js";
|
|
7
|
+
import { applyFiscalAliases } from "./fiscal-aliases.js";
|
|
8
|
+
import { applyClaudeCandidateProfile, CLAUDE_CANDIDATE_TOOLS, CLAUDE_GROUP_METADATA } from "./claude-profile.js";
|
|
9
|
+
import { applyGoogleProfile } from "./google-profile.js";
|
|
10
|
+
import { applyMuseProfile } from "./muse-profile.js";
|
|
11
|
+
import { applyOpenAIProfile, applyOpenAIReviewProfiles, } from "./openai-profile.js";
|
|
12
|
+
import { registerAllPrompts } from "./prompts/register-all.js";
|
|
13
|
+
import { registerAllResources } from "./resources/register-all.js";
|
|
14
|
+
import { applyToolExposureProfile } from "./tool-exposure.js";
|
|
15
|
+
import { registerAllTools } from "./tools/register-all.js";
|
|
16
|
+
export function localMcpSurfaceComposition(openaiMode, groupedMode, claudeMode = false, googleMode = false, museMode = false) {
|
|
17
|
+
return { openaiMode, groupedMode, includeDynamicResources: true, claudeMode, googleMode, museMode };
|
|
18
|
+
}
|
|
19
|
+
export function remoteMcpSurfaceComposition(openaiMode, groupedMode, claudeMode = false, googleMode = false, museMode = false) {
|
|
20
|
+
return { openaiMode, groupedMode, includeDynamicResources: false, claudeMode, googleMode, museMode };
|
|
21
|
+
}
|
|
22
|
+
export function registerMcpSurface(server, client, options) {
|
|
23
|
+
const activeModes = [options.openaiMode, options.claudeMode, options.googleMode, options.museMode].filter(Boolean).length;
|
|
24
|
+
if (activeModes > 1) {
|
|
25
|
+
throw new Error("FRIHET_OPENAI_MODE, FRIHET_CLAUDE_MODE, FRIHET_GOOGLE_MODE, and FRIHET_MUSE_MODE are mutually exclusive");
|
|
26
|
+
}
|
|
27
|
+
if (options.claudeMode) {
|
|
28
|
+
// Directory reads annotations.title. Install before grouped discovery eagerly
|
|
29
|
+
// registers its meta-tools, and clone annotations to preserve shared hints.
|
|
30
|
+
const registerTool = server.registerTool.bind(server);
|
|
31
|
+
server.registerTool = (name, config, handler) => registerTool(name, {
|
|
32
|
+
...config,
|
|
33
|
+
annotations: { ...config.annotations, title: config.title },
|
|
34
|
+
}, handler);
|
|
35
|
+
}
|
|
36
|
+
if (options.groupedMode) {
|
|
37
|
+
if (options.openaiMode) {
|
|
38
|
+
applyOpenAIReviewProfiles(server);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
applyToolExposureProfile(server, {
|
|
42
|
+
...(options.claudeMode ? {
|
|
43
|
+
allowlist: CLAUDE_CANDIDATE_TOOLS,
|
|
44
|
+
groupMetadata: CLAUDE_GROUP_METADATA,
|
|
45
|
+
describeToolExample: "list_invoices",
|
|
46
|
+
} : {}),
|
|
47
|
+
capabilityTruth: {
|
|
48
|
+
metaKey: CAPABILITY_META_KEY,
|
|
49
|
+
localDiscovery: buildLocalDiscoveryCapability,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (options.openaiMode) {
|
|
55
|
+
applyOpenAIProfile(server);
|
|
56
|
+
}
|
|
57
|
+
if (!options.openaiMode && !options.googleMode && !options.museMode) {
|
|
58
|
+
applyPublicCapabilityTruth(server);
|
|
59
|
+
}
|
|
60
|
+
if (options.claudeMode) {
|
|
61
|
+
applyClaudeCandidateProfile(server);
|
|
62
|
+
}
|
|
63
|
+
else if (options.googleMode) {
|
|
64
|
+
applyGoogleProfile(server);
|
|
65
|
+
}
|
|
66
|
+
else if (options.museMode) {
|
|
67
|
+
applyMuseProfile(server);
|
|
68
|
+
}
|
|
69
|
+
registerAllTools(server, client);
|
|
70
|
+
applyFiscalAliases(server);
|
|
71
|
+
registerAllResources(server, options.includeDynamicResources ? client : undefined);
|
|
72
|
+
registerAllPrompts(server);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=server-composition.js.map
|