@cmssy/mcp-server 0.87.0 → 0.88.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=binder-input-validation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binder-input-validation.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/binder-input-validation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,148 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { z } from "zod";
3
+ import * as aiTools from "@cmssy/ai-tools";
4
+ import { createServer } from "../server.js";
5
+ import { callBound as call, connectBound as connect, connectServer, validationRefusal as refusal, } from "./mcp-harness.js";
6
+ const refusingOps = {};
7
+ function fakeTool(overrides) {
8
+ return {
9
+ name: "probe_tool",
10
+ description: "a tool",
11
+ requiredPermissions: [],
12
+ execute: async (input) => ({ echoed: input }),
13
+ ...overrides,
14
+ };
15
+ }
16
+ describe("the binder hands the MCP server the schema the tool declared (CMS-1982)", () => {
17
+ it("refuses a parameter the tool does not declare instead of discarding it", async () => {
18
+ const client = await connect([
19
+ fakeTool({
20
+ inputSchema: z.object({
21
+ limit: z.number().int().optional(),
22
+ }),
23
+ }),
24
+ ], refusingOps);
25
+ const result = await call(client, "probe_tool", { limit: 5, type: "video" });
26
+ expect(refusal(result), "an undeclared parameter has to come back as a refusal; stripping it answers a request nobody made and reads as success").toMatch(/type/);
27
+ });
28
+ it("names the required parameters in the advertised schema", async () => {
29
+ const client = await connect([
30
+ fakeTool({
31
+ inputSchema: z.object({
32
+ id: z.string().min(1),
33
+ name: z.string().optional(),
34
+ rows: z.array(z.object({ k: z.string() })),
35
+ page: z.number().default(1),
36
+ }),
37
+ }),
38
+ ], refusingOps);
39
+ const listed = await client.listTools();
40
+ const schema = listed.tools[0].inputSchema;
41
+ expect(schema.required?.sort(), "a parameter the tool cannot run without has to reach the model as required; an empty required list reads as 'everything is optional'").toStrictEqual(["id", "rows"]);
42
+ expect(schema.additionalProperties).toBe(false);
43
+ expect(Object.keys(schema.properties ?? {}).sort()).toStrictEqual([
44
+ "id",
45
+ "name",
46
+ "page",
47
+ "rows",
48
+ ]);
49
+ });
50
+ it("still accepts an object parameter sent as a JSON-encoded string", async () => {
51
+ const client = await connect([
52
+ fakeTool({
53
+ inputSchema: z.object({
54
+ id: z.string(),
55
+ rows: z.array(z.object({ k: z.string() })),
56
+ }),
57
+ }),
58
+ ], refusingOps);
59
+ const result = await call(client, "probe_tool", {
60
+ id: "a",
61
+ rows: '[{"k":"v"}]',
62
+ });
63
+ expect(JSON.parse(result.content[0].text)).toStrictEqual({ echoed: { id: "a", rows: [{ k: "v" }] } });
64
+ });
65
+ it("refuses a value of the wrong type for a declared parameter", async () => {
66
+ const client = await connect([
67
+ fakeTool({
68
+ inputSchema: z.object({
69
+ limit: z.number(),
70
+ }),
71
+ }),
72
+ ], refusingOps);
73
+ const result = await call(client, "probe_tool", { limit: "lots" });
74
+ expect(refusal(result)).toMatch(/limit/);
75
+ });
76
+ });
77
+ const OBJECT_LEVEL_RULES = {
78
+ update_media_folder: {
79
+ refused: { id: "6abd61e1a51c17ea3525336a" },
80
+ accepted: { id: "6abd61e1a51c17ea3525336a", name: "renamed" },
81
+ },
82
+ upload_media: {
83
+ refused: { filePath: "/tmp/a.png", url: "https://example.com/a.png" },
84
+ accepted: { filePath: "/tmp/a.png" },
85
+ },
86
+ };
87
+ function declaredTools() {
88
+ return Object.values(aiTools).filter((value) => typeof value === "object" &&
89
+ value !== null &&
90
+ "name" in value &&
91
+ "inputSchema" in value &&
92
+ "execute" in value);
93
+ }
94
+ function withObjectLevelRules() {
95
+ return declaredTools().filter((tool) => (tool.inputSchema._zod?.def?.checks?.length ?? 0) > 0);
96
+ }
97
+ describe("a rule the tool declares across its parameters is enforced through the binder (CMS-1982)", () => {
98
+ it("covers every tool whose input schema carries an object-level rule", () => {
99
+ expect(withObjectLevelRules()
100
+ .map((tool) => tool.name)
101
+ .sort(), "the table below is the proof per rule; a tool that gains a cross-field rule without a row here would be bound unenforced and nothing else would notice").toStrictEqual(Object.keys(OBJECT_LEVEL_RULES).sort());
102
+ });
103
+ for (const [name, probe] of Object.entries(OBJECT_LEVEL_RULES)) {
104
+ it(`refuses the input ${name} was written to refuse`, async () => {
105
+ const tool = declaredTools().find((candidate) => candidate.name === name);
106
+ expect(tool, `${name} is no longer exported`).toBeDefined();
107
+ const client = await connect([tool], refusingOps);
108
+ const result = await call(client, name, probe.refused);
109
+ expect(refusal(result), "the rule is declared across the parameters, so only a parse of the whole object can enforce it").toBeTruthy();
110
+ });
111
+ it(`lets ${name} through once the rule is satisfied`, async () => {
112
+ const tool = declaredTools().find((candidate) => candidate.name === name);
113
+ const client = await connect([{ ...tool, execute: async () => ({ ok: true }) }], refusingOps);
114
+ const result = await call(client, name, probe.accepted);
115
+ expect(result.isError, "the rule has to refuse its own case only; a guard that refuses everything proves nothing").toBeFalsy();
116
+ });
117
+ }
118
+ });
119
+ const RULE_INSTEAD_OF_A_REQUIRED_FIELD = ["upload_media"];
120
+ describe("every tool the live server binds advertises what it needs (CMS-1982)", () => {
121
+ async function advertised() {
122
+ const client = await connectServer(createServer({ query: vi.fn() }));
123
+ const listed = await client.listTools();
124
+ return listed.tools.map((tool) => ({
125
+ name: tool.name,
126
+ schema: tool.inputSchema,
127
+ }));
128
+ }
129
+ it("refuses an undeclared parameter on every one of them", async () => {
130
+ const open = (await advertised()).filter((tool) => tool.schema.additionalProperties !== false);
131
+ expect(open.map((tool) => tool.name)).toStrictEqual([]);
132
+ });
133
+ it("names a required parameter whenever the tool cannot run without one", async () => {
134
+ const byName = new Map(declaredTools().map((tool) => [tool.name, tool.inputSchema]));
135
+ const disagree = [];
136
+ for (const { name, schema } of await advertised()) {
137
+ const declared = byName.get(name);
138
+ if (!declared)
139
+ continue;
140
+ const needsSomething = !declared.safeParse({}).success;
141
+ const advertisesSomething = (schema.required ?? []).length > 0;
142
+ if (needsSomething !== advertisesSomething)
143
+ disagree.push(name);
144
+ }
145
+ expect(disagree, "a tool that refuses an empty call has to say which parameter it was missing; before CMS-1982 the rebuilt shape left required empty on 71 of them and the model had to guess. The exception is a tool whose requirement is a rule across optional parameters - JSON Schema cannot carry 'exactly one of', so the rule surfaces as the refusal proven in the table above, and a tool joining that class has to be a decision rather than a silent entry").toStrictEqual(RULE_INSTEAD_OF_A_REQUIRED_FIELD);
146
+ });
147
+ });
148
+ //# sourceMappingURL=binder-input-validation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binder-input-validation.test.js","sourceRoot":"","sources":["../../src/__tests__/binder-input-validation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EACL,SAAS,IAAI,IAAI,EACjB,YAAY,IAAI,OAAO,EACvB,aAAa,EACb,iBAAiB,IAAI,OAAO,GAC7B,MAAM,kBAAkB,CAAC;AAQ1B,MAAM,WAAW,GAAG,EAAkB,CAAC;AAEvC,SAAS,QAAQ,CACf,SAAwD;IAExD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,QAAQ;QACrB,mBAAmB,EAAE,EAAE;QACvB,OAAO,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACtD,GAAG,SAAS;KACQ,CAAC;AACzB,CAAC;AAED,QAAQ,CAAC,yEAAyE,EAAE,GAAG,EAAE;IACvF,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B;YACE,QAAQ,CAAC;gBACP,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;iBACnC,CAAqC;aACvC,CAAC;SACH,EACD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAE7E,MAAM,CACJ,OAAO,CAAC,MAAM,CAAC,EACf,wHAAwH,CACzH,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B;YACE,QAAQ,CAAC;gBACP,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;oBACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;oBAC3B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;oBAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;iBAC5B,CAAqC;aACvC,CAAC;SACH,EACD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,WAAyB,CAAC;QAE1D,MAAM,CACJ,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EACvB,sIAAsI,CACvI,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC;YAChE,IAAI;YACJ,MAAM;YACN,MAAM;YACN,MAAM;SACP,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B;YACE,QAAQ,CAAC;gBACP,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;oBACd,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;iBAC3C,CAAqC;aACvC,CAAC;SACH,EACD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE;YAC9C,EAAE,EAAE,GAAG;YACP,IAAI,EAAE,aAAa;SACpB,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,KAAK,CAAE,MAAM,CAAC,OAA8B,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAC/E,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B;YACE,QAAQ,CAAC;gBACP,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;iBAClB,CAAqC;aACvC,CAAC;SACH,EACD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEnE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,kBAAkB,GACtB;IACE,mBAAmB,EAAE;QACnB,OAAO,EAAE,EAAE,EAAE,EAAE,0BAA0B,EAAE;QAC3C,QAAQ,EAAE,EAAE,EAAE,EAAE,0BAA0B,EAAE,IAAI,EAAE,SAAS,EAAE;KAC9D;IACD,YAAY,EAAE;QACZ,OAAO,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,2BAA2B,EAAE;QACrE,QAAQ,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE;KACrC;CACF,CAAC;AAEJ,SAAS,aAAa;IACpB,OAAQ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAe,CAAC,MAAM,CACjD,CAAC,KAAK,EAAmB,EAAE,CACzB,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,aAAa,IAAI,KAAK;QACtB,SAAS,IAAI,KAAK,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB;IAC3B,OAAO,aAAa,EAAE,CAAC,MAAM,CAC3B,CAAC,IAAI,EAAE,EAAE,CACP,CACE,IAAI,CAAC,WAGN,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CACxC,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,0FAA0F,EAAE,GAAG,EAAE;IACxG,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CACJ,oBAAoB,EAAE;aACnB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACxB,IAAI,EAAE,EACT,wJAAwJ,CACzJ,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/D,EAAE,CAAC,qBAAqB,IAAI,wBAAwB,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC1E,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,wBAAwB,CAAC,CAAC,WAAW,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC,IAAK,CAAC,EAAE,WAAW,CAAC,CAAC;YAEnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAEvD,MAAM,CACJ,OAAO,CAAC,MAAM,CAAC,EACf,gGAAgG,CACjG,CAAC,UAAU,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,QAAQ,IAAI,qCAAqC,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,CAAC,EAAE,GAAG,IAAK,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAY,CAAC,EAC7D,WAAW,CACZ,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;YAExD,MAAM,CACJ,MAAM,CAAC,OAAO,EACd,0FAA0F,CAC3F,CAAC,SAAS,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,gCAAgC,GAAG,CAAC,cAAc,CAAC,CAAC;AAE1D,QAAQ,CAAC,sEAAsE,EAAE,GAAG,EAAE;IACpF,KAAK,UAAU,UAAU;QACvB,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAA4B,CAAC,CAC3D,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,WAAyB;SACvC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,IAAI,GAAG,CAAC,MAAM,UAAU,EAAE,CAAC,CAAC,MAAM,CACtC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,KAAK,KAAK,CACrD,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAC7D,CAAC;QACF,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAE,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ;gBAAE,SAAS;YACxB,MAAM,cAAc,GAAG,CACrB,QACD,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;YACxB,MAAM,mBAAmB,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAC/D,IAAI,cAAc,KAAK,mBAAmB;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,CACJ,QAAQ,EACR,ubAAub,CACxb,CAAC,aAAa,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,15 +1,9 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { z } from "zod";
3
- import { bindSharedTool } from "../ai-tools-binder.js";
4
3
  import { TOOL_HEADER, clientHeaders } from "../client-marker.js";
4
+ import { callBound, connectBound } from "./mcp-harness.js";
5
5
  describe("a bound tool runs inside its own tool call (CMS-1865)", () => {
6
6
  it("lets the client name the tool while the tool executes", async () => {
7
- let handler;
8
- const server = {
9
- tool: (_n, _d, _s, fn) => {
10
- handler = fn;
11
- },
12
- };
13
7
  let seen;
14
8
  const tool = {
15
9
  name: "list_pages",
@@ -20,8 +14,8 @@ describe("a bound tool runs inside its own tool call (CMS-1865)", () => {
20
14
  return { ok: true };
21
15
  },
22
16
  };
23
- bindSharedTool(server, tool, {});
24
- await handler?.({});
17
+ const client = await connectBound([tool], {});
18
+ await callBound(client, "list_pages", {});
25
19
  expect(seen?.[TOOL_HEADER]).toBe("list_pages");
26
20
  expect(clientHeaders("0.0.0")).not.toHaveProperty(TOOL_HEADER);
27
21
  });
@@ -1 +1 @@
1
- {"version":3,"file":"binder-tool-marker.test.js","sourceRoot":"","sources":["../../src/__tests__/binder-tool-marker.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEjE,QAAQ,CAAC,uDAAuD,EAAE,GAAG,EAAE;IACrE,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,IAAI,OAA2D,CAAC;QAChE,MAAM,MAAM,GAAG;YACb,IAAI,EAAE,CAAC,EAAU,EAAE,EAAU,EAAE,EAAW,EAAE,EAAkB,EAAE,EAAE;gBAChE,OAAO,GAAG,EAAE,CAAC;YACf,CAAC;SACsB,CAAC;QAC1B,IAAI,IAAwC,CAAC;QAC7C,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC9B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC;SACmB,CAAC;QAEvB,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,EAAkB,CAAC,CAAC;QACjD,MAAM,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAEpB,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"binder-tool-marker.test.js","sourceRoot":"","sources":["../../src/__tests__/binder-tool-marker.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE3D,QAAQ,CAAC,uDAAuD,EAAE,GAAG,EAAE;IACrE,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,IAAI,IAAwC,CAAC;QAC7C,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBAC9B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC;SACmB,CAAC;QAEvB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,EAAkB,CAAC,CAAC;QAC9D,MAAM,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAE1C,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
+ import type { AiTool, WorkspaceOps } from "@cmssy/ai-tools";
4
+ export declare function connectServer(server: McpServer): Promise<Client>;
5
+ export declare function connectBound(tools: AiTool[], ops: WorkspaceOps): Promise<Client>;
6
+ export declare function callBound(client: Client, name: string, args: unknown): Promise<Awaited<ReturnType<Client["callTool"]>>>;
7
+ export declare function validationRefusal(result: Awaited<ReturnType<Client["callTool"]>>): string | null;
8
+ //# sourceMappingURL=mcp-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-harness.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG5D,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAStE;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAElD;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,GAC9C,MAAM,GAAG,IAAI,CAIf"}
@@ -0,0 +1,29 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
4
+ import { bindSharedTool } from "../ai-tools-binder.js";
5
+ export async function connectServer(server) {
6
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
7
+ const client = new Client({ name: "test-client", version: "0.0.0" });
8
+ await Promise.all([
9
+ client.connect(clientTransport),
10
+ server.connect(serverTransport),
11
+ ]);
12
+ return client;
13
+ }
14
+ export async function connectBound(tools, ops) {
15
+ const server = new McpServer({ name: "test", version: "0.0.0" });
16
+ for (const tool of tools)
17
+ bindSharedTool(server, tool, ops);
18
+ return connectServer(server);
19
+ }
20
+ export async function callBound(client, name, args) {
21
+ return client.callTool({ name, arguments: args });
22
+ }
23
+ export function validationRefusal(result) {
24
+ if (!result.isError)
25
+ return null;
26
+ const text = result.content[0]?.text ?? "";
27
+ return text.includes("Input validation error") ? text : null;
28
+ }
29
+ //# sourceMappingURL=mcp-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-harness.js","sourceRoot":"","sources":["../../src/__tests__/mcp-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAiB;IACnD,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,GACtC,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACrE,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC;KAChC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAe,EACf,GAAiB;IAEjB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,IAAY,EACZ,IAAa;IAEb,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAA+B,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAA+C;IAE/C,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAAI,MAAM,CAAC,OAA+B,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IACpE,OAAO,IAAI,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC"}
@@ -1,5 +1,7 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
2
3
  import type { AiTool, WorkspaceOps } from "@cmssy/ai-tools";
3
4
  export declare function boundDeclarations(server: McpServer): Map<string, AiTool>;
5
+ export declare function toolInputSchema(tool: Pick<AiTool, "inputSchema">): z.ZodObject<z.ZodRawShape>;
4
6
  export declare function bindSharedTool(server: McpServer, tool: AiTool, ops: WorkspaceOps): void;
5
7
  //# sourceMappingURL=ai-tools-binder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-tools-binder.d.ts","sourceRoot":"","sources":["../src/ai-tools-binder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe5D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAExE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,GAChB,IAAI,CAkCN"}
1
+ {"version":3,"file":"ai-tools-binder.d.ts","sourceRoot":"","sources":["../src/ai-tools-binder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe5D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAExE;AAOD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,GAChC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAS5B;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,GAChB,IAAI,CAkCN"}
@@ -15,17 +15,26 @@ const declarations = new WeakMap();
15
15
  export function boundDeclarations(server) {
16
16
  return declarations.get(server) ?? new Map();
17
17
  }
18
+ function coerceJson(schema) {
19
+ const wrapped = z.preprocess(jsonPreprocess, schema);
20
+ return schema.safeParse(undefined).success ? wrapped : wrapped.nonoptional();
21
+ }
22
+ export function toolInputSchema(tool) {
23
+ const declared = tool.inputSchema;
24
+ const coerced = Object.fromEntries(Object.entries(declared.shape).map(([key, schema]) => [
25
+ key,
26
+ coerceJson(schema),
27
+ ]));
28
+ return declared.safeExtend(coerced).strict();
29
+ }
18
30
  export function bindSharedTool(server, tool, ops) {
19
31
  const declared = declarations.get(server) ?? new Map();
20
32
  declared.set(tool.name, tool);
21
33
  declarations.set(server, declared);
22
- const shape = tool.inputSchema
23
- .shape;
24
- const mcpShape = Object.fromEntries(Object.entries(shape).map(([key, schema]) => [
25
- key,
26
- z.preprocess(jsonPreprocess, schema),
27
- ]));
28
- server.tool(tool.name, tool.description, mcpShape, async (input) => {
34
+ server.registerTool(tool.name, {
35
+ description: tool.description,
36
+ inputSchema: toolInputSchema(tool),
37
+ }, async (input) => {
29
38
  try {
30
39
  const result = await runAsTool(tool.name, () => tool.execute(input, ops));
31
40
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-tools-binder.js","sourceRoot":"","sources":["../src/ai-tools-binder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,cAAc,GAAG,CAAC,GAAY,EAAE,EAAE;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,IAAI,OAAO,EAAkC,CAAC;AAEnE,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,OAAO,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAiB,EACjB,IAAY,EACZ,GAAiB;IAEjB,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;IACvE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAI,IAAI,CAAC,WAAqD;SACtE,KAAK,CAAC;IACT,MAAM,QAAQ,GAAkB,MAAM,CAAC,WAAW,CAChD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;QAC3C,GAAG;QACH,CAAC,CAAC,UAAU,CAAC,cAAc,EAAE,MAAsB,CAAC;KACrD,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE;QAC1E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1E,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;iBACjE;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;qBACvD;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"ai-tools-binder.js","sourceRoot":"","sources":["../src/ai-tools-binder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmssy/mcp-server",
3
- "version": "0.87.0",
3
+ "version": "0.88.0",
4
4
  "description": "MCP server for Cmssy CMS — enables AI-driven page creation and management",
5
5
  "mcpName": "io.github.cmssy-io/cmssy-mcp",
6
6
  "homepage": "https://cmssy.com",