@frihet/mcp-server 1.12.0-beta.1 → 1.13.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 +54 -8
- package/dist/__tests__/openai-profile.test.d.ts +10 -0
- package/dist/__tests__/openai-profile.test.d.ts.map +1 -0
- package/dist/__tests__/openai-profile.test.js +132 -0
- package/dist/__tests__/openai-profile.test.js.map +1 -0
- package/dist/__tests__/tool-exposure.test.d.ts +11 -0
- package/dist/__tests__/tool-exposure.test.d.ts.map +1 -0
- package/dist/__tests__/tool-exposure.test.js +249 -0
- package/dist/__tests__/tool-exposure.test.js.map +1 -0
- package/dist/client.d.ts +9 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +5 -3
- package/dist/client.js.map +1 -1
- package/dist/index.js +22 -5
- package/dist/index.js.map +1 -1
- package/dist/openai-profile.d.ts +4 -1
- package/dist/openai-profile.d.ts.map +1 -1
- package/dist/openai-profile.js +105 -1
- package/dist/openai-profile.js.map +1 -1
- package/dist/tool-exposure.d.ts +127 -0
- package/dist/tool-exposure.d.ts.map +1 -0
- package/dist/tool-exposure.js +453 -0
- package/dist/tool-exposure.js.map +1 -0
- package/dist/tools/register-all.d.ts +2 -2
- package/dist/tools/register-all.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -32,13 +32,15 @@
|
|
|
32
32
|
| **Remote endpoint** | Live | `https://mcp.frihet.io/mcp` (zero install, OAuth or API key) |
|
|
33
33
|
| **Smithery** | Live | [smithery.ai/server/frihet/frihet-mcp](https://smithery.ai/server/frihet/frihet-mcp) |
|
|
34
34
|
| **MCP Registry** | Live | [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io/?q=io.frihet) |
|
|
35
|
-
| **Glama** |
|
|
36
|
-
| **mcp.so** |
|
|
37
|
-
| **PulseMCP** |
|
|
35
|
+
| **Glama** | Live | [glama.ai/mcp/servers/@Frihet-io/frihet-mcp](https://glama.ai/mcp/servers/@Frihet-io/frihet-mcp) |
|
|
36
|
+
| **mcp.so** | Auto-index (unverified) | [mcp.so](https://mcp.so) — indexes from npm + GitHub |
|
|
37
|
+
| **PulseMCP** | Auto-index (unverified) | [pulsemcp.com](https://pulsemcp.com) — indexes from npm + GitHub |
|
|
38
38
|
| **Cursor Marketplace** | Coming soon | [cursor.com/marketplace](https://cursor.com/marketplace) |
|
|
39
39
|
| **ChatGPT Apps** | Coming soon | [chatgpt.com](https://chatgpt.com) |
|
|
40
40
|
| **Anthropic Claude Directory** | Coming soon | [claude.ai/settings/connectors](https://claude.ai/settings/connectors) |
|
|
41
41
|
|
|
42
|
+
> **Tool count:** npm `latest` (1.13.0) ships all 151 tools, same as the remote endpoint (`mcp.frihet.io`).
|
|
43
|
+
|
|
42
44
|
---
|
|
43
45
|
|
|
44
46
|
## What is this
|
|
@@ -50,9 +52,9 @@ You: "Create an invoice for TechStart SL, 40 hours of consulting at 75 EUR/h
|
|
|
50
52
|
Claude: Done. Invoice INV-2026-089 created. Total: 3,000.00 EUR + 21% IVA = 3,630.00 EUR.
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
151 tools.
|
|
55
|
+
151 tools. 11 resources. 10 prompts. Structured output on every tool. Zero boilerplate.
|
|
54
56
|
|
|
55
|
-
<!-- v1.12.0-beta.1 — D4-B megasprint: HR (9), payroll (2), onboarding (2), permissions (2), period close (3), webhook test (1) = +19 =
|
|
57
|
+
<!-- v1.12.0-beta.1 — D4-B megasprint: HR (9), payroll (2), onboarding (2), permissions (2), period close (3), webhook test (1) = +19 = 151 tools total -->
|
|
56
58
|
|
|
57
59
|
---
|
|
58
60
|
|
|
@@ -547,7 +549,7 @@ All 151 tools return **structured output** via `outputSchema` -- typed JSON, not
|
|
|
547
549
|
|
|
548
550
|
---
|
|
549
551
|
|
|
550
|
-
## Resources (
|
|
552
|
+
## Resources (11)
|
|
551
553
|
|
|
552
554
|
Context the AI can read to make smarter decisions.
|
|
553
555
|
|
|
@@ -560,6 +562,8 @@ Context the AI can read to make smarter decisions.
|
|
|
560
562
|
| Tax Calendar | `frihet://tax/calendar` | Quarterly filing deadlines: Modelo 303, 130, 390, 420, VeriFactu timeline |
|
|
561
563
|
| Expense Categories | `frihet://config/expense-categories` | 8 categories with deductibility rules, IVA treatment, amortization |
|
|
562
564
|
| Invoice Statuses | `frihet://config/invoice-statuses` | Status flow (draft > sent > paid/overdue > cancelled), transition rules, webhook events |
|
|
565
|
+
| Currencies | `frihet://config/currencies` | 40 supported currencies with ISO codes, symbols, decimal places, locale formatting |
|
|
566
|
+
| Countries | `frihet://config/countries` | 61 supported countries with fiscal zones, default tax rates, currencies, invoice prefixes |
|
|
563
567
|
|
|
564
568
|
**Dynamic** (live data from your account):
|
|
565
569
|
|
|
@@ -568,10 +572,11 @@ Context the AI can read to make smarter decisions.
|
|
|
568
572
|
| Business Profile | `frihet://business-profile` | Your business info, plan, defaults, recent activity, top clients |
|
|
569
573
|
| Monthly Snapshot | `frihet://monthly-snapshot` | Current month P&L, revenue, expenses, tax liability |
|
|
570
574
|
| Overdue Invoices | `frihet://overdue-invoices` | All invoices past due date (up to 100) |
|
|
575
|
+
| Plan Limits | `frihet://status/plan-limits` | Live plan tier, usage counters, invoices/month, API rate limits |
|
|
571
576
|
|
|
572
577
|
---
|
|
573
578
|
|
|
574
|
-
## Prompts (
|
|
579
|
+
## Prompts (10)
|
|
575
580
|
|
|
576
581
|
Pre-built workflows the AI can execute as guided multi-step operations.
|
|
577
582
|
|
|
@@ -583,6 +588,9 @@ Pre-built workflows the AI can execute as guided multi-step operations.
|
|
|
583
588
|
| `overdue-followup` | Find overdue invoices, draft follow-up messages, suggest payment reminders | -- |
|
|
584
589
|
| `new-client-invoice` | Create a client + first invoice in one workflow with tax rate lookup | `clientName`, `country?` |
|
|
585
590
|
| `expense-report` | Generate expense report grouped by category with deductible totals | `month?` (YYYY-MM) |
|
|
591
|
+
| `year-end-close` | Full annual closing: quarterly review, pending invoices, uncategorized expenses, year-end checklist | `year` (YYYY) |
|
|
592
|
+
| `cash-flow-forecast` | Project cash flow for coming months: recurring income, expenses, overdue receivables, tax deadlines | `months?` (default: 3) |
|
|
593
|
+
| `invoice-aging-review` | AR aging analysis: group unpaid invoices by bucket (0-30/31-60/61-90/90+ days), top debtors, collection actions | -- |
|
|
586
594
|
| `expense-batch` | Process expenses in bulk: categorize, apply tax rates, flag missing receipts | `fiscalZone?` |
|
|
587
595
|
|
|
588
596
|
---
|
|
@@ -621,6 +629,44 @@ Two transports:
|
|
|
621
629
|
|----------|----------|---------|
|
|
622
630
|
| `FRIHET_API_KEY` | Yes (stdio) | -- |
|
|
623
631
|
| `FRIHET_API_URL` | No | `https://api.frihet.io/v1` |
|
|
632
|
+
| `FRIHET_TOOL_MODE` | No | `full` |
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## Tool exposure: depth served on demand
|
|
637
|
+
|
|
638
|
+
Frihet's differentiator is **depth** — full ES/EU fiscal coverage plus native compliance (VeriFactu, TicketBAI, Facturae/FACe/KSeF), banking, CRM, HR/payroll, stay/PMS and POS. But a flat list of every tool, loaded into an agent's context up front, is the 2026 context-rot problem: it crowds out the task and degrades tool selection before any work begins.
|
|
639
|
+
|
|
640
|
+
`FRIHET_TOOL_MODE` lets you choose how that depth is exposed.
|
|
641
|
+
|
|
642
|
+
| Mode | Behavior |
|
|
643
|
+
|------|----------|
|
|
644
|
+
| `full` (default) | All tools are exposed with their full descriptions and schemas. **Unchanged from previous releases** — existing setups are unaffected. |
|
|
645
|
+
| `grouped` | **Progressive disclosure.** Each tool's description collapses to a one-line `[group] summary — full schema via describe_tool('name')`, and three lightweight discovery tools are added. The agent loads depth only for the tools it actually needs. |
|
|
646
|
+
|
|
647
|
+
In `grouped` mode the tools are unchanged — same names, same input schemas, same behavior. Only the *up-front context cost* changes. Discovery flows through three meta-tools:
|
|
648
|
+
|
|
649
|
+
- **`list_tool_groups()`** — the domain map (invoicing, expenses, fiscal/compliance, banking, CRM, HR/payroll, stay/PMS, POS, intelligence, products, platform) with a one-line blurb and tool count for each.
|
|
650
|
+
- **`search_tools(query)`** — free-text search across tool name, title, summary and group; returns matching tools with their group, summary, read-only flag and input fields. Optional `group` filter and `limit`.
|
|
651
|
+
- **`describe_tool(name)`** — the full original description and input fields for one tool, on demand, before you call it.
|
|
652
|
+
|
|
653
|
+
```jsonc
|
|
654
|
+
// claude_desktop_config.json — opt in to grouped mode
|
|
655
|
+
{
|
|
656
|
+
"mcpServers": {
|
|
657
|
+
"frihet": {
|
|
658
|
+
"command": "npx",
|
|
659
|
+
"args": ["@frihet/mcp-server"],
|
|
660
|
+
"env": {
|
|
661
|
+
"FRIHET_API_KEY": "fri_...",
|
|
662
|
+
"FRIHET_TOOL_MODE": "grouped"
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
> This is an opt-in exposure layer only — it never changes a tool's logic, name or behavior, and `full` mode is byte-identical to before. The same interceptor pattern powers the OpenAI-safe profile (`FRIHET_OPENAI_MODE`).
|
|
624
670
|
|
|
625
671
|
---
|
|
626
672
|
|
|
@@ -722,7 +768,7 @@ npm run build # must pass before submitting
|
|
|
722
768
|
|
|
723
769
|
| Package | What it is |
|
|
724
770
|
|---------|-----------|
|
|
725
|
-
| [`@frihet/mcp-server`](https://www.npmjs.com/package/@frihet/mcp-server) | This MCP server (151 tools,
|
|
771
|
+
| [`@frihet/mcp-server`](https://www.npmjs.com/package/@frihet/mcp-server) | This MCP server (151 tools, 11 resources, 10 prompts) |
|
|
726
772
|
| [`@frihet/sdk`](https://github.com/Frihet-io/frihet-sdk) | TypeScript SDK (`frihet.invoices.create()`) |
|
|
727
773
|
| [`frihet`](https://www.npmjs.com/package/frihet) | CLI (`frihet invoices list --status overdue`) |
|
|
728
774
|
| [`n8n-nodes-frihet`](https://www.npmjs.com/package/n8n-nodes-frihet) | n8n community node for workflow automation |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the OpenAI-safe MCP profile.
|
|
3
|
+
*
|
|
4
|
+
* The public ChatGPT app intentionally exposes a narrower tool surface than
|
|
5
|
+
* the full MCP server. This prevents regulated or sensitive workflows added
|
|
6
|
+
* to the general MCP server from becoming part of the OpenAI submission by
|
|
7
|
+
* accident.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=openai-profile.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-profile.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/openai-profile.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the OpenAI-safe MCP profile.
|
|
3
|
+
*
|
|
4
|
+
* The public ChatGPT app intentionally exposes a narrower tool surface than
|
|
5
|
+
* the full MCP server. This prevents regulated or sensitive workflows added
|
|
6
|
+
* to the general MCP server from becoming part of the OpenAI submission by
|
|
7
|
+
* accident.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, test } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { applyOpenAIProfile } from "../openai-profile.js";
|
|
12
|
+
import { registerAllTools } from "../tools/register-all.js";
|
|
13
|
+
import { registerAllPrompts } from "../prompts/register-all.js";
|
|
14
|
+
class StubMcpServer {
|
|
15
|
+
tools = new Map();
|
|
16
|
+
prompts = [];
|
|
17
|
+
resources = [];
|
|
18
|
+
registerTool(name, config, handler) {
|
|
19
|
+
this.tools.set(name, { name, config, handler });
|
|
20
|
+
}
|
|
21
|
+
registerPrompt(name) {
|
|
22
|
+
this.prompts.push(name);
|
|
23
|
+
}
|
|
24
|
+
registerResource(name) {
|
|
25
|
+
this.resources.push(name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function makeClient() {
|
|
29
|
+
return new Proxy({}, {
|
|
30
|
+
get: (_target, prop) => async (input) => {
|
|
31
|
+
if (prop === "createClient") {
|
|
32
|
+
return {
|
|
33
|
+
id: "cli_openai",
|
|
34
|
+
name: "OpenAI Test Corp",
|
|
35
|
+
email: "test@example.com",
|
|
36
|
+
taxId: "B12345678",
|
|
37
|
+
secret: "should-not-leak",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
data: [],
|
|
42
|
+
total: 0,
|
|
43
|
+
limit: 10,
|
|
44
|
+
offset: 0,
|
|
45
|
+
input,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function makeOpenAIServer() {
|
|
51
|
+
const server = new StubMcpServer();
|
|
52
|
+
applyOpenAIProfile(server);
|
|
53
|
+
registerAllTools(server, makeClient());
|
|
54
|
+
registerAllPrompts(server);
|
|
55
|
+
return server;
|
|
56
|
+
}
|
|
57
|
+
describe("OpenAI profile", () => {
|
|
58
|
+
test("exposes exactly the reviewed 53-tool surface", () => {
|
|
59
|
+
const server = makeOpenAIServer();
|
|
60
|
+
assert.equal(server.tools.size, 53);
|
|
61
|
+
assert.equal(server.prompts.length, 0);
|
|
62
|
+
for (const hiddenTool of [
|
|
63
|
+
"get_quarterly_taxes",
|
|
64
|
+
"get_invoice_einvoice",
|
|
65
|
+
"send_einvoice",
|
|
66
|
+
"validate_einvoice_xml",
|
|
67
|
+
"frihet_tax_id_vies_lookup",
|
|
68
|
+
"create_reservation",
|
|
69
|
+
"payroll_export",
|
|
70
|
+
"invite_team_member",
|
|
71
|
+
]) {
|
|
72
|
+
assert.equal(server.tools.has(hiddenTool), false, `${hiddenTool} must not be exposed in OpenAI mode`);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
test("keeps only reviewed open-world tools marked openWorldHint=true", () => {
|
|
76
|
+
const server = makeOpenAIServer();
|
|
77
|
+
const openWorldTools = [...server.tools.values()]
|
|
78
|
+
.filter((tool) => tool.config.annotations?.["openWorldHint"] === true)
|
|
79
|
+
.map((tool) => tool.name)
|
|
80
|
+
.sort();
|
|
81
|
+
assert.deepEqual(openWorldTools, [
|
|
82
|
+
"create_webhook",
|
|
83
|
+
"send_invoice",
|
|
84
|
+
"send_quote",
|
|
85
|
+
"update_webhook",
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
test("removes restricted input fields from OpenAI-visible schemas", () => {
|
|
89
|
+
const server = makeOpenAIServer();
|
|
90
|
+
for (const name of ["create_client", "update_client", "create_vendor", "update_vendor"]) {
|
|
91
|
+
const tool = server.tools.get(name);
|
|
92
|
+
assert.ok(tool, `${name} should be visible`);
|
|
93
|
+
assert.equal("taxId" in (tool.config.inputSchema ?? {}), false);
|
|
94
|
+
}
|
|
95
|
+
for (const name of ["send_invoice", "send_quote"]) {
|
|
96
|
+
const tool = server.tools.get(name);
|
|
97
|
+
assert.ok(tool, `${name} should be visible`);
|
|
98
|
+
assert.equal("to" in (tool.config.inputSchema ?? {}), false);
|
|
99
|
+
}
|
|
100
|
+
for (const name of ["create_webhook", "update_webhook"]) {
|
|
101
|
+
const tool = server.tools.get(name);
|
|
102
|
+
assert.ok(tool, `${name} should be visible`);
|
|
103
|
+
assert.equal("secret" in (tool.config.inputSchema ?? {}), false);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
test("every reviewed tool states an explicit openWorldHint rationale", () => {
|
|
107
|
+
const server = makeOpenAIServer();
|
|
108
|
+
for (const tool of server.tools.values()) {
|
|
109
|
+
// OpenAI review: openWorldHint must be explicit (not null) AND justified per tool.
|
|
110
|
+
assert.equal(typeof tool.config.annotations?.["openWorldHint"], "boolean", `${tool.name} must have an explicit boolean openWorldHint`);
|
|
111
|
+
assert.ok(tool.config.description.includes("openWorldHint"), `${tool.name} description must state an openWorldHint rationale`);
|
|
112
|
+
}
|
|
113
|
+
// Closed-world read tool carries the closed-world rationale.
|
|
114
|
+
assert.match(server.tools.get("list_invoices").config.description, /openWorldHint: false/);
|
|
115
|
+
// Open-world tool keeps its bespoke true rationale (not double-appended).
|
|
116
|
+
const sendInvoiceDesc = server.tools.get("send_invoice").config.description;
|
|
117
|
+
assert.match(sendInvoiceDesc, /openWorldHint: true/);
|
|
118
|
+
assert.doesNotMatch(sendInvoiceDesc, /openWorldHint: false/);
|
|
119
|
+
});
|
|
120
|
+
test("redacts restricted output fields from structured content and text", async () => {
|
|
121
|
+
const server = makeOpenAIServer();
|
|
122
|
+
const tool = server.tools.get("create_client");
|
|
123
|
+
assert.ok(tool, "create_client should be visible");
|
|
124
|
+
const result = await tool.handler({ name: "OpenAI Test Corp" });
|
|
125
|
+
const serialized = JSON.stringify(result);
|
|
126
|
+
assert.equal(serialized.includes("taxId"), false);
|
|
127
|
+
assert.equal(serialized.includes("B12345678"), false);
|
|
128
|
+
assert.equal(serialized.includes("secret"), false);
|
|
129
|
+
assert.equal(serialized.includes("should-not-leak"), false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=openai-profile.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-profile.test.js","sourceRoot":"","sources":["../../src/__tests__/openai-profile.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the grouped tool-exposure profile (progressive disclosure).
|
|
3
|
+
*
|
|
4
|
+
* The default ("full") mode must stay BYTE-IDENTICAL to the un-profiled server
|
|
5
|
+
* so existing users are unaffected. The opt-in "grouped" mode collapses the 151
|
|
6
|
+
* full tool descriptions into terse one-liners and adds three discovery
|
|
7
|
+
* meta-tools (list_tool_groups, search_tools, describe_tool) so agents load
|
|
8
|
+
* depth on demand instead of a flat 151-tool wall of context.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=tool-exposure.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-exposure.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-exposure.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the grouped tool-exposure profile (progressive disclosure).
|
|
3
|
+
*
|
|
4
|
+
* The default ("full") mode must stay BYTE-IDENTICAL to the un-profiled server
|
|
5
|
+
* so existing users are unaffected. The opt-in "grouped" mode collapses the 151
|
|
6
|
+
* full tool descriptions into terse one-liners and adds three discovery
|
|
7
|
+
* meta-tools (list_tool_groups, search_tools, describe_tool) so agents load
|
|
8
|
+
* depth on demand instead of a flat 151-tool wall of context.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, test } from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { applyToolExposureProfile, resolveToolMode, groupForTool, GROUPS, FILE_TO_GROUP, GROUPED_META_TOOL_COUNT, } from "../tool-exposure.js";
|
|
16
|
+
import { registerAllTools } from "../tools/register-all.js";
|
|
17
|
+
import { registerAllPrompts } from "../prompts/register-all.js";
|
|
18
|
+
class StubMcpServer {
|
|
19
|
+
tools = new Map();
|
|
20
|
+
prompts = [];
|
|
21
|
+
resources = [];
|
|
22
|
+
registerTool(name, config, handler) {
|
|
23
|
+
this.tools.set(name, { name, config, handler });
|
|
24
|
+
}
|
|
25
|
+
registerPrompt(name) {
|
|
26
|
+
this.prompts.push(name);
|
|
27
|
+
}
|
|
28
|
+
registerResource(name) {
|
|
29
|
+
this.resources.push(name);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function makeClient() {
|
|
33
|
+
return new Proxy({}, {
|
|
34
|
+
get: () => async (input) => ({
|
|
35
|
+
data: [],
|
|
36
|
+
total: 0,
|
|
37
|
+
limit: 10,
|
|
38
|
+
offset: 0,
|
|
39
|
+
input,
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const asMcp = (s) => s;
|
|
44
|
+
/** Build a server with NO profile (current/full behavior). */
|
|
45
|
+
function makeFullServer() {
|
|
46
|
+
const server = new StubMcpServer();
|
|
47
|
+
registerAllTools(asMcp(server), makeClient());
|
|
48
|
+
registerAllPrompts(asMcp(server));
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
/** Build a server with the grouped tool-exposure profile applied. */
|
|
52
|
+
function makeGroupedServer() {
|
|
53
|
+
const server = new StubMcpServer();
|
|
54
|
+
const handle = applyToolExposureProfile(server);
|
|
55
|
+
registerAllTools(asMcp(server), makeClient());
|
|
56
|
+
registerAllPrompts(asMcp(server));
|
|
57
|
+
return { server, handle };
|
|
58
|
+
}
|
|
59
|
+
const META_TOOLS = ["list_tool_groups", "search_tools", "describe_tool"];
|
|
60
|
+
describe("tool-exposure: mode resolution", () => {
|
|
61
|
+
test("default and 'full' resolve to full; only 'grouped' opts in", () => {
|
|
62
|
+
assert.equal(resolveToolMode({}), "full");
|
|
63
|
+
assert.equal(resolveToolMode({ FRIHET_TOOL_MODE: undefined }), "full");
|
|
64
|
+
assert.equal(resolveToolMode({ FRIHET_TOOL_MODE: "full" }), "full");
|
|
65
|
+
assert.equal(resolveToolMode({ FRIHET_TOOL_MODE: "anything-else" }), "full");
|
|
66
|
+
assert.equal(resolveToolMode({ FRIHET_TOOL_MODE: "grouped" }), "grouped");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("tool-exposure: full mode is byte-identical", () => {
|
|
70
|
+
test("registers exactly 151 tools, no meta-tools, descriptions untouched", () => {
|
|
71
|
+
const full = makeFullServer();
|
|
72
|
+
assert.equal(full.tools.size, 151);
|
|
73
|
+
for (const meta of META_TOOLS) {
|
|
74
|
+
assert.equal(full.tools.has(meta), false, `${meta} must NOT exist in full mode`);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
test("grouped mode does not mutate the un-profiled tool descriptions", () => {
|
|
78
|
+
// Capture the full-mode description of a representative tool, then confirm
|
|
79
|
+
// the grouped server's collapse did not leak back into the base registration.
|
|
80
|
+
const full = makeFullServer();
|
|
81
|
+
const fullDesc = full.tools.get("list_invoices").config.description;
|
|
82
|
+
// Full description is the rich, multi-sentence original (not a collapsed line).
|
|
83
|
+
assert.ok(fullDesc.length > 117, "full description should be the rich original");
|
|
84
|
+
assert.equal(fullDesc.includes("describe_tool"), false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("tool-exposure: grouped mode", () => {
|
|
88
|
+
test("registers 151 tools + 3 meta-tools and a complete catalog", () => {
|
|
89
|
+
const { server, handle } = makeGroupedServer();
|
|
90
|
+
assert.equal(server.tools.size, 151 + GROUPED_META_TOOL_COUNT);
|
|
91
|
+
assert.equal(GROUPED_META_TOOL_COUNT, 3);
|
|
92
|
+
for (const meta of META_TOOLS) {
|
|
93
|
+
assert.equal(server.tools.has(meta), true, `${meta} must exist in grouped mode`);
|
|
94
|
+
}
|
|
95
|
+
// Catalog holds every real tool (meta-tools excluded).
|
|
96
|
+
assert.equal(handle.catalog.size, 151);
|
|
97
|
+
for (const meta of META_TOOLS) {
|
|
98
|
+
assert.equal(handle.catalog.has(meta), false);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
test("collapses each real tool's description to a terse pointer line", () => {
|
|
102
|
+
const { server } = makeGroupedServer();
|
|
103
|
+
const li = server.tools.get("list_invoices");
|
|
104
|
+
assert.match(li.config.description, /^\[invoicing\] /);
|
|
105
|
+
assert.match(li.config.description, /describe_tool\('list_invoices'\)/);
|
|
106
|
+
// Terse: collapsed lines are far shorter than the rich originals.
|
|
107
|
+
assert.ok(li.config.description.length < 200);
|
|
108
|
+
// Every collapsed description names its group and the describe_tool pointer.
|
|
109
|
+
for (const [name, tool] of server.tools) {
|
|
110
|
+
if (META_TOOLS.includes(name))
|
|
111
|
+
continue;
|
|
112
|
+
assert.match(tool.config.description, /^\[[a-z]+\] /, `${name} description must start with [group]`);
|
|
113
|
+
assert.ok(tool.config.description.includes(`describe_tool('${name}')`), `${name} description must point to describe_tool`);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
test("does NOT change tool names, annotations, or input schemas", () => {
|
|
117
|
+
const full = makeFullServer();
|
|
118
|
+
const { server: grouped } = makeGroupedServer();
|
|
119
|
+
// Same set of real tool names (grouped adds only the 3 meta-tools).
|
|
120
|
+
const realGrouped = [...grouped.tools.keys()].filter((n) => !META_TOOLS.includes(n));
|
|
121
|
+
assert.deepEqual([...full.tools.keys()].sort(), realGrouped.sort());
|
|
122
|
+
// Annotations + input schema identity preserved for a mutating tool.
|
|
123
|
+
const ci = "create_invoice";
|
|
124
|
+
assert.deepEqual(grouped.tools.get(ci).config.annotations, full.tools.get(ci).config.annotations);
|
|
125
|
+
assert.deepEqual(Object.keys(grouped.tools.get(ci).config.inputSchema ?? {}), Object.keys(full.tools.get(ci).config.inputSchema ?? {}));
|
|
126
|
+
});
|
|
127
|
+
test("tool logic is unchanged — collapsed tool still invokes its handler", async () => {
|
|
128
|
+
const { server } = makeGroupedServer();
|
|
129
|
+
const result = await server.tools.get("list_invoices").handler({});
|
|
130
|
+
assert.ok(Array.isArray(result.content));
|
|
131
|
+
// The real handler ran (returns content), proving behavior is untouched.
|
|
132
|
+
assert.ok(result.content.length >= 1);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("tool-exposure: group taxonomy", () => {
|
|
136
|
+
test("groupForTool reproduces the source-file grouping for all 151 tools", () => {
|
|
137
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
138
|
+
const toolsDir = join(here, "..", "..", "src", "tools");
|
|
139
|
+
let checked = 0;
|
|
140
|
+
const mismatches = [];
|
|
141
|
+
for (const f of readdirSync(toolsDir)) {
|
|
142
|
+
if (!f.endsWith(".ts"))
|
|
143
|
+
continue;
|
|
144
|
+
const base = f.replace(/\.ts$/, "");
|
|
145
|
+
if (base === "register-all" || base === "shared")
|
|
146
|
+
continue;
|
|
147
|
+
const fileGroup = FILE_TO_GROUP[base];
|
|
148
|
+
assert.ok(fileGroup, `source file ${base}.ts must be mapped in FILE_TO_GROUP`);
|
|
149
|
+
const txt = readFileSync(join(toolsDir, f), "utf8");
|
|
150
|
+
for (const m of txt.matchAll(/registerTool\(\s*"([a-z_0-9]+)"/g)) {
|
|
151
|
+
const name = m[1];
|
|
152
|
+
checked += 1;
|
|
153
|
+
const ng = groupForTool(name);
|
|
154
|
+
if (ng !== fileGroup)
|
|
155
|
+
mismatches.push(`${name}: name=${ng} file=${fileGroup}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
assert.equal(checked, 151, "should have scanned all 151 registration sites");
|
|
159
|
+
assert.deepEqual(mismatches, [], "groupForTool must match the source-file group");
|
|
160
|
+
});
|
|
161
|
+
test("every group used by a tool has metadata", () => {
|
|
162
|
+
const { handle } = makeGroupedServer();
|
|
163
|
+
for (const group of handle.groups.keys()) {
|
|
164
|
+
assert.ok(GROUPS[group], `group ${group} must have metadata`);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
test("group ids are stable and cover the brief's 9 domains", () => {
|
|
168
|
+
for (const id of [
|
|
169
|
+
"invoicing",
|
|
170
|
+
"expenses",
|
|
171
|
+
"fiscal",
|
|
172
|
+
"banking",
|
|
173
|
+
"crm",
|
|
174
|
+
"hr",
|
|
175
|
+
"stay",
|
|
176
|
+
"pos",
|
|
177
|
+
"intelligence",
|
|
178
|
+
]) {
|
|
179
|
+
assert.ok(GROUPS[id], `${id} must be a defined group`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe("tool-exposure: meta-tools", () => {
|
|
184
|
+
test("list_tool_groups returns non-empty groups with counts summing to 151", async () => {
|
|
185
|
+
const { server } = makeGroupedServer();
|
|
186
|
+
const res = await server.tools.get("list_tool_groups").handler({});
|
|
187
|
+
const payload = JSON.parse(res.content[0].text);
|
|
188
|
+
assert.equal(payload.totalTools, 151);
|
|
189
|
+
const sum = payload.groups.reduce((acc, g) => acc + g.toolCount, 0);
|
|
190
|
+
assert.equal(sum, 151);
|
|
191
|
+
// No empty groups are listed.
|
|
192
|
+
assert.ok(payload.groups.every((g) => g.toolCount > 0));
|
|
193
|
+
// Fiscal is a headline group (compliance depth).
|
|
194
|
+
assert.ok(payload.groups.some((g) => g.group === "fiscal" && g.toolCount > 0));
|
|
195
|
+
});
|
|
196
|
+
test("search_tools finds fiscal tools by free-text and ranks the exact name top", async () => {
|
|
197
|
+
const { server } = makeGroupedServer();
|
|
198
|
+
const res = await server.tools.get("search_tools").handler({
|
|
199
|
+
query: "modelo 303",
|
|
200
|
+
});
|
|
201
|
+
const payload = JSON.parse(res.content[0].text);
|
|
202
|
+
assert.ok(payload.count > 0);
|
|
203
|
+
assert.equal(payload.tools[0].name, "get_modelo_303_summary");
|
|
204
|
+
assert.equal(payload.tools[0].group, "fiscal");
|
|
205
|
+
});
|
|
206
|
+
test("search_tools honors the group filter", async () => {
|
|
207
|
+
const { server } = makeGroupedServer();
|
|
208
|
+
const res = await server.tools.get("search_tools").handler({
|
|
209
|
+
query: "",
|
|
210
|
+
group: "banking",
|
|
211
|
+
limit: 50,
|
|
212
|
+
});
|
|
213
|
+
const payload = JSON.parse(res.content[0].text);
|
|
214
|
+
assert.ok(payload.tools.length > 0);
|
|
215
|
+
assert.ok(payload.tools.every((t) => t.group === "banking"));
|
|
216
|
+
});
|
|
217
|
+
test("describe_tool returns the full original description on demand", async () => {
|
|
218
|
+
const full = makeFullServer();
|
|
219
|
+
const fullDesc = full.tools.get("get_modelo_303_summary").config.description;
|
|
220
|
+
const { server } = makeGroupedServer();
|
|
221
|
+
const res = await server.tools.get("describe_tool").handler({
|
|
222
|
+
name: "get_modelo_303_summary",
|
|
223
|
+
});
|
|
224
|
+
const payload = JSON.parse(res.content[0].text);
|
|
225
|
+
assert.equal(payload.name, "get_modelo_303_summary");
|
|
226
|
+
assert.equal(payload.group, "fiscal");
|
|
227
|
+
// describe_tool serves the FULL original description (depth on demand).
|
|
228
|
+
assert.equal(payload.description, fullDesc);
|
|
229
|
+
});
|
|
230
|
+
test("describe_tool errors with suggestions for an unknown name", async () => {
|
|
231
|
+
const { server } = makeGroupedServer();
|
|
232
|
+
const res = await server.tools.get("describe_tool").handler({ name: "modelo" });
|
|
233
|
+
assert.equal(res.isError, true);
|
|
234
|
+
const payload = JSON.parse(res.content[0].text);
|
|
235
|
+
assert.ok(payload.error.length > 0);
|
|
236
|
+
// 'modelo' is a substring of several real tool names → suggestions offered.
|
|
237
|
+
assert.ok(payload.suggestions.length > 0);
|
|
238
|
+
assert.ok(payload.suggestions.every((s) => s.includes("modelo")));
|
|
239
|
+
});
|
|
240
|
+
test("meta-tools are read-only and closed-world", () => {
|
|
241
|
+
const { server } = makeGroupedServer();
|
|
242
|
+
for (const meta of META_TOOLS) {
|
|
243
|
+
const ann = server.tools.get(meta).config.annotations;
|
|
244
|
+
assert.equal(ann?.readOnlyHint, true, `${meta} must be read-only`);
|
|
245
|
+
assert.equal(ann?.openWorldHint, false, `${meta} must be closed-world`);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
//# sourceMappingURL=tool-exposure.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-exposure.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-exposure.test.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -9,10 +9,18 @@ export declare class FrihetApiError extends Error {
|
|
|
9
9
|
readonly errorCode: string;
|
|
10
10
|
constructor(statusCode: number, errorCode: string, message?: string);
|
|
11
11
|
}
|
|
12
|
+
export interface FrihetClientOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Per-request timeout in milliseconds. Defaults to 30000.
|
|
15
|
+
* Cloudflare Workers should pass ≤25000 to leave margin under the ~30s limit.
|
|
16
|
+
*/
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
}
|
|
12
19
|
export declare class FrihetClient {
|
|
13
20
|
private readonly apiKey;
|
|
14
21
|
private readonly baseUrl;
|
|
15
|
-
|
|
22
|
+
private readonly timeoutMs;
|
|
23
|
+
constructor(apiKey: string, baseUrl?: string, options?: FrihetClientOptions);
|
|
16
24
|
private request;
|
|
17
25
|
private sleep;
|
|
18
26
|
/** Wrapper for paginated endpoints — validates response shape has `data` array. */
|