@cmssy/mcp-server 0.92.4 → 0.93.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/dist/__tests__/confirm-gate.test.d.ts +2 -0
- package/dist/__tests__/confirm-gate.test.d.ts.map +1 -0
- package/dist/__tests__/confirm-gate.test.js +147 -0
- package/dist/__tests__/confirm-gate.test.js.map +1 -0
- package/dist/ai-tools-binder.d.ts +1 -1
- package/dist/ai-tools-binder.d.ts.map +1 -1
- package/dist/ai-tools-binder.js +53 -1
- package/dist/ai-tools-binder.js.map +1 -1
- package/dist/confirm-gate.d.ts +12 -0
- package/dist/confirm-gate.d.ts.map +1 -0
- package/dist/confirm-gate.js +60 -0
- package/dist/confirm-gate.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-gate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/confirm-gate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CONFIRM_GATED_TOOLS, cancelOrderTool } from "@cmssy/ai-tools";
|
|
4
|
+
import { toolInputSchema } from "../ai-tools-binder.js";
|
|
5
|
+
import { CONFIRM_ARG } from "../confirm-gate.js";
|
|
6
|
+
import { callBound as call, connectBound as connect } from "./mcp-harness.js";
|
|
7
|
+
function gatedTool(execute) {
|
|
8
|
+
return {
|
|
9
|
+
name: "delete_record",
|
|
10
|
+
description: "a destructive tool",
|
|
11
|
+
requiredPermissions: [],
|
|
12
|
+
confirmGated: true,
|
|
13
|
+
inputSchema: z.object({
|
|
14
|
+
modelIdOrSlug: z.string(),
|
|
15
|
+
recordId: z.string(),
|
|
16
|
+
}),
|
|
17
|
+
execute,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function resultJson(result) {
|
|
21
|
+
const text = result.content[0]?.text ?? "";
|
|
22
|
+
return JSON.parse(text);
|
|
23
|
+
}
|
|
24
|
+
const ARGS = { modelIdOrSlug: "products", recordId: "r1" };
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
vi.useRealTimers();
|
|
27
|
+
});
|
|
28
|
+
describe("the MCP confirm gate (CMS-2067)", () => {
|
|
29
|
+
it("refuses the first call and does not execute - the moat claim is server-side on this surface too", async () => {
|
|
30
|
+
const execute = vi.fn();
|
|
31
|
+
const client = await connect([gatedTool(execute)], {});
|
|
32
|
+
const result = await call(client, "delete_record", ARGS);
|
|
33
|
+
const body = resultJson(result);
|
|
34
|
+
expect(execute, "a gated tool executing on its first call is exactly the hole the funnel run found: cancel_order ran with no confirmation").not.toHaveBeenCalled();
|
|
35
|
+
expect(body.needsConfirmation).toBe(true);
|
|
36
|
+
expect(body.ref).toMatch(/^[0-9a-f]{8}$/);
|
|
37
|
+
expect(body.instruction).toContain("NOT performed");
|
|
38
|
+
});
|
|
39
|
+
it("executes exactly once with the issued ref and refuses the replay", async () => {
|
|
40
|
+
const execute = vi.fn().mockResolvedValue({ deleted: true });
|
|
41
|
+
const client = await connect([gatedTool(execute)], {});
|
|
42
|
+
const first = resultJson(await call(client, "delete_record", ARGS));
|
|
43
|
+
const approved = await call(client, "delete_record", {
|
|
44
|
+
...ARGS,
|
|
45
|
+
[CONFIRM_ARG]: first.ref,
|
|
46
|
+
});
|
|
47
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
48
|
+
expect(execute.mock.calls[0][0], "the ref must not leak into the tool's own input - ai-tools schemas never declared it").toEqual(ARGS);
|
|
49
|
+
expect(resultJson(approved)).toEqual({ deleted: true });
|
|
50
|
+
const replay = resultJson(await call(client, "delete_record", {
|
|
51
|
+
...ARGS,
|
|
52
|
+
[CONFIRM_ARG]: first.ref,
|
|
53
|
+
}));
|
|
54
|
+
expect(replay.needsConfirmation, "a consumed ref approving a second run would turn one approval into unlimited runs").toBe(true);
|
|
55
|
+
expect(replay.refusedBecause).toBe("unknown-ref");
|
|
56
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
57
|
+
});
|
|
58
|
+
it("refuses a ref when the arguments drifted - the approval covered different work", async () => {
|
|
59
|
+
const execute = vi.fn();
|
|
60
|
+
const client = await connect([gatedTool(execute)], {});
|
|
61
|
+
const first = resultJson(await call(client, "delete_record", ARGS));
|
|
62
|
+
const drifted = resultJson(await call(client, "delete_record", {
|
|
63
|
+
modelIdOrSlug: "products",
|
|
64
|
+
recordId: "r2",
|
|
65
|
+
[CONFIRM_ARG]: first.ref,
|
|
66
|
+
}));
|
|
67
|
+
expect(execute).not.toHaveBeenCalled();
|
|
68
|
+
expect(drifted.refusedBecause).toBe("args-changed");
|
|
69
|
+
expect(drifted.needsConfirmation).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
it("refuses an expired ref and issues a fresh one", async () => {
|
|
72
|
+
vi.useFakeTimers();
|
|
73
|
+
const execute = vi.fn();
|
|
74
|
+
const client = await connect([gatedTool(execute)], {});
|
|
75
|
+
const first = resultJson(await call(client, "delete_record", ARGS));
|
|
76
|
+
vi.advanceTimersByTime(601_000);
|
|
77
|
+
const expired = resultJson(await call(client, "delete_record", {
|
|
78
|
+
...ARGS,
|
|
79
|
+
[CONFIRM_ARG]: first.ref,
|
|
80
|
+
}));
|
|
81
|
+
expect(execute).not.toHaveBeenCalled();
|
|
82
|
+
expect(expired.refusedBecause).toBe("expired");
|
|
83
|
+
expect(expired.ref).not.toBe(first.ref);
|
|
84
|
+
});
|
|
85
|
+
it("re-asking without a ref reuses the live pending ref instead of minting a parade of them", async () => {
|
|
86
|
+
const execute = vi.fn();
|
|
87
|
+
const client = await connect([gatedTool(execute)], {});
|
|
88
|
+
const first = resultJson(await call(client, "delete_record", ARGS));
|
|
89
|
+
const second = resultJson(await call(client, "delete_record", ARGS));
|
|
90
|
+
expect(second.ref).toBe(first.ref);
|
|
91
|
+
});
|
|
92
|
+
it("an invented ref never executes", async () => {
|
|
93
|
+
const execute = vi.fn();
|
|
94
|
+
const client = await connect([gatedTool(execute)], {});
|
|
95
|
+
const forged = resultJson(await call(client, "delete_record", {
|
|
96
|
+
...ARGS,
|
|
97
|
+
[CONFIRM_ARG]: "deadbeef",
|
|
98
|
+
}));
|
|
99
|
+
expect(execute).not.toHaveBeenCalled();
|
|
100
|
+
expect(forged.refusedBecause).toBe("unknown-ref");
|
|
101
|
+
});
|
|
102
|
+
it("an ungated tool executes directly and does not advertise _confirm", async () => {
|
|
103
|
+
const execute = vi.fn().mockResolvedValue({ ok: true });
|
|
104
|
+
const tool = {
|
|
105
|
+
name: "list_records",
|
|
106
|
+
description: "read",
|
|
107
|
+
requiredPermissions: [],
|
|
108
|
+
inputSchema: z.object({
|
|
109
|
+
modelIdOrSlug: z.string(),
|
|
110
|
+
}),
|
|
111
|
+
execute,
|
|
112
|
+
};
|
|
113
|
+
const client = await connect([tool], {});
|
|
114
|
+
const result = await call(client, "list_records", {
|
|
115
|
+
modelIdOrSlug: "products",
|
|
116
|
+
});
|
|
117
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
118
|
+
expect(resultJson(result)).toEqual({ ok: true });
|
|
119
|
+
expect(Object.keys(toolInputSchema(tool).shape), "advertising _confirm on a read tool would teach agents to pass it everywhere").not.toContain(CONFIRM_ARG);
|
|
120
|
+
});
|
|
121
|
+
it("a real gated tool from the registry advertises _confirm in its schema", () => {
|
|
122
|
+
expect(cancelOrderTool.confirmGated).toBe(true);
|
|
123
|
+
expect(Object.keys(toolInputSchema(cancelOrderTool).shape)).toContain(CONFIRM_ARG);
|
|
124
|
+
});
|
|
125
|
+
it("pins the gated vocabulary this server enforces", () => {
|
|
126
|
+
expect([...CONFIRM_GATED_TOOLS].sort()).toEqual([
|
|
127
|
+
"bulk_delete_products",
|
|
128
|
+
"bulk_update_products",
|
|
129
|
+
"cancel_order",
|
|
130
|
+
"clear_cart_config",
|
|
131
|
+
"delete_form",
|
|
132
|
+
"delete_form_submission",
|
|
133
|
+
"delete_model",
|
|
134
|
+
"delete_page",
|
|
135
|
+
"delete_record",
|
|
136
|
+
"delete_webhook",
|
|
137
|
+
"promote_dev_draft",
|
|
138
|
+
"publish_page",
|
|
139
|
+
"refund_order",
|
|
140
|
+
"revert_to_published",
|
|
141
|
+
"rotate_webhook_secret",
|
|
142
|
+
"suspend_customer",
|
|
143
|
+
"unpublish_page",
|
|
144
|
+
]);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=confirm-gate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-gate.test.js","sourceRoot":"","sources":["../../src/__tests__/confirm-gate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { AiTool, WorkspaceOps } from "@cmssy/ai-tools";
|
|
4
4
|
export declare function boundDeclarations(server: McpServer): Map<string, AiTool>;
|
|
5
|
-
export declare function toolInputSchema(tool: Pick<AiTool, "inputSchema">): z.ZodObject<z.ZodRawShape>;
|
|
5
|
+
export declare function toolInputSchema(tool: Pick<AiTool, "inputSchema" | "confirmGated">): z.ZodObject<z.ZodRawShape>;
|
|
6
6
|
export declare function bindSharedTool(server: McpServer, tool: AiTool, ops: WorkspaceOps): void;
|
|
7
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;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
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;AAyE5D,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,GAAG,cAAc,CAAC,GACjD,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAY5B;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,GAChB,IAAI,CAkDN"}
|
package/dist/ai-tools-binder.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { runAsTool } from "./client-marker.js";
|
|
3
|
+
import { CONFIRM_ARG, CONFIRM_REF_PATTERN, CONFIRMATION_TTL_SECONDS, ConfirmGate, confirmArgsHash, confirmSummary, } from "./confirm-gate.js";
|
|
3
4
|
const jsonPreprocess = (val) => {
|
|
4
5
|
if (typeof val !== "string")
|
|
5
6
|
return val;
|
|
@@ -12,6 +13,41 @@ const jsonPreprocess = (val) => {
|
|
|
12
13
|
}
|
|
13
14
|
};
|
|
14
15
|
const declarations = new WeakMap();
|
|
16
|
+
const gates = new WeakMap();
|
|
17
|
+
function gateFor(server) {
|
|
18
|
+
const existing = gates.get(server);
|
|
19
|
+
if (existing)
|
|
20
|
+
return existing;
|
|
21
|
+
const gate = new ConfirmGate();
|
|
22
|
+
gates.set(server, gate);
|
|
23
|
+
return gate;
|
|
24
|
+
}
|
|
25
|
+
const confirmArgSchema = z
|
|
26
|
+
.string()
|
|
27
|
+
.regex(CONFIRM_REF_PATTERN)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Confirmation ref this server issued for this exact call after the user approved it. Never invent or reuse one.");
|
|
30
|
+
function confirmationPrompt(gate, toolName, args, reason) {
|
|
31
|
+
const ref = gate.request(toolName, confirmArgsHash(args));
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: JSON.stringify({
|
|
37
|
+
needsConfirmation: true,
|
|
38
|
+
ref,
|
|
39
|
+
...(reason ? { refusedBecause: reason } : {}),
|
|
40
|
+
summary: confirmSummary(toolName, args),
|
|
41
|
+
expiresInSeconds: CONFIRMATION_TTL_SECONDS,
|
|
42
|
+
instruction: "This action was NOT performed. Tell the user exactly what it " +
|
|
43
|
+
"would do and wait for their explicit approval in their next " +
|
|
44
|
+
`message. Then call the tool once more with the same arguments plus ${CONFIRM_ARG}: "${ref}". ` +
|
|
45
|
+
"Never invent a ref and never confirm on the user's behalf.",
|
|
46
|
+
}, null, 2),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
15
51
|
export function boundDeclarations(server) {
|
|
16
52
|
return declarations.get(server) ?? new Map();
|
|
17
53
|
}
|
|
@@ -25,6 +61,9 @@ export function toolInputSchema(tool) {
|
|
|
25
61
|
key,
|
|
26
62
|
coerceJson(schema),
|
|
27
63
|
]));
|
|
64
|
+
if (tool.confirmGated === true) {
|
|
65
|
+
coerced[CONFIRM_ARG] = confirmArgSchema;
|
|
66
|
+
}
|
|
28
67
|
return declared.safeExtend(coerced).strict();
|
|
29
68
|
}
|
|
30
69
|
export function bindSharedTool(server, tool, ops) {
|
|
@@ -35,8 +74,21 @@ export function bindSharedTool(server, tool, ops) {
|
|
|
35
74
|
description: tool.description,
|
|
36
75
|
inputSchema: toolInputSchema(tool),
|
|
37
76
|
}, async (input) => {
|
|
77
|
+
let executeInput = input;
|
|
78
|
+
if (tool.confirmGated === true) {
|
|
79
|
+
const gate = gateFor(server);
|
|
80
|
+
const { [CONFIRM_ARG]: ref, ...rest } = input;
|
|
81
|
+
if (typeof ref !== "string") {
|
|
82
|
+
return confirmationPrompt(gate, tool.name, rest, null);
|
|
83
|
+
}
|
|
84
|
+
const outcome = gate.consume(ref, tool.name, confirmArgsHash(rest));
|
|
85
|
+
if (outcome !== "approved") {
|
|
86
|
+
return confirmationPrompt(gate, tool.name, rest, outcome);
|
|
87
|
+
}
|
|
88
|
+
executeInput = rest;
|
|
89
|
+
}
|
|
38
90
|
try {
|
|
39
|
-
const result = await runAsTool(tool.name, () => tool.execute(
|
|
91
|
+
const result = await runAsTool(tool.name, () => tool.execute(executeInput, ops));
|
|
40
92
|
return {
|
|
41
93
|
content: [
|
|
42
94
|
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"ai-tools-binder.js","sourceRoot":"","sources":["../src/ai-tools-binder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const CONFIRMATION_TTL_SECONDS = 600;
|
|
2
|
+
export declare const CONFIRM_ARG = "_confirm";
|
|
3
|
+
export declare const CONFIRM_REF_PATTERN: RegExp;
|
|
4
|
+
export declare function confirmArgsHash(input: unknown): string;
|
|
5
|
+
export declare function confirmSummary(toolName: string, input: unknown): string;
|
|
6
|
+
export type ConsumeOutcome = "approved" | "unknown-ref" | "expired" | "args-changed";
|
|
7
|
+
export declare class ConfirmGate {
|
|
8
|
+
private pending;
|
|
9
|
+
request(toolName: string, argsHash: string): string;
|
|
10
|
+
consume(ref: string, toolName: string, argsHash: string): ConsumeOutcome;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=confirm-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-gate.d.ts","sourceRoot":"","sources":["../src/confirm-gate.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,mBAAmB,QAAkB,CAAC;AAanD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAItD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAEvE;AAED,MAAM,MAAM,cAAc,GACxB,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,cAAc,CAAC;AAQ1D,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA0C;IAEzD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoBnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc;CAazE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
export const CONFIRMATION_TTL_SECONDS = 600;
|
|
3
|
+
export const CONFIRM_ARG = "_confirm";
|
|
4
|
+
export const CONFIRM_REF_PATTERN = /^[0-9a-f]{8}$/;
|
|
5
|
+
function canonicalize(value) {
|
|
6
|
+
if (Array.isArray(value))
|
|
7
|
+
return value.map(canonicalize);
|
|
8
|
+
if (value !== null && typeof value === "object") {
|
|
9
|
+
const entries = Object.entries(value)
|
|
10
|
+
.filter(([, v]) => v !== undefined)
|
|
11
|
+
.sort(([a], [b]) => (a < b ? -1 : 1));
|
|
12
|
+
return Object.fromEntries(entries.map(([k, v]) => [k, canonicalize(v)]));
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function confirmArgsHash(input) {
|
|
17
|
+
return createHash("sha256")
|
|
18
|
+
.update(JSON.stringify(canonicalize(input)))
|
|
19
|
+
.digest("hex");
|
|
20
|
+
}
|
|
21
|
+
export function confirmSummary(toolName, input) {
|
|
22
|
+
return `${toolName.split("_").join(" ")} ${JSON.stringify(canonicalize(input))}`;
|
|
23
|
+
}
|
|
24
|
+
export class ConfirmGate {
|
|
25
|
+
pending = new Map();
|
|
26
|
+
request(toolName, argsHash) {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
for (const [ref, entry] of this.pending) {
|
|
29
|
+
if (entry.expiresAt <= now) {
|
|
30
|
+
this.pending.delete(ref);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (entry.toolName === toolName && entry.argsHash === argsHash) {
|
|
34
|
+
return ref;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const ref = randomBytes(4).toString("hex");
|
|
38
|
+
this.pending.set(ref, {
|
|
39
|
+
toolName,
|
|
40
|
+
argsHash,
|
|
41
|
+
expiresAt: now + CONFIRMATION_TTL_SECONDS * 1000,
|
|
42
|
+
});
|
|
43
|
+
return ref;
|
|
44
|
+
}
|
|
45
|
+
consume(ref, toolName, argsHash) {
|
|
46
|
+
const entry = this.pending.get(ref);
|
|
47
|
+
if (!entry)
|
|
48
|
+
return "unknown-ref";
|
|
49
|
+
if (entry.expiresAt <= Date.now()) {
|
|
50
|
+
this.pending.delete(ref);
|
|
51
|
+
return "expired";
|
|
52
|
+
}
|
|
53
|
+
if (entry.toolName !== toolName || entry.argsHash !== argsHash) {
|
|
54
|
+
return "args-changed";
|
|
55
|
+
}
|
|
56
|
+
this.pending.delete(ref);
|
|
57
|
+
return "approved";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=confirm-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-gate.js","sourceRoot":"","sources":["../src/confirm-gate.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.
|
|
3
|
+
"version": "0.93.0",
|
|
4
4
|
"description": "MCP server for Cmssy CMS \u2014 enables AI-driven page creation and management",
|
|
5
5
|
"mcpName": "io.github.cmssy-io/cmssy-mcp",
|
|
6
6
|
"homepage": "https://cmssy.com",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"packageManager": "pnpm@11.1.2",
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@cmssy/ai-tools": "0.
|
|
33
|
+
"@cmssy/ai-tools": "0.65.0",
|
|
34
34
|
"@cmssy/types": "0.54.0",
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
36
36
|
"zod": "^4.3.6"
|