@frihet/mcp-server 1.16.3 → 1.16.4

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.
Files changed (203) hide show
  1. package/README.md +1 -1
  2. package/dist/openai-profile.js +1 -1
  3. package/package.json +7 -4
  4. package/scripts/postinstall.js +30 -8
  5. package/dist/__tests__/audit-server-version.test.d.ts +0 -13
  6. package/dist/__tests__/audit-server-version.test.d.ts.map +0 -1
  7. package/dist/__tests__/audit-server-version.test.js +0 -96
  8. package/dist/__tests__/audit-server-version.test.js.map +0 -1
  9. package/dist/__tests__/banking-client-contract.test.d.ts +0 -20
  10. package/dist/__tests__/banking-client-contract.test.d.ts.map +0 -1
  11. package/dist/__tests__/banking-client-contract.test.js +0 -133
  12. package/dist/__tests__/banking-client-contract.test.js.map +0 -1
  13. package/dist/__tests__/banking-tools.test.d.ts +0 -18
  14. package/dist/__tests__/banking-tools.test.d.ts.map +0 -1
  15. package/dist/__tests__/banking-tools.test.js +0 -252
  16. package/dist/__tests__/banking-tools.test.js.map +0 -1
  17. package/dist/__tests__/contract.test.d.ts +0 -33
  18. package/dist/__tests__/contract.test.d.ts.map +0 -1
  19. package/dist/__tests__/contract.test.js +0 -208
  20. package/dist/__tests__/contract.test.js.map +0 -1
  21. package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.d.ts +0 -13
  22. package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.d.ts.map +0 -1
  23. package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.js +0 -420
  24. package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.js.map +0 -1
  25. package/dist/__tests__/demo-mode.test.d.ts +0 -11
  26. package/dist/__tests__/demo-mode.test.d.ts.map +0 -1
  27. package/dist/__tests__/demo-mode.test.js +0 -119
  28. package/dist/__tests__/demo-mode.test.js.map +0 -1
  29. package/dist/__tests__/einvoice-day4-tools.test.d.ts +0 -16
  30. package/dist/__tests__/einvoice-day4-tools.test.d.ts.map +0 -1
  31. package/dist/__tests__/einvoice-day4-tools.test.js +0 -421
  32. package/dist/__tests__/einvoice-day4-tools.test.js.map +0 -1
  33. package/dist/__tests__/einvoice-integration.test.d.ts +0 -24
  34. package/dist/__tests__/einvoice-integration.test.d.ts.map +0 -1
  35. package/dist/__tests__/einvoice-integration.test.js +0 -142
  36. package/dist/__tests__/einvoice-integration.test.js.map +0 -1
  37. package/dist/__tests__/einvoice-tools.test.d.ts +0 -16
  38. package/dist/__tests__/einvoice-tools.test.d.ts.map +0 -1
  39. package/dist/__tests__/einvoice-tools.test.js +0 -411
  40. package/dist/__tests__/einvoice-tools.test.js.map +0 -1
  41. package/dist/__tests__/fiscal-tools.test.d.ts +0 -21
  42. package/dist/__tests__/fiscal-tools.test.d.ts.map +0 -1
  43. package/dist/__tests__/fiscal-tools.test.js +0 -271
  44. package/dist/__tests__/fiscal-tools.test.js.map +0 -1
  45. package/dist/__tests__/get-envelope-unwrap-regression.test.d.ts +0 -27
  46. package/dist/__tests__/get-envelope-unwrap-regression.test.d.ts.map +0 -1
  47. package/dist/__tests__/get-envelope-unwrap-regression.test.js +0 -223
  48. package/dist/__tests__/get-envelope-unwrap-regression.test.js.map +0 -1
  49. package/dist/__tests__/intelligence-duplicate-invoice.test.d.ts +0 -14
  50. package/dist/__tests__/intelligence-duplicate-invoice.test.d.ts.map +0 -1
  51. package/dist/__tests__/intelligence-duplicate-invoice.test.js +0 -108
  52. package/dist/__tests__/intelligence-duplicate-invoice.test.js.map +0 -1
  53. package/dist/__tests__/kitchen-tools.test.d.ts +0 -18
  54. package/dist/__tests__/kitchen-tools.test.d.ts.map +0 -1
  55. package/dist/__tests__/kitchen-tools.test.js +0 -399
  56. package/dist/__tests__/kitchen-tools.test.js.map +0 -1
  57. package/dist/__tests__/mutation-unwrap-and-schema-regression.test.d.ts +0 -30
  58. package/dist/__tests__/mutation-unwrap-and-schema-regression.test.d.ts.map +0 -1
  59. package/dist/__tests__/mutation-unwrap-and-schema-regression.test.js +0 -164
  60. package/dist/__tests__/mutation-unwrap-and-schema-regression.test.js.map +0 -1
  61. package/dist/__tests__/observability-redaction.test.d.ts +0 -13
  62. package/dist/__tests__/observability-redaction.test.d.ts.map +0 -1
  63. package/dist/__tests__/observability-redaction.test.js +0 -94
  64. package/dist/__tests__/observability-redaction.test.js.map +0 -1
  65. package/dist/__tests__/openai-grouped-compose.test.d.ts +0 -26
  66. package/dist/__tests__/openai-grouped-compose.test.d.ts.map +0 -1
  67. package/dist/__tests__/openai-grouped-compose.test.js +0 -245
  68. package/dist/__tests__/openai-grouped-compose.test.js.map +0 -1
  69. package/dist/__tests__/openai-profile.test.d.ts +0 -10
  70. package/dist/__tests__/openai-profile.test.d.ts.map +0 -1
  71. package/dist/__tests__/openai-profile.test.js +0 -168
  72. package/dist/__tests__/openai-profile.test.js.map +0 -1
  73. package/dist/__tests__/pagination-cursor-param.test.d.ts +0 -27
  74. package/dist/__tests__/pagination-cursor-param.test.d.ts.map +0 -1
  75. package/dist/__tests__/pagination-cursor-param.test.js +0 -96
  76. package/dist/__tests__/pagination-cursor-param.test.js.map +0 -1
  77. package/dist/__tests__/pos-tools.test.d.ts +0 -16
  78. package/dist/__tests__/pos-tools.test.d.ts.map +0 -1
  79. package/dist/__tests__/pos-tools.test.js +0 -244
  80. package/dist/__tests__/pos-tools.test.js.map +0 -1
  81. package/dist/__tests__/recurring-tools.test.d.ts +0 -23
  82. package/dist/__tests__/recurring-tools.test.d.ts.map +0 -1
  83. package/dist/__tests__/recurring-tools.test.js +0 -352
  84. package/dist/__tests__/recurring-tools.test.js.map +0 -1
  85. package/dist/__tests__/schema-envelope-guard.test.d.ts +0 -18
  86. package/dist/__tests__/schema-envelope-guard.test.d.ts.map +0 -1
  87. package/dist/__tests__/schema-envelope-guard.test.js +0 -56
  88. package/dist/__tests__/schema-envelope-guard.test.js.map +0 -1
  89. package/dist/__tests__/stay-tools.test.d.ts +0 -17
  90. package/dist/__tests__/stay-tools.test.d.ts.map +0 -1
  91. package/dist/__tests__/stay-tools.test.js +0 -259
  92. package/dist/__tests__/stay-tools.test.js.map +0 -1
  93. package/dist/__tests__/team-tools.test.d.ts +0 -18
  94. package/dist/__tests__/team-tools.test.d.ts.map +0 -1
  95. package/dist/__tests__/team-tools.test.js +0 -228
  96. package/dist/__tests__/team-tools.test.js.map +0 -1
  97. package/dist/__tests__/time-tools.test.d.ts +0 -19
  98. package/dist/__tests__/time-tools.test.d.ts.map +0 -1
  99. package/dist/__tests__/time-tools.test.js +0 -286
  100. package/dist/__tests__/time-tools.test.js.map +0 -1
  101. package/dist/__tests__/tool-exposure.test.d.ts +0 -11
  102. package/dist/__tests__/tool-exposure.test.d.ts.map +0 -1
  103. package/dist/__tests__/tool-exposure.test.js +0 -264
  104. package/dist/__tests__/tool-exposure.test.js.map +0 -1
  105. package/dist/client-interface.d.ts.map +0 -1
  106. package/dist/client-interface.js.map +0 -1
  107. package/dist/client.d.ts.map +0 -1
  108. package/dist/client.js.map +0 -1
  109. package/dist/demo-client.d.ts.map +0 -1
  110. package/dist/demo-client.js.map +0 -1
  111. package/dist/demo-fixtures.d.ts.map +0 -1
  112. package/dist/demo-fixtures.js.map +0 -1
  113. package/dist/index.d.ts.map +0 -1
  114. package/dist/index.js.map +0 -1
  115. package/dist/logger.d.ts.map +0 -1
  116. package/dist/logger.js.map +0 -1
  117. package/dist/metrics.d.ts.map +0 -1
  118. package/dist/metrics.js.map +0 -1
  119. package/dist/observability.d.ts.map +0 -1
  120. package/dist/observability.js.map +0 -1
  121. package/dist/openai-profile.d.ts.map +0 -1
  122. package/dist/openai-profile.js.map +0 -1
  123. package/dist/prompts/register-all.d.ts.map +0 -1
  124. package/dist/prompts/register-all.js.map +0 -1
  125. package/dist/redaction.d.ts.map +0 -1
  126. package/dist/redaction.js.map +0 -1
  127. package/dist/resources/register-all.d.ts.map +0 -1
  128. package/dist/resources/register-all.js.map +0 -1
  129. package/dist/tool-exposure.d.ts.map +0 -1
  130. package/dist/tool-exposure.js.map +0 -1
  131. package/dist/tools/accountingClose.d.ts.map +0 -1
  132. package/dist/tools/accountingClose.js.map +0 -1
  133. package/dist/tools/audit_gl.d.ts.map +0 -1
  134. package/dist/tools/audit_gl.js.map +0 -1
  135. package/dist/tools/backend-availability.d.ts.map +0 -1
  136. package/dist/tools/backend-availability.js.map +0 -1
  137. package/dist/tools/bank_rules.d.ts.map +0 -1
  138. package/dist/tools/bank_rules.js.map +0 -1
  139. package/dist/tools/banking.d.ts.map +0 -1
  140. package/dist/tools/banking.js.map +0 -1
  141. package/dist/tools/clients.d.ts.map +0 -1
  142. package/dist/tools/clients.js.map +0 -1
  143. package/dist/tools/crm.d.ts.map +0 -1
  144. package/dist/tools/crm.js.map +0 -1
  145. package/dist/tools/deposits.d.ts.map +0 -1
  146. package/dist/tools/deposits.js.map +0 -1
  147. package/dist/tools/einvoice.d.ts.map +0 -1
  148. package/dist/tools/einvoice.js.map +0 -1
  149. package/dist/tools/expenses.d.ts.map +0 -1
  150. package/dist/tools/expenses.js.map +0 -1
  151. package/dist/tools/fiscal.d.ts.map +0 -1
  152. package/dist/tools/fiscal.js.map +0 -1
  153. package/dist/tools/gestoria.d.ts.map +0 -1
  154. package/dist/tools/gestoria.js.map +0 -1
  155. package/dist/tools/hr.d.ts.map +0 -1
  156. package/dist/tools/hr.js.map +0 -1
  157. package/dist/tools/igic.d.ts.map +0 -1
  158. package/dist/tools/igic.js.map +0 -1
  159. package/dist/tools/impuesto_sociedades.d.ts.map +0 -1
  160. package/dist/tools/impuesto_sociedades.js.map +0 -1
  161. package/dist/tools/intelligence.d.ts.map +0 -1
  162. package/dist/tools/intelligence.js.map +0 -1
  163. package/dist/tools/invoices.d.ts.map +0 -1
  164. package/dist/tools/invoices.js.map +0 -1
  165. package/dist/tools/kitchen.d.ts.map +0 -1
  166. package/dist/tools/kitchen.js.map +0 -1
  167. package/dist/tools/onboard_vies.d.ts.map +0 -1
  168. package/dist/tools/onboard_vies.js.map +0 -1
  169. package/dist/tools/onboarding.d.ts.map +0 -1
  170. package/dist/tools/onboarding.js.map +0 -1
  171. package/dist/tools/payroll.d.ts.map +0 -1
  172. package/dist/tools/payroll.js.map +0 -1
  173. package/dist/tools/permissions.d.ts.map +0 -1
  174. package/dist/tools/permissions.js.map +0 -1
  175. package/dist/tools/portal_domain.d.ts.map +0 -1
  176. package/dist/tools/portal_domain.js.map +0 -1
  177. package/dist/tools/pos.d.ts.map +0 -1
  178. package/dist/tools/pos.js.map +0 -1
  179. package/dist/tools/products.d.ts.map +0 -1
  180. package/dist/tools/products.js.map +0 -1
  181. package/dist/tools/quotes.d.ts.map +0 -1
  182. package/dist/tools/quotes.js.map +0 -1
  183. package/dist/tools/recurring.d.ts.map +0 -1
  184. package/dist/tools/recurring.js.map +0 -1
  185. package/dist/tools/register-all.d.ts.map +0 -1
  186. package/dist/tools/register-all.js.map +0 -1
  187. package/dist/tools/shared.d.ts.map +0 -1
  188. package/dist/tools/shared.js.map +0 -1
  189. package/dist/tools/stay.d.ts.map +0 -1
  190. package/dist/tools/stay.js.map +0 -1
  191. package/dist/tools/team.d.ts.map +0 -1
  192. package/dist/tools/team.js.map +0 -1
  193. package/dist/tools/time.d.ts.map +0 -1
  194. package/dist/tools/time.js.map +0 -1
  195. package/dist/tools/vendors.d.ts.map +0 -1
  196. package/dist/tools/vendors.js.map +0 -1
  197. package/dist/tools/webhooks.d.ts.map +0 -1
  198. package/dist/tools/webhooks.js.map +0 -1
  199. package/dist/types.d.ts.map +0 -1
  200. package/dist/types.js.map +0 -1
  201. package/scripts/audit-mcp-refs.mjs +0 -402
  202. package/scripts/no-public-leak.sh +0 -60
  203. package/scripts/test-openai-grouped-compose.mjs +0 -173
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env bash
2
- # =============================================================================
3
- # no-public-leak.sh — prevent competitor-comparison + business-secret leaks on
4
- # the PUBLIC frihet-mcp surface (repo is public + npm + mcp.frihet.io Worker).
5
- #
6
- # WHY: the June-2026 Holded cease-&-desist remediation scrubbed the website +
7
- # docs but MISSED this public MCP repo — a "When to recommend Frihet" worker
8
- # block listed "Alternatives to Holded, QuickBooks, ..." (comparison + named a
9
- # C&D claimant) and DISTRIBUTION-ROADMAP.md exposed competitive strategy.
10
- # This gate makes that class of leak fail CI instead of shipping silently.
11
- #
12
- # Scope: marketing/strategy PROSE surfaces (markdown + Worker descriptions),
13
- # NOT functional interop code. The payroll export format value "holded" (an
14
- # enum alongside a3/contasol/sage/siltra in src/) is lawful referential/interop
15
- # use and is intentionally NOT scanned here.
16
- #
17
- # Exit 0 = clean. Exit 1 = leak found.
18
- # =============================================================================
19
- set -uo pipefail
20
- cd "$(git rev-parse --show-toplevel)"
21
-
22
- fail=0
23
- note() { echo " ✗ $1"; fail=1; }
24
-
25
- # 1. Worker descriptions must NEVER name a competitor (served live on mcp.frihet.io).
26
- if grep -rinE "holded" workers/ 2>/dev/null; then
27
- note "Competitor 'Holded' found in workers/ (public Worker description) — remove."
28
- fi
29
-
30
- # 2. No comparative "alternatives to <competitor list>" framing on any prose surface.
31
- if grep -rinE "alternativ(e|a)s? to (holded|quickbooks|anfix|contasimple|quipu|odoo|billin|sage|factorial|a3erp|declarando|txerpa|xero|zoho)" \
32
- --include="*.md" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | grep -v "/dist/"; then
33
- note "Comparative 'alternatives to <competitor>' framing found — comparisons are de-prioritized/legal-gated."
34
- fi
35
-
36
- # 3. No business-secret / strategy artifacts on the public surface.
37
- if grep -rinE "distribution-roadmap|first-mover advantage|cease.?(and|&).?desist|requerimiento" \
38
- --include="*.md" --include="*.ts" --include="*.js" . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "scripts/no-public-leak.sh"; then
39
- note "Business-secret / legal-strategy marker found on public surface — move to a private location."
40
- fi
41
-
42
- # 4. No internal doctrine / internal-tooling markers on prose surfaces (July-2026
43
- # leak class: CLAUDE.md carried the "north star" roadmap + moat doctrine, and
44
- # AGENTS.md carried internal multi-agent dispatch + LLM-router cost rules).
45
- # Public-repo CLAUDE.md/AGENTS.md are docs for EXTERNAL contributors, never
46
- # internal operating docs.
47
- if grep -rinE "north.?star|moat|SOUL\.md|~/\.claude/bin|litellm|sonnet worker|multi-agent dispatch|doctrina|doctrine" \
48
- --include="*.md" --include="*.ts" --include="*.js" --include="*.toml" . 2>/dev/null | grep -v node_modules | grep -v "/dist/" | grep -v "scripts/no-public-leak.sh"; then
49
- note "Internal doctrine / internal-tooling marker found — public repo docs are for external contributors only."
50
- fi
51
-
52
- # 5. Strategy/secret-named files must never be tracked (recurrence guard).
53
- if git ls-files | grep -inE "strategy|roadmap|secrets?\.md$|decision_spec" ; then
54
- note "Strategy/secrets-named file tracked in public repo — keep these in a private repo."
55
- fi
56
-
57
- if [ "$fail" -eq 0 ]; then
58
- echo "✓ no-public-leak: clean (no competitor comparison, strategy secret, or internal doctrine on public surface)"
59
- fi
60
- exit $fail
@@ -1,173 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * LIVE smoke for the OpenAI × grouped COMPOSITION on openai-mcp.frihet.io.
4
- *
5
- * ⚠️ DO NOT RUN until the openai-mcp Worker has been deployed with
6
- * FRIHET_TOOL_MODE=grouped (env.openai). The composition is gated behind
7
- * a production flip + an OpenAI app re-review.
8
- * Running it before deploy asserts against the OLD ("full") surface and will
9
- * fail on the meta-tool checks — that failure is expected pre-deploy.
10
- *
11
- * What it asserts against the LIVE MCP endpoint (after a deploy):
12
- * (1) tools/list returns 56 tools: the 53 reviewed business tools + the 3
13
- * discovery meta-tools (search_tools, describe_tool, list_tool_groups).
14
- * (2) Every reviewed business tool has a collapsed description that still
15
- * carries an openWorldHint rationale marker.
16
- * (3) search_tools (browse-all) and describe_tool only ever surface tools that
17
- * are in tools/list — i.e. the catalog never leaks a non-reviewed tool.
18
- *
19
- * Usage (AFTER deploy only):
20
- * FRIHET_API_KEY=fri_xxx node scripts/test-openai-grouped-compose.mjs
21
- * node scripts/test-openai-grouped-compose.mjs --endpoint https://openai-mcp.frihet.io/mcp --key fri_xxx
22
- *
23
- * Exit 0 = all invariants hold. Exit 1 = a violation. Exit 2 = setup/transport error.
24
- */
25
-
26
- const ARGS = process.argv.slice(2);
27
- function arg(flag) {
28
- const i = ARGS.indexOf(flag);
29
- return i >= 0 ? ARGS[i + 1] : undefined;
30
- }
31
-
32
- const ENDPOINT = arg("--endpoint") || "https://openai-mcp.frihet.io/mcp";
33
- const API_KEY = arg("--key") || process.env.FRIHET_API_KEY;
34
-
35
- // The 3 grouped discovery meta-tools (must be PRESENT in the composed surface).
36
- const META_TOOLS = ["list_tool_groups", "search_tools", "describe_tool"];
37
- // A handful of tools that exist on the FULL server but must NEVER surface here.
38
- const MUST_NOT_LEAK = [
39
- "get_quarterly_taxes",
40
- "get_invoice_einvoice",
41
- "send_einvoice",
42
- "get_modelo_303_summary",
43
- "create_reservation",
44
- "payroll_export",
45
- ];
46
- const EXPECTED_BUSINESS = 53;
47
- const EXPECTED_TOTAL = EXPECTED_BUSINESS + META_TOOLS.length; // 56
48
-
49
- if (!API_KEY || !API_KEY.startsWith("fri_")) {
50
- console.error("✗ Missing/invalid API key. Pass --key fri_* or set FRIHET_API_KEY (fri_*).");
51
- process.exit(2);
52
- }
53
-
54
- let nextId = 1;
55
- async function rpc(method, params) {
56
- const res = await fetch(ENDPOINT, {
57
- method: "POST",
58
- headers: {
59
- "Content-Type": "application/json",
60
- Accept: "application/json, text/event-stream",
61
- Authorization: `Bearer ${API_KEY}`,
62
- },
63
- body: JSON.stringify({ jsonrpc: "2.0", id: nextId++, method, params }),
64
- });
65
- if (!res.ok) throw new Error(`${method} → HTTP ${res.status} ${res.statusText}`);
66
- const ct = res.headers.get("content-type") || "";
67
- let payload;
68
- if (ct.includes("text/event-stream")) {
69
- // Parse the last data: line of an SSE response.
70
- const text = await res.text();
71
- const dataLines = text
72
- .split("\n")
73
- .filter((l) => l.startsWith("data:"))
74
- .map((l) => l.slice(5).trim())
75
- .filter(Boolean);
76
- if (!dataLines.length) throw new Error(`${method} → empty SSE body`);
77
- payload = JSON.parse(dataLines[dataLines.length - 1]);
78
- } else {
79
- payload = await res.json();
80
- }
81
- if (payload.error) throw new Error(`${method} → JSON-RPC error: ${JSON.stringify(payload.error)}`);
82
- return payload.result;
83
- }
84
-
85
- function parseToolText(callResult) {
86
- const block = (callResult?.content || []).find((c) => c.type === "text");
87
- return block ? JSON.parse(block.text) : null;
88
- }
89
-
90
- async function main() {
91
- const failures = [];
92
- const note = (ok, label) => {
93
- console.log(`${ok ? "✓" : "✗"} ${label}`);
94
- if (!ok) failures.push(label);
95
- };
96
-
97
- // Handshake.
98
- await rpc("initialize", {
99
- protocolVersion: "2025-06-18",
100
- capabilities: {},
101
- clientInfo: { name: "openai-grouped-compose-smoke", version: "1.0.0" },
102
- });
103
-
104
- // ---- tools/list ----------------------------------------------------------
105
- const list = await rpc("tools/list", {});
106
- const tools = list.tools || [];
107
- const names = new Set(tools.map((t) => t.name));
108
-
109
- // Invariant (1): 56 tools, meta-tools present.
110
- note(tools.length === EXPECTED_TOTAL, `tools/list returns ${EXPECTED_TOTAL} tools (got ${tools.length})`);
111
- for (const m of META_TOOLS) note(names.has(m), `meta-tool present: ${m}`);
112
- const businessCount = tools.filter((t) => !META_TOOLS.includes(t.name)).length;
113
- note(businessCount === EXPECTED_BUSINESS, `exactly ${EXPECTED_BUSINESS} reviewed business tools (got ${businessCount})`);
114
- for (const leak of MUST_NOT_LEAK) note(!names.has(leak), `non-reviewed tool absent: ${leak}`);
115
-
116
- // Meta-tools are read-only + closed-world.
117
- for (const m of META_TOOLS) {
118
- const t = tools.find((x) => x.name === m);
119
- const ann = t?.annotations || {};
120
- note(ann.readOnlyHint === true && ann.openWorldHint === false, `${m} is read-only + closed-world`);
121
- }
122
-
123
- // Invariant (2): every business tool collapsed + carries openWorldHint rationale.
124
- let collapsedOk = true;
125
- let owOk = true;
126
- for (const t of tools) {
127
- if (META_TOOLS.includes(t.name)) continue;
128
- const d = t.description || "";
129
- if (!/^\[[a-z]+\] /.test(d) || !d.includes(`describe_tool('${t.name}')`)) collapsedOk = false;
130
- if (!d.includes("openWorldHint")) owOk = false;
131
- }
132
- note(collapsedOk, "every reviewed tool has a collapsed [group] … describe_tool() description");
133
- note(owOk, "every reviewed tool's collapsed description carries an openWorldHint rationale");
134
-
135
- // Invariant (3): catalog only ever surfaces tools that are in tools/list.
136
- const search = await rpc("tools/call", { name: "search_tools", arguments: { query: "", limit: 500 } });
137
- const searchPayload = parseToolText(search);
138
- const searchNames = (searchPayload?.tools || []).map((x) => x.name);
139
- const searchLeaks = searchNames.filter((n) => !names.has(n));
140
- note(searchLeaks.length === 0, `search_tools (browse-all) leaks nothing (leaks: ${searchLeaks.join(", ") || "none"})`);
141
- note(
142
- searchNames.length === EXPECTED_BUSINESS,
143
- `search_tools browse-all returns the ${EXPECTED_BUSINESS} reviewed tools (got ${searchNames.length})`,
144
- );
145
-
146
- // A fiscal query must surface no non-reviewed tool.
147
- const fiscal = await rpc("tools/call", { name: "search_tools", arguments: { query: "modelo 303 verifactu" } });
148
- const fiscalNames = (parseToolText(fiscal)?.tools || []).map((x) => x.name);
149
- note(fiscalNames.every((n) => names.has(n)), "search_tools('modelo 303') surfaces no non-reviewed tool");
150
-
151
- // describe_tool rejects a non-reviewed tool.
152
- const desc = await rpc("tools/call", { name: "describe_tool", arguments: { name: "get_quarterly_taxes" } });
153
- note(desc?.isError === true, "describe_tool('get_quarterly_taxes') is rejected (not in reviewed catalog)");
154
-
155
- // list_tool_groups totals 53.
156
- const groups = await rpc("tools/call", { name: "list_tool_groups", arguments: {} });
157
- const gPayload = parseToolText(groups);
158
- note(gPayload?.totalTools === EXPECTED_BUSINESS, `list_tool_groups totalTools === ${EXPECTED_BUSINESS} (got ${gPayload?.totalTools})`);
159
-
160
- console.log("");
161
- if (failures.length) {
162
- console.error(`FAIL — ${failures.length} invariant violation(s):`);
163
- for (const f of failures) console.error(` - ${f}`);
164
- process.exit(1);
165
- }
166
- console.log(`PASS — all ${EXPECTED_TOTAL}-tool composition invariants hold on ${ENDPOINT}`);
167
- process.exit(0);
168
- }
169
-
170
- main().catch((err) => {
171
- console.error(`✗ transport/setup error: ${err.message}`);
172
- process.exit(2);
173
- });