@clipform/mcp-server 2.2.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auth-context.js +2 -1
- package/dist/{chunk-HCZI2UJ5.js → chunk-G3PMV62Z.js} +2 -20
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/chunk-PBQ5BQWD.js +60 -0
- package/dist/chunk-PBQ5BQWD.js.map +1 -0
- package/dist/{chunk-XKVU6UN7.js → chunk-QC4JULCW.js} +14 -12
- package/dist/{chunk-XKVU6UN7.js.map → chunk-QC4JULCW.js.map} +1 -1
- package/dist/chunk-V4L5RQWK.js +21 -0
- package/dist/{chunk-HCZI2UJ5.js.map → chunk-V4L5RQWK.js.map} +1 -1
- package/dist/{chunk-T6L5Z4J5.js → chunk-WCPHQ4GU.js} +3 -3
- package/dist/{chunk-EOAGENT6.js → chunk-WNXTF76M.js} +2 -2
- package/dist/{chunk-GZRTOCD2.js → chunk-YZJZ5NPL.js} +33 -51
- package/dist/chunk-YZJZ5NPL.js.map +1 -0
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/prompts.js +5 -3
- package/dist/resources.js +5 -3
- package/dist/server.js +7 -5
- package/dist/telemetry.d.ts +27 -0
- package/dist/telemetry.js +16 -0
- package/dist/telemetry.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-GZRTOCD2.js.map +0 -1
- /package/dist/{chunk-T6L5Z4J5.js.map → chunk-WCPHQ4GU.js.map} +0 -0
- /package/dist/{chunk-EOAGENT6.js.map → chunk-WNXTF76M.js.map} +0 -0
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
67
67
|
| `clipform_list_forms` | List forms in your workspace with optional filtering. |
|
|
68
68
|
| `clipform_get_form` | Retrieve a form's details including all nodes in sequential order. |
|
|
69
69
|
| `clipform_update_form` | Update a form's title, publish status, settings, or tags. |
|
|
70
|
-
| `clipform_delete_form` |
|
|
70
|
+
| `clipform_delete_form` | Move a form and all its nodes to the trash. |
|
|
71
71
|
| `clipform_add_node` | Add a new node to an existing form. |
|
|
72
72
|
| `clipform_update_node` | Update one or more existing nodes' text, type, config, or options. |
|
|
73
73
|
| `clipform_delete_node` | Delete a node from a form. |
|
package/dist/auth-context.js
CHANGED
|
@@ -28,27 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
mod
|
|
29
29
|
));
|
|
30
30
|
|
|
31
|
-
// src/lib/auth-context.ts
|
|
32
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
33
|
-
var storage = new AsyncLocalStorage();
|
|
34
|
-
function runWithMcpAuth(ctx, fn) {
|
|
35
|
-
return storage.run(ctx, fn);
|
|
36
|
-
}
|
|
37
|
-
function getMcpAuth() {
|
|
38
|
-
return storage.getStore();
|
|
39
|
-
}
|
|
40
|
-
function runWithMcpTool(toolName, fn) {
|
|
41
|
-
const parent = storage.getStore();
|
|
42
|
-
if (!parent) return fn();
|
|
43
|
-
return storage.run({ ...parent, tool_name: toolName }, fn);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
31
|
export {
|
|
47
32
|
__commonJS,
|
|
48
33
|
__export,
|
|
49
|
-
__toESM
|
|
50
|
-
runWithMcpAuth,
|
|
51
|
-
getMcpAuth,
|
|
52
|
-
runWithMcpTool
|
|
34
|
+
__toESM
|
|
53
35
|
};
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
36
|
+
//# sourceMappingURL=chunk-G3PMV62Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/lib/telemetry.ts
|
|
2
|
+
function isTelemetryEnabled() {
|
|
3
|
+
return process.env.DO_NOT_TRACK !== "1" && process.env.CLIPFORM_TELEMETRY !== "off";
|
|
4
|
+
}
|
|
5
|
+
var mcpVersion = "unknown";
|
|
6
|
+
function setMcpVersion(version) {
|
|
7
|
+
mcpVersion = version;
|
|
8
|
+
}
|
|
9
|
+
function getApiBaseUrl() {
|
|
10
|
+
return process.env.API_URL || null;
|
|
11
|
+
}
|
|
12
|
+
var customReporter = null;
|
|
13
|
+
function setErrorReporter(reporter) {
|
|
14
|
+
customReporter = reporter;
|
|
15
|
+
}
|
|
16
|
+
function reportError(report) {
|
|
17
|
+
if (customReporter) {
|
|
18
|
+
customReporter(report);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isTelemetryEnabled()) return;
|
|
22
|
+
const base = getApiBaseUrl();
|
|
23
|
+
if (!base) return;
|
|
24
|
+
const payload = {
|
|
25
|
+
...report,
|
|
26
|
+
error_message: report.error_message.slice(0, 500),
|
|
27
|
+
mcp_version: mcpVersion,
|
|
28
|
+
runtime: detectRuntime(),
|
|
29
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
30
|
+
};
|
|
31
|
+
fetch(`${base}/v1/telemetry/errors`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify(payload),
|
|
35
|
+
signal: AbortSignal.timeout(2e3)
|
|
36
|
+
}).catch(() => {
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function isServerFault(status) {
|
|
40
|
+
return status >= 500;
|
|
41
|
+
}
|
|
42
|
+
function isAuthFault(status, code) {
|
|
43
|
+
if (status === 401) return true;
|
|
44
|
+
if (status === 403) return code === "FORBIDDEN";
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function detectRuntime() {
|
|
48
|
+
if (process.env.CLAUDE_CODE) return "claude-code";
|
|
49
|
+
if (process.env.CURSOR_SESSION_ID) return "cursor";
|
|
50
|
+
return "stdio";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
setMcpVersion,
|
|
55
|
+
setErrorReporter,
|
|
56
|
+
reportError,
|
|
57
|
+
isServerFault,
|
|
58
|
+
isAuthFault
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=chunk-PBQ5BQWD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/telemetry.ts"],"sourcesContent":["// Evaluated per-call (not frozen at module load) so a runtime env change is\n// actually observed - also what makes the ordering fix below testable.\nfunction isTelemetryEnabled(): boolean {\n return process.env.DO_NOT_TRACK !== \"1\" && process.env.CLIPFORM_TELEMETRY !== \"off\";\n}\n\nlet mcpVersion = \"unknown\";\n\nexport function setMcpVersion(version: string) {\n mcpVersion = version;\n}\n\nfunction getApiBaseUrl(): string | null {\n return process.env.API_URL || null;\n}\n\nexport interface ErrorReport {\n error_type: string;\n error_message: string;\n tool_name?: string;\n status_code?: number;\n api_path?: string;\n}\n\nexport type ErrorReporter = (report: ErrorReport) => void;\n\n// Overridable delivery mechanism (#2599 follow-up). The default below POSTs\n// to /v1/telemetry/errors - correct for the external stdio MCP client, which\n// runs as its own process talking to a real remote API over HTTP. The\n// in-process host (apps/api, via packages/mcp-client) runs this same package\n// IN the API process itself, so that default would have the API POST\n// itself: mcp_version is only ever set by the stdio bin (src/index.ts), so\n// the endpoint's version-format check 400s every in-process report, and\n// /v1/telemetry/errors' 10/min IP rate limit is shared across every\n// in-process channel on one loopback IP. The in-process host installs its\n// own reporter (apps/api/src/lib/mcp-telemetry-bridge.ts) that captures\n// straight through its own PostHog client instead. Exported so that bridge\n// can install it; pass null to restore the default HTTP reporter.\nlet customReporter: ErrorReporter | null = null;\n\nexport function setErrorReporter(reporter: ErrorReporter | null): void {\n customReporter = reporter;\n}\n\nexport function reportError(report: ErrorReport) {\n // An installed reporter (the in-process host) takes precedence over the\n // opt-out gate below - DO_NOT_TRACK/CLIPFORM_TELEMETRY are an end-user\n // choice for the EXTERNAL stdio client and have no server-side meaning;\n // whatever those vars happen to be set to in the API's own environment\n // must never silently suppress the AI channels' own error capture (#2599\n // minor - the gate used to run before this check).\n if (customReporter) {\n customReporter(report);\n return;\n }\n\n if (!isTelemetryEnabled()) return;\n\n const base = getApiBaseUrl();\n if (!base) return;\n\n const payload = {\n ...report,\n error_message: report.error_message.slice(0, 500),\n mcp_version: mcpVersion,\n runtime: detectRuntime(),\n timestamp: new Date().toISOString(),\n };\n\n fetch(`${base}/v1/telemetry/errors`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(2_000),\n }).catch(() => {});\n}\n\nexport function isServerFault(status: number): boolean {\n return status >= 500;\n}\n\n/**\n * Genuine auth failures - unlike 404/422 these are never ordinary user/agent\n * error, so they're worth reporting even though they're 4xx (#2599). A 401\n * has no other legitimate cause in this API, so it always reports. A 403,\n * though, is NOT always an auth fault here: PLAN_LIMIT and other\n * business-logic denials (feature gating) also respond 403, and those are\n * ordinary user error - exactly the noise this stays silent for. Only the\n * API's own `code` on the JSON error body (from `{ code, error }`, e.g.\n * `create-form.ts`'s ApiError) tells them apart, so a 403 only counts as an\n * auth fault when the code says so; an unrecognized/missing code on a 403\n * stays silent rather than risk misclassifying a new business-logic denial.\n */\nexport function isAuthFault(status: number, code?: string): boolean {\n if (status === 401) return true;\n if (status === 403) return code === \"FORBIDDEN\";\n return false;\n}\n\nfunction detectRuntime(): string {\n if (process.env.CLAUDE_CODE) return \"claude-code\";\n if (process.env.CURSOR_SESSION_ID) return \"cursor\";\n return \"stdio\";\n}\n"],"mappings":";AAEA,SAAS,qBAA8B;AACrC,SAAO,QAAQ,IAAI,iBAAiB,OAAO,QAAQ,IAAI,uBAAuB;AAChF;AAEA,IAAI,aAAa;AAEV,SAAS,cAAc,SAAiB;AAC7C,eAAa;AACf;AAEA,SAAS,gBAA+B;AACtC,SAAO,QAAQ,IAAI,WAAW;AAChC;AAwBA,IAAI,iBAAuC;AAEpC,SAAS,iBAAiB,UAAsC;AACrE,mBAAiB;AACnB;AAEO,SAAS,YAAY,QAAqB;AAO/C,MAAI,gBAAgB;AAClB,mBAAe,MAAM;AACrB;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB,EAAG;AAE3B,QAAM,OAAO,cAAc;AAC3B,MAAI,CAAC,KAAM;AAEX,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,eAAe,OAAO,cAAc,MAAM,GAAG,GAAG;AAAA,IAChD,aAAa;AAAA,IACb,SAAS,cAAc;AAAA,IACvB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AAEA,QAAM,GAAG,IAAI,wBAAwB;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,IAC5B,QAAQ,YAAY,QAAQ,GAAK;AAAA,EACnC,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAEO,SAAS,cAAc,QAAyB;AACrD,SAAO,UAAU;AACnB;AAcO,SAAS,YAAY,QAAgB,MAAwB;AAClE,MAAI,WAAW,IAAK,QAAO;AAC3B,MAAI,WAAW,IAAK,QAAO,SAAS;AACpC,SAAO;AACT;AAEA,SAAS,gBAAwB;AAC/B,MAAI,QAAQ,IAAI,YAAa,QAAO;AACpC,MAAI,QAAQ,IAAI,kBAAmB,QAAO;AAC1C,SAAO;AACT;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getWorkflowText,
|
|
7
7
|
objectType,
|
|
8
8
|
registerPrompts
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-WCPHQ4GU.js";
|
|
10
10
|
import {
|
|
11
11
|
GUIDE_TYPES,
|
|
12
12
|
QUIZ_VARIANTS,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getGuideUri,
|
|
15
15
|
guideFallbackText,
|
|
16
16
|
registerResources
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WNXTF76M.js";
|
|
18
18
|
import {
|
|
19
19
|
ACTIVE_NODE_TYPES,
|
|
20
20
|
BUSINESS,
|
|
@@ -33,14 +33,16 @@ import {
|
|
|
33
33
|
resolveFormType,
|
|
34
34
|
structuredResult,
|
|
35
35
|
textResult
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-YZJZ5NPL.js";
|
|
37
37
|
import {
|
|
38
|
-
__commonJS,
|
|
39
|
-
__export,
|
|
40
|
-
__toESM,
|
|
41
38
|
getMcpAuth,
|
|
42
39
|
runWithMcpTool
|
|
43
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-V4L5RQWK.js";
|
|
41
|
+
import {
|
|
42
|
+
__commonJS,
|
|
43
|
+
__export,
|
|
44
|
+
__toESM
|
|
45
|
+
} from "./chunk-G3PMV62Z.js";
|
|
44
46
|
|
|
45
47
|
// ../../node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
46
48
|
var require_code = __commonJS({
|
|
@@ -17626,7 +17628,7 @@ function registerDeleteFormTool(server) {
|
|
|
17626
17628
|
"clipform_delete_form",
|
|
17627
17629
|
{
|
|
17628
17630
|
title: "Delete Clipform",
|
|
17629
|
-
description: `
|
|
17631
|
+
description: `Move a form and all its nodes to the trash. It stops accepting responses immediately and can be restored later. Requires user confirmation before it runs.`,
|
|
17630
17632
|
inputSchema: {
|
|
17631
17633
|
form_id: external_exports.string().uuid().describe("The form UUID to delete (returned by clipform_create_form, not the short share_id from the URL)"),
|
|
17632
17634
|
confirm: external_exports.boolean().optional().describe(CONFIRM_FIELD_DESCRIPTION)
|
|
@@ -17641,8 +17643,8 @@ function registerDeleteFormTool(server) {
|
|
|
17641
17643
|
async ({ form_id, confirm }) => {
|
|
17642
17644
|
const decision = await confirmDestructive(server, {
|
|
17643
17645
|
alreadyConfirmed: confirm,
|
|
17644
|
-
message: `
|
|
17645
|
-
relay: `Confirmation required:
|
|
17646
|
+
message: `Move form ${form_id} to the trash? It stops accepting responses immediately and can be restored later.`,
|
|
17647
|
+
relay: `Confirmation required: moving form ${form_id} to the trash stops it accepting responses immediately. It can be restored later. Ask the user to confirm, then call clipform_delete_form again with confirm: true.`
|
|
17646
17648
|
});
|
|
17647
17649
|
if (!decision.proceed) {
|
|
17648
17650
|
return textResult(decision.message);
|
|
@@ -17653,7 +17655,7 @@ function registerDeleteFormTool(server) {
|
|
|
17653
17655
|
if (!result.ok) {
|
|
17654
17656
|
return errorResult(result.error);
|
|
17655
17657
|
}
|
|
17656
|
-
return textResult(`Form ${form_id} has been
|
|
17658
|
+
return textResult(`Form ${form_id} has been moved to the trash.`);
|
|
17657
17659
|
}
|
|
17658
17660
|
);
|
|
17659
17661
|
}
|
|
@@ -19977,4 +19979,4 @@ export {
|
|
|
19977
19979
|
RENDER_TIMING,
|
|
19978
19980
|
createServer
|
|
19979
19981
|
};
|
|
19980
|
-
//# sourceMappingURL=chunk-
|
|
19982
|
+
//# sourceMappingURL=chunk-QC4JULCW.js.map
|