@frihet/mcp-server 1.16.3 → 1.16.5
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 +1 -1
- package/dist/client-interface.d.ts +1 -1
- package/dist/client.d.ts +13 -1
- package/dist/client.js +70 -6
- package/dist/demo-client.d.ts +1 -1
- package/dist/demo-client.js +23 -3
- package/dist/openai-profile.js +1 -1
- package/dist/tools/invoices.js +24 -11
- package/package.json +11 -5
- package/scripts/postinstall.js +30 -8
- package/dist/__tests__/audit-server-version.test.d.ts +0 -13
- package/dist/__tests__/audit-server-version.test.d.ts.map +0 -1
- package/dist/__tests__/audit-server-version.test.js +0 -96
- package/dist/__tests__/audit-server-version.test.js.map +0 -1
- package/dist/__tests__/banking-client-contract.test.d.ts +0 -20
- package/dist/__tests__/banking-client-contract.test.d.ts.map +0 -1
- package/dist/__tests__/banking-client-contract.test.js +0 -133
- package/dist/__tests__/banking-client-contract.test.js.map +0 -1
- package/dist/__tests__/banking-tools.test.d.ts +0 -18
- package/dist/__tests__/banking-tools.test.d.ts.map +0 -1
- package/dist/__tests__/banking-tools.test.js +0 -252
- package/dist/__tests__/banking-tools.test.js.map +0 -1
- package/dist/__tests__/contract.test.d.ts +0 -33
- package/dist/__tests__/contract.test.d.ts.map +0 -1
- package/dist/__tests__/contract.test.js +0 -208
- package/dist/__tests__/contract.test.js.map +0 -1
- package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.d.ts +0 -13
- package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.d.ts.map +0 -1
- package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.js +0 -420
- package/dist/__tests__/d4b-hr-payroll-onboarding-tools.test.js.map +0 -1
- package/dist/__tests__/demo-mode.test.d.ts +0 -11
- package/dist/__tests__/demo-mode.test.d.ts.map +0 -1
- package/dist/__tests__/demo-mode.test.js +0 -119
- package/dist/__tests__/demo-mode.test.js.map +0 -1
- package/dist/__tests__/einvoice-day4-tools.test.d.ts +0 -16
- package/dist/__tests__/einvoice-day4-tools.test.d.ts.map +0 -1
- package/dist/__tests__/einvoice-day4-tools.test.js +0 -421
- package/dist/__tests__/einvoice-day4-tools.test.js.map +0 -1
- package/dist/__tests__/einvoice-integration.test.d.ts +0 -24
- package/dist/__tests__/einvoice-integration.test.d.ts.map +0 -1
- package/dist/__tests__/einvoice-integration.test.js +0 -142
- package/dist/__tests__/einvoice-integration.test.js.map +0 -1
- package/dist/__tests__/einvoice-tools.test.d.ts +0 -16
- package/dist/__tests__/einvoice-tools.test.d.ts.map +0 -1
- package/dist/__tests__/einvoice-tools.test.js +0 -411
- package/dist/__tests__/einvoice-tools.test.js.map +0 -1
- package/dist/__tests__/fiscal-tools.test.d.ts +0 -21
- package/dist/__tests__/fiscal-tools.test.d.ts.map +0 -1
- package/dist/__tests__/fiscal-tools.test.js +0 -271
- package/dist/__tests__/fiscal-tools.test.js.map +0 -1
- package/dist/__tests__/get-envelope-unwrap-regression.test.d.ts +0 -27
- package/dist/__tests__/get-envelope-unwrap-regression.test.d.ts.map +0 -1
- package/dist/__tests__/get-envelope-unwrap-regression.test.js +0 -223
- package/dist/__tests__/get-envelope-unwrap-regression.test.js.map +0 -1
- package/dist/__tests__/intelligence-duplicate-invoice.test.d.ts +0 -14
- package/dist/__tests__/intelligence-duplicate-invoice.test.d.ts.map +0 -1
- package/dist/__tests__/intelligence-duplicate-invoice.test.js +0 -108
- package/dist/__tests__/intelligence-duplicate-invoice.test.js.map +0 -1
- package/dist/__tests__/kitchen-tools.test.d.ts +0 -18
- package/dist/__tests__/kitchen-tools.test.d.ts.map +0 -1
- package/dist/__tests__/kitchen-tools.test.js +0 -399
- package/dist/__tests__/kitchen-tools.test.js.map +0 -1
- package/dist/__tests__/mutation-unwrap-and-schema-regression.test.d.ts +0 -30
- package/dist/__tests__/mutation-unwrap-and-schema-regression.test.d.ts.map +0 -1
- package/dist/__tests__/mutation-unwrap-and-schema-regression.test.js +0 -164
- package/dist/__tests__/mutation-unwrap-and-schema-regression.test.js.map +0 -1
- package/dist/__tests__/observability-redaction.test.d.ts +0 -13
- package/dist/__tests__/observability-redaction.test.d.ts.map +0 -1
- package/dist/__tests__/observability-redaction.test.js +0 -94
- package/dist/__tests__/observability-redaction.test.js.map +0 -1
- package/dist/__tests__/openai-grouped-compose.test.d.ts +0 -26
- package/dist/__tests__/openai-grouped-compose.test.d.ts.map +0 -1
- package/dist/__tests__/openai-grouped-compose.test.js +0 -245
- package/dist/__tests__/openai-grouped-compose.test.js.map +0 -1
- package/dist/__tests__/openai-profile.test.d.ts +0 -10
- package/dist/__tests__/openai-profile.test.d.ts.map +0 -1
- package/dist/__tests__/openai-profile.test.js +0 -168
- package/dist/__tests__/openai-profile.test.js.map +0 -1
- package/dist/__tests__/pagination-cursor-param.test.d.ts +0 -27
- package/dist/__tests__/pagination-cursor-param.test.d.ts.map +0 -1
- package/dist/__tests__/pagination-cursor-param.test.js +0 -96
- package/dist/__tests__/pagination-cursor-param.test.js.map +0 -1
- package/dist/__tests__/pos-tools.test.d.ts +0 -16
- package/dist/__tests__/pos-tools.test.d.ts.map +0 -1
- package/dist/__tests__/pos-tools.test.js +0 -244
- package/dist/__tests__/pos-tools.test.js.map +0 -1
- package/dist/__tests__/recurring-tools.test.d.ts +0 -23
- package/dist/__tests__/recurring-tools.test.d.ts.map +0 -1
- package/dist/__tests__/recurring-tools.test.js +0 -352
- package/dist/__tests__/recurring-tools.test.js.map +0 -1
- package/dist/__tests__/schema-envelope-guard.test.d.ts +0 -18
- package/dist/__tests__/schema-envelope-guard.test.d.ts.map +0 -1
- package/dist/__tests__/schema-envelope-guard.test.js +0 -56
- package/dist/__tests__/schema-envelope-guard.test.js.map +0 -1
- package/dist/__tests__/stay-tools.test.d.ts +0 -17
- package/dist/__tests__/stay-tools.test.d.ts.map +0 -1
- package/dist/__tests__/stay-tools.test.js +0 -259
- package/dist/__tests__/stay-tools.test.js.map +0 -1
- package/dist/__tests__/team-tools.test.d.ts +0 -18
- package/dist/__tests__/team-tools.test.d.ts.map +0 -1
- package/dist/__tests__/team-tools.test.js +0 -228
- package/dist/__tests__/team-tools.test.js.map +0 -1
- package/dist/__tests__/time-tools.test.d.ts +0 -19
- package/dist/__tests__/time-tools.test.d.ts.map +0 -1
- package/dist/__tests__/time-tools.test.js +0 -286
- package/dist/__tests__/time-tools.test.js.map +0 -1
- package/dist/__tests__/tool-exposure.test.d.ts +0 -11
- package/dist/__tests__/tool-exposure.test.d.ts.map +0 -1
- package/dist/__tests__/tool-exposure.test.js +0 -264
- package/dist/__tests__/tool-exposure.test.js.map +0 -1
- package/dist/client-interface.d.ts.map +0 -1
- package/dist/client-interface.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/demo-client.d.ts.map +0 -1
- package/dist/demo-client.js.map +0 -1
- package/dist/demo-fixtures.d.ts.map +0 -1
- package/dist/demo-fixtures.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js.map +0 -1
- package/dist/observability.d.ts.map +0 -1
- package/dist/observability.js.map +0 -1
- package/dist/openai-profile.d.ts.map +0 -1
- package/dist/openai-profile.js.map +0 -1
- package/dist/prompts/register-all.d.ts.map +0 -1
- package/dist/prompts/register-all.js.map +0 -1
- package/dist/redaction.d.ts.map +0 -1
- package/dist/redaction.js.map +0 -1
- package/dist/resources/register-all.d.ts.map +0 -1
- package/dist/resources/register-all.js.map +0 -1
- package/dist/tool-exposure.d.ts.map +0 -1
- package/dist/tool-exposure.js.map +0 -1
- package/dist/tools/accountingClose.d.ts.map +0 -1
- package/dist/tools/accountingClose.js.map +0 -1
- package/dist/tools/audit_gl.d.ts.map +0 -1
- package/dist/tools/audit_gl.js.map +0 -1
- package/dist/tools/backend-availability.d.ts.map +0 -1
- package/dist/tools/backend-availability.js.map +0 -1
- package/dist/tools/bank_rules.d.ts.map +0 -1
- package/dist/tools/bank_rules.js.map +0 -1
- package/dist/tools/banking.d.ts.map +0 -1
- package/dist/tools/banking.js.map +0 -1
- package/dist/tools/clients.d.ts.map +0 -1
- package/dist/tools/clients.js.map +0 -1
- package/dist/tools/crm.d.ts.map +0 -1
- package/dist/tools/crm.js.map +0 -1
- package/dist/tools/deposits.d.ts.map +0 -1
- package/dist/tools/deposits.js.map +0 -1
- package/dist/tools/einvoice.d.ts.map +0 -1
- package/dist/tools/einvoice.js.map +0 -1
- package/dist/tools/expenses.d.ts.map +0 -1
- package/dist/tools/expenses.js.map +0 -1
- package/dist/tools/fiscal.d.ts.map +0 -1
- package/dist/tools/fiscal.js.map +0 -1
- package/dist/tools/gestoria.d.ts.map +0 -1
- package/dist/tools/gestoria.js.map +0 -1
- package/dist/tools/hr.d.ts.map +0 -1
- package/dist/tools/hr.js.map +0 -1
- package/dist/tools/igic.d.ts.map +0 -1
- package/dist/tools/igic.js.map +0 -1
- package/dist/tools/impuesto_sociedades.d.ts.map +0 -1
- package/dist/tools/impuesto_sociedades.js.map +0 -1
- package/dist/tools/intelligence.d.ts.map +0 -1
- package/dist/tools/intelligence.js.map +0 -1
- package/dist/tools/invoices.d.ts.map +0 -1
- package/dist/tools/invoices.js.map +0 -1
- package/dist/tools/kitchen.d.ts.map +0 -1
- package/dist/tools/kitchen.js.map +0 -1
- package/dist/tools/onboard_vies.d.ts.map +0 -1
- package/dist/tools/onboard_vies.js.map +0 -1
- package/dist/tools/onboarding.d.ts.map +0 -1
- package/dist/tools/onboarding.js.map +0 -1
- package/dist/tools/payroll.d.ts.map +0 -1
- package/dist/tools/payroll.js.map +0 -1
- package/dist/tools/permissions.d.ts.map +0 -1
- package/dist/tools/permissions.js.map +0 -1
- package/dist/tools/portal_domain.d.ts.map +0 -1
- package/dist/tools/portal_domain.js.map +0 -1
- package/dist/tools/pos.d.ts.map +0 -1
- package/dist/tools/pos.js.map +0 -1
- package/dist/tools/products.d.ts.map +0 -1
- package/dist/tools/products.js.map +0 -1
- package/dist/tools/quotes.d.ts.map +0 -1
- package/dist/tools/quotes.js.map +0 -1
- package/dist/tools/recurring.d.ts.map +0 -1
- package/dist/tools/recurring.js.map +0 -1
- package/dist/tools/register-all.d.ts.map +0 -1
- package/dist/tools/register-all.js.map +0 -1
- package/dist/tools/shared.d.ts.map +0 -1
- package/dist/tools/shared.js.map +0 -1
- package/dist/tools/stay.d.ts.map +0 -1
- package/dist/tools/stay.js.map +0 -1
- package/dist/tools/team.d.ts.map +0 -1
- package/dist/tools/team.js.map +0 -1
- package/dist/tools/time.d.ts.map +0 -1
- package/dist/tools/time.js.map +0 -1
- package/dist/tools/vendors.d.ts.map +0 -1
- package/dist/tools/vendors.js.map +0 -1
- package/dist/tools/webhooks.d.ts.map +0 -1
- package/dist/tools/webhooks.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/scripts/audit-mcp-refs.mjs +0 -402
- package/scripts/no-public-leak.sh +0 -60
- package/scripts/test-openai-grouped-compose.mjs +0 -173
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Time Tracking MCP tools — Wave Mature 3 (6 tools).
|
|
3
|
-
*
|
|
4
|
-
* Uses Node.js built-in test runner (node:test + node:assert).
|
|
5
|
-
* Run: npm test (after build)
|
|
6
|
-
*
|
|
7
|
-
* Coverage:
|
|
8
|
-
* 1. Tool registration — all 6 time tools registered
|
|
9
|
-
* 2. list_time_entries — success path + structuredContent shape
|
|
10
|
-
* 3. get_time_entry — success path
|
|
11
|
-
* 4. create_time_entry — success path
|
|
12
|
-
* 5. update_time_entry — success path + partial update
|
|
13
|
-
* 6. delete_time_entry — confirm=false gate
|
|
14
|
-
* 7. delete_time_entry — confirm=true success path
|
|
15
|
-
* 8. get_time_summary — success path + aggregation fields
|
|
16
|
-
* 9. API error — 404 propagated as isError=true
|
|
17
|
-
*/
|
|
18
|
-
import { test, describe, beforeEach } from "node:test";
|
|
19
|
-
import assert from "node:assert/strict";
|
|
20
|
-
class StubMcpServer {
|
|
21
|
-
tools = new Map();
|
|
22
|
-
registerTool(name, config, handler) {
|
|
23
|
-
this.tools.set(name, { name, config, handler });
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
// ── Mock data ────────────────────────────────────────────────────────────────
|
|
27
|
-
const MOCK_ENTRY = {
|
|
28
|
-
id: "te_abc123",
|
|
29
|
-
userId: "usr_viktor",
|
|
30
|
-
projectId: "proj_xyz",
|
|
31
|
-
hours: 2.5,
|
|
32
|
-
description: "Frontend code review",
|
|
33
|
-
billable: true,
|
|
34
|
-
date: "2026-05-10",
|
|
35
|
-
status: "logged",
|
|
36
|
-
createdAt: "2026-05-10T09:00:00Z",
|
|
37
|
-
};
|
|
38
|
-
const MOCK_ENTRIES_LIST = {
|
|
39
|
-
data: [MOCK_ENTRY],
|
|
40
|
-
total: 1,
|
|
41
|
-
limit: 20,
|
|
42
|
-
offset: 0,
|
|
43
|
-
};
|
|
44
|
-
const MOCK_TIME_SUMMARY = {
|
|
45
|
-
from: "2026-05-01",
|
|
46
|
-
to: "2026-05-31",
|
|
47
|
-
totalHours: 42.5,
|
|
48
|
-
billableHours: 38.0,
|
|
49
|
-
nonBillableHours: 4.5,
|
|
50
|
-
estimatedCostEur: 6375.0,
|
|
51
|
-
groups: [
|
|
52
|
-
{ key: "proj_xyz", label: "Project Alpha", totalHours: 42.5, billableHours: 38.0, nonBillableHours: 4.5 },
|
|
53
|
-
],
|
|
54
|
-
};
|
|
55
|
-
// ── Client stubs ─────────────────────────────────────────────────────────────
|
|
56
|
-
function makeSuccessClient() {
|
|
57
|
-
return {
|
|
58
|
-
listTimeEntries: async () => MOCK_ENTRIES_LIST,
|
|
59
|
-
getTimeEntry: async (_id) => MOCK_ENTRY,
|
|
60
|
-
createTimeEntry: async (_data) => MOCK_ENTRY,
|
|
61
|
-
updateTimeEntry: async (_id, data) => ({ ...MOCK_ENTRY, ...data }),
|
|
62
|
-
deleteTimeEntry: async (_id) => undefined,
|
|
63
|
-
getTimeSummary: async () => MOCK_TIME_SUMMARY,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
function make404Client() {
|
|
67
|
-
const notFound = () => {
|
|
68
|
-
const err = Object.assign(new Error("Not Found"), { statusCode: 404, errorCode: "not_found" });
|
|
69
|
-
return Promise.reject(err);
|
|
70
|
-
};
|
|
71
|
-
return {
|
|
72
|
-
listTimeEntries: notFound,
|
|
73
|
-
getTimeEntry: notFound,
|
|
74
|
-
createTimeEntry: notFound,
|
|
75
|
-
updateTimeEntry: notFound,
|
|
76
|
-
deleteTimeEntry: notFound,
|
|
77
|
-
getTimeSummary: notFound,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// ── Helper ───────────────────────────────────────────────────────────────────
|
|
81
|
-
async function makeServer(clientFn) {
|
|
82
|
-
const server = new StubMcpServer();
|
|
83
|
-
const { registerTimeTools } = await import("../tools/time.js");
|
|
84
|
-
registerTimeTools(server, clientFn());
|
|
85
|
-
return server;
|
|
86
|
-
}
|
|
87
|
-
// ── Registration tests ───────────────────────────────────────────────────────
|
|
88
|
-
describe("Time Tools — Registration", () => {
|
|
89
|
-
let server;
|
|
90
|
-
beforeEach(async () => {
|
|
91
|
-
server = await makeServer(makeSuccessClient);
|
|
92
|
-
});
|
|
93
|
-
test("registers exactly 6 time tools", () => {
|
|
94
|
-
assert.equal(server.tools.size, 6);
|
|
95
|
-
});
|
|
96
|
-
test("registers list_time_entries", () => {
|
|
97
|
-
assert.ok(server.tools.has("list_time_entries"));
|
|
98
|
-
});
|
|
99
|
-
test("registers create_time_entry", () => {
|
|
100
|
-
assert.ok(server.tools.has("create_time_entry"));
|
|
101
|
-
});
|
|
102
|
-
test("registers update_time_entry", () => {
|
|
103
|
-
assert.ok(server.tools.has("update_time_entry"));
|
|
104
|
-
});
|
|
105
|
-
test("registers delete_time_entry", () => {
|
|
106
|
-
assert.ok(server.tools.has("delete_time_entry"));
|
|
107
|
-
});
|
|
108
|
-
test("registers get_time_entry", () => {
|
|
109
|
-
assert.ok(server.tools.has("get_time_entry"));
|
|
110
|
-
});
|
|
111
|
-
test("registers get_time_summary", () => {
|
|
112
|
-
assert.ok(server.tools.has("get_time_summary"));
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
// ── get_time_entry ───────────────────────────────────────────────────────────
|
|
116
|
-
describe("get_time_entry — success path", () => {
|
|
117
|
-
test("returns single entry with expected fields", async () => {
|
|
118
|
-
const server = await makeServer(makeSuccessClient);
|
|
119
|
-
const tool = server.tools.get("get_time_entry");
|
|
120
|
-
const result = await tool.handler({ id: "te_abc123" });
|
|
121
|
-
assert.ok(!result.isError);
|
|
122
|
-
const sc = result.structuredContent;
|
|
123
|
-
assert.equal(sc["id"], "te_abc123");
|
|
124
|
-
assert.equal(sc["hours"], 2.5);
|
|
125
|
-
assert.equal(sc["billable"], true);
|
|
126
|
-
});
|
|
127
|
-
test("content block has type text", async () => {
|
|
128
|
-
const server = await makeServer(makeSuccessClient);
|
|
129
|
-
const tool = server.tools.get("get_time_entry");
|
|
130
|
-
const result = await tool.handler({ id: "te_abc123" });
|
|
131
|
-
assert.equal(result.content[0].type, "text");
|
|
132
|
-
});
|
|
133
|
-
test("404 propagates as isError=true", async () => {
|
|
134
|
-
const server = await makeServer(make404Client);
|
|
135
|
-
const tool = server.tools.get("get_time_entry");
|
|
136
|
-
const result = await tool.handler({ id: "te_missing" });
|
|
137
|
-
assert.ok(result.isError);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
// ── list_time_entries ────────────────────────────────────────────────────────
|
|
141
|
-
describe("list_time_entries — success path", () => {
|
|
142
|
-
test("returns structuredContent with data array", async () => {
|
|
143
|
-
const server = await makeServer(makeSuccessClient);
|
|
144
|
-
const tool = server.tools.get("list_time_entries");
|
|
145
|
-
const result = await tool.handler({ projectId: "proj_xyz", from: "2026-05-01", to: "2026-05-31" });
|
|
146
|
-
assert.ok(!result.isError);
|
|
147
|
-
const sc = result.structuredContent;
|
|
148
|
-
assert.ok(Array.isArray(sc["data"]));
|
|
149
|
-
assert.equal(sc["total"], 1);
|
|
150
|
-
});
|
|
151
|
-
test("first entry has expected fields", async () => {
|
|
152
|
-
const server = await makeServer(makeSuccessClient);
|
|
153
|
-
const tool = server.tools.get("list_time_entries");
|
|
154
|
-
const result = await tool.handler({});
|
|
155
|
-
const first = result.structuredContent["data"][0];
|
|
156
|
-
assert.equal(first["id"], "te_abc123");
|
|
157
|
-
assert.equal(first["hours"], 2.5);
|
|
158
|
-
assert.equal(first["billable"], true);
|
|
159
|
-
assert.equal(first["date"], "2026-05-10");
|
|
160
|
-
});
|
|
161
|
-
test("content block has type text and mentions time_entries", async () => {
|
|
162
|
-
const server = await makeServer(makeSuccessClient);
|
|
163
|
-
const tool = server.tools.get("list_time_entries");
|
|
164
|
-
const result = await tool.handler({});
|
|
165
|
-
assert.equal(result.content[0].type, "text");
|
|
166
|
-
assert.ok(result.content[0].text.includes("time_entries"));
|
|
167
|
-
});
|
|
168
|
-
test("billable filter accepted without error", async () => {
|
|
169
|
-
const server = await makeServer(makeSuccessClient);
|
|
170
|
-
const tool = server.tools.get("list_time_entries");
|
|
171
|
-
const result = await tool.handler({ billable: true });
|
|
172
|
-
assert.ok(!result.isError);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
// ── create_time_entry ────────────────────────────────────────────────────────
|
|
176
|
-
describe("create_time_entry — success path", () => {
|
|
177
|
-
test("returns created entry with expected fields", async () => {
|
|
178
|
-
const server = await makeServer(makeSuccessClient);
|
|
179
|
-
const tool = server.tools.get("create_time_entry");
|
|
180
|
-
const result = await tool.handler({
|
|
181
|
-
projectId: "proj_xyz",
|
|
182
|
-
hours: 2.5,
|
|
183
|
-
date: "2026-05-10",
|
|
184
|
-
description: "Frontend code review",
|
|
185
|
-
billable: true,
|
|
186
|
-
});
|
|
187
|
-
assert.ok(!result.isError);
|
|
188
|
-
const sc = result.structuredContent;
|
|
189
|
-
assert.equal(sc["id"], "te_abc123");
|
|
190
|
-
assert.equal(sc["hours"], 2.5);
|
|
191
|
-
assert.equal(sc["billable"], true);
|
|
192
|
-
});
|
|
193
|
-
test("content block mentions time entry created", async () => {
|
|
194
|
-
const server = await makeServer(makeSuccessClient);
|
|
195
|
-
const tool = server.tools.get("create_time_entry");
|
|
196
|
-
const result = await tool.handler({ projectId: "proj_xyz", hours: 1.0, date: "2026-05-10" });
|
|
197
|
-
assert.ok(result.content[0].text.includes("created"));
|
|
198
|
-
});
|
|
199
|
-
test("404 propagates as isError=true", async () => {
|
|
200
|
-
const server = await makeServer(make404Client);
|
|
201
|
-
const tool = server.tools.get("create_time_entry");
|
|
202
|
-
const result = await tool.handler({ projectId: "proj_xyz", hours: 1.0, date: "2026-05-10" });
|
|
203
|
-
assert.ok(result.isError);
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
// ── update_time_entry ────────────────────────────────────────────────────────
|
|
207
|
-
describe("update_time_entry — success path", () => {
|
|
208
|
-
test("returns updated entry with new hours", async () => {
|
|
209
|
-
const server = await makeServer(makeSuccessClient);
|
|
210
|
-
const tool = server.tools.get("update_time_entry");
|
|
211
|
-
const result = await tool.handler({ id: "te_abc123", hours: 3.0 });
|
|
212
|
-
assert.ok(!result.isError);
|
|
213
|
-
const sc = result.structuredContent;
|
|
214
|
-
assert.equal(sc["hours"], 3.0);
|
|
215
|
-
});
|
|
216
|
-
test("content block mentions updated", async () => {
|
|
217
|
-
const server = await makeServer(makeSuccessClient);
|
|
218
|
-
const tool = server.tools.get("update_time_entry");
|
|
219
|
-
const result = await tool.handler({ id: "te_abc123", description: "Updated description" });
|
|
220
|
-
assert.ok(result.content[0].text.includes("updated"));
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
// ── delete_time_entry ────────────────────────────────────────────────────────
|
|
224
|
-
describe("delete_time_entry — trust area gate", () => {
|
|
225
|
-
test("confirm=false returns isError=true without calling API", async () => {
|
|
226
|
-
const server = await makeServer(makeSuccessClient);
|
|
227
|
-
const tool = server.tools.get("delete_time_entry");
|
|
228
|
-
const result = await tool.handler({ id: "te_abc123", confirm: false });
|
|
229
|
-
assert.ok(result.isError);
|
|
230
|
-
assert.ok(result.content[0].text.includes("confirm=true"));
|
|
231
|
-
});
|
|
232
|
-
test("confirm=true succeeds and returns success=true", async () => {
|
|
233
|
-
const server = await makeServer(makeSuccessClient);
|
|
234
|
-
const tool = server.tools.get("delete_time_entry");
|
|
235
|
-
const result = await tool.handler({ id: "te_abc123", confirm: true });
|
|
236
|
-
assert.ok(!result.isError);
|
|
237
|
-
assert.equal(result.structuredContent["success"], true);
|
|
238
|
-
assert.equal(result.structuredContent["id"], "te_abc123");
|
|
239
|
-
});
|
|
240
|
-
test("confirm=true with 404 propagates isError=true", async () => {
|
|
241
|
-
const server = await makeServer(make404Client);
|
|
242
|
-
const tool = server.tools.get("delete_time_entry");
|
|
243
|
-
const result = await tool.handler({ id: "te_missing", confirm: true });
|
|
244
|
-
assert.ok(result.isError);
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
// ── get_time_summary ─────────────────────────────────────────────────────────
|
|
248
|
-
describe("get_time_summary — success path", () => {
|
|
249
|
-
test("returns summary with aggregation fields", async () => {
|
|
250
|
-
const server = await makeServer(makeSuccessClient);
|
|
251
|
-
const tool = server.tools.get("get_time_summary");
|
|
252
|
-
const result = await tool.handler({ from: "2026-05-01", to: "2026-05-31" });
|
|
253
|
-
assert.ok(!result.isError);
|
|
254
|
-
const sc = result.structuredContent;
|
|
255
|
-
assert.equal(sc["totalHours"], 42.5);
|
|
256
|
-
assert.equal(sc["billableHours"], 38.0);
|
|
257
|
-
assert.equal(sc["nonBillableHours"], 4.5);
|
|
258
|
-
});
|
|
259
|
-
test("content block has type text", async () => {
|
|
260
|
-
const server = await makeServer(makeSuccessClient);
|
|
261
|
-
const tool = server.tools.get("get_time_summary");
|
|
262
|
-
const result = await tool.handler({ from: "2026-05-01", to: "2026-05-31" });
|
|
263
|
-
assert.equal(result.content[0].type, "text");
|
|
264
|
-
});
|
|
265
|
-
test("groups array present when returned", async () => {
|
|
266
|
-
const server = await makeServer(makeSuccessClient);
|
|
267
|
-
const tool = server.tools.get("get_time_summary");
|
|
268
|
-
const result = await tool.handler({ from: "2026-05-01", to: "2026-05-31", groupBy: "project" });
|
|
269
|
-
const sc = result.structuredContent;
|
|
270
|
-
assert.ok(Array.isArray(sc["groups"]));
|
|
271
|
-
assert.equal(sc["groups"].length, 1);
|
|
272
|
-
});
|
|
273
|
-
test("userId filter accepted without error", async () => {
|
|
274
|
-
const server = await makeServer(makeSuccessClient);
|
|
275
|
-
const tool = server.tools.get("get_time_summary");
|
|
276
|
-
const result = await tool.handler({ from: "2026-05-01", to: "2026-05-31", userId: "usr_viktor" });
|
|
277
|
-
assert.ok(!result.isError);
|
|
278
|
-
});
|
|
279
|
-
test("404 propagates as isError=true", async () => {
|
|
280
|
-
const server = await makeServer(make404Client);
|
|
281
|
-
const tool = server.tools.get("get_time_summary");
|
|
282
|
-
const result = await tool.handler({ from: "2026-05-01", to: "2026-05-31" });
|
|
283
|
-
assert.ok(result.isError);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
//# sourceMappingURL=time-tools.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"time-tools.test.js","sourceRoot":"","sources":["../../src/__tests__/time-tools.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-exposure.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool-exposure.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -1,264 +0,0 @@
|
|
|
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 157 tools, no meta-tools, descriptions untouched", () => {
|
|
71
|
-
const full = makeFullServer();
|
|
72
|
-
assert.equal(full.tools.size, 157);
|
|
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 157 tools + 3 meta-tools and a complete catalog", () => {
|
|
89
|
-
const { server, handle } = makeGroupedServer();
|
|
90
|
-
assert.equal(server.tools.size, 157 + 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, 157);
|
|
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 157 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
|
-
// Skip helper modules that register ZERO tools (not tool-group files):
|
|
146
|
-
// register-all = registration entrypoint, shared = cross-tool helpers,
|
|
147
|
-
// backend-availability = the 404→structured-error guard helper.
|
|
148
|
-
if (base === "register-all" || base === "shared" || base === "backend-availability")
|
|
149
|
-
continue;
|
|
150
|
-
const fileGroup = FILE_TO_GROUP[base];
|
|
151
|
-
assert.ok(fileGroup, `source file ${base}.ts must be mapped in FILE_TO_GROUP`);
|
|
152
|
-
const txt = readFileSync(join(toolsDir, f), "utf8");
|
|
153
|
-
for (const m of txt.matchAll(/registerTool\(\s*"([a-z_0-9]+)"/g)) {
|
|
154
|
-
const name = m[1];
|
|
155
|
-
checked += 1;
|
|
156
|
-
const ng = groupForTool(name);
|
|
157
|
-
if (ng !== fileGroup)
|
|
158
|
-
mismatches.push(`${name}: name=${ng} file=${fileGroup}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
assert.equal(checked, 157, "should have scanned all 157 registration sites");
|
|
162
|
-
assert.deepEqual(mismatches, [], "groupForTool must match the source-file group");
|
|
163
|
-
});
|
|
164
|
-
test("every group used by a tool has metadata", () => {
|
|
165
|
-
const { handle } = makeGroupedServer();
|
|
166
|
-
for (const group of handle.groups.keys()) {
|
|
167
|
-
assert.ok(GROUPS[group], `group ${group} must have metadata`);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
test("group ids are stable and cover the brief's 9 domains", () => {
|
|
171
|
-
for (const id of [
|
|
172
|
-
"invoicing",
|
|
173
|
-
"expenses",
|
|
174
|
-
"fiscal",
|
|
175
|
-
"banking",
|
|
176
|
-
"crm",
|
|
177
|
-
"hr",
|
|
178
|
-
"stay",
|
|
179
|
-
"pos",
|
|
180
|
-
"intelligence",
|
|
181
|
-
]) {
|
|
182
|
-
assert.ok(GROUPS[id], `${id} must be a defined group`);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
describe("tool-exposure: meta-tools", () => {
|
|
187
|
-
test("list_tool_groups returns non-empty groups with counts summing to 157", async () => {
|
|
188
|
-
const { server } = makeGroupedServer();
|
|
189
|
-
const res = await server.tools.get("list_tool_groups").handler({});
|
|
190
|
-
const payload = JSON.parse(res.content[0].text);
|
|
191
|
-
assert.equal(payload.totalTools, 157);
|
|
192
|
-
const sum = payload.groups.reduce((acc, g) => acc + g.toolCount, 0);
|
|
193
|
-
assert.equal(sum, 157);
|
|
194
|
-
// No empty groups are listed.
|
|
195
|
-
assert.ok(payload.groups.every((g) => g.toolCount > 0));
|
|
196
|
-
// Fiscal is a headline group (compliance depth).
|
|
197
|
-
assert.ok(payload.groups.some((g) => g.group === "fiscal" && g.toolCount > 0));
|
|
198
|
-
});
|
|
199
|
-
test("search_tools finds fiscal tools by free-text and ranks the exact name top", async () => {
|
|
200
|
-
const { server } = makeGroupedServer();
|
|
201
|
-
const res = await server.tools.get("search_tools").handler({
|
|
202
|
-
query: "modelo 303",
|
|
203
|
-
});
|
|
204
|
-
const payload = JSON.parse(res.content[0].text);
|
|
205
|
-
assert.ok(payload.count > 0);
|
|
206
|
-
assert.equal(payload.tools[0].name, "get_modelo_303_summary");
|
|
207
|
-
assert.equal(payload.tools[0].group, "fiscal");
|
|
208
|
-
});
|
|
209
|
-
test("search_tools honors the group filter", async () => {
|
|
210
|
-
const { server } = makeGroupedServer();
|
|
211
|
-
const res = await server.tools.get("search_tools").handler({
|
|
212
|
-
query: "",
|
|
213
|
-
group: "banking",
|
|
214
|
-
limit: 50,
|
|
215
|
-
});
|
|
216
|
-
const payload = JSON.parse(res.content[0].text);
|
|
217
|
-
assert.ok(payload.tools.length > 0);
|
|
218
|
-
assert.ok(payload.tools.every((t) => t.group === "banking"));
|
|
219
|
-
});
|
|
220
|
-
test("describe_tool returns the full original description on demand", async () => {
|
|
221
|
-
const full = makeFullServer();
|
|
222
|
-
const fullDesc = full.tools.get("get_modelo_303_summary").config.description;
|
|
223
|
-
const { server } = makeGroupedServer();
|
|
224
|
-
const res = await server.tools.get("describe_tool").handler({
|
|
225
|
-
name: "get_modelo_303_summary",
|
|
226
|
-
});
|
|
227
|
-
const payload = JSON.parse(res.content[0].text);
|
|
228
|
-
assert.equal(payload.name, "get_modelo_303_summary");
|
|
229
|
-
assert.equal(payload.group, "fiscal");
|
|
230
|
-
// describe_tool serves the FULL original description (depth on demand).
|
|
231
|
-
assert.equal(payload.description, fullDesc);
|
|
232
|
-
});
|
|
233
|
-
test("describe_tool errors with suggestions for an unknown name", async () => {
|
|
234
|
-
const { server } = makeGroupedServer();
|
|
235
|
-
const res = await server.tools.get("describe_tool").handler({ name: "modelo" });
|
|
236
|
-
assert.equal(res.isError, true);
|
|
237
|
-
const payload = JSON.parse(res.content[0].text);
|
|
238
|
-
assert.ok(payload.error.length > 0);
|
|
239
|
-
// 'modelo' is a substring of several real tool names → suggestions offered.
|
|
240
|
-
assert.ok(payload.suggestions.length > 0);
|
|
241
|
-
assert.ok(payload.suggestions.every((s) => s.includes("modelo")));
|
|
242
|
-
});
|
|
243
|
-
test("meta-tools are read-only and closed-world", () => {
|
|
244
|
-
const { server } = makeGroupedServer();
|
|
245
|
-
for (const meta of META_TOOLS) {
|
|
246
|
-
const ann = server.tools.get(meta).config.annotations;
|
|
247
|
-
assert.equal(ann?.readOnlyHint, true, `${meta} must be read-only`);
|
|
248
|
-
assert.equal(ann?.openWorldHint, false, `${meta} must be closed-world`);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
test("meta-tools expose typed inputSchema so agents get arg hints", () => {
|
|
252
|
-
const { server } = makeGroupedServer();
|
|
253
|
-
// list_tool_groups takes no args.
|
|
254
|
-
assert.deepEqual(Object.keys(server.tools.get("list_tool_groups").config.inputSchema ?? {}), [], "list_tool_groups must take no args");
|
|
255
|
-
// search_tools advertises query/group/limit.
|
|
256
|
-
assert.deepEqual(Object.keys(server.tools.get("search_tools").config.inputSchema ?? {}).sort(), ["group", "limit", "query"], "search_tools must advertise query/group/limit");
|
|
257
|
-
// describe_tool advertises a required `name`.
|
|
258
|
-
const describeSchema = server.tools.get("describe_tool").config.inputSchema ?? {};
|
|
259
|
-
assert.deepEqual(Object.keys(describeSchema), ["name"], "describe_tool must advertise a `name` arg");
|
|
260
|
-
// The name field is a Zod schema (typed hint), not a bare placeholder.
|
|
261
|
-
assert.equal(typeof describeSchema.name?.parse, "function", "describe_tool.name must be a Zod schema");
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
//# sourceMappingURL=tool-exposure.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tool-exposure.test.js","sourceRoot":"","sources":["../../src/__tests__/tool-exposure.test.ts"],"names":[],"mappings":"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"}
|