@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 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` | Permanently delete a form and all its nodes. |
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. |
@@ -2,7 +2,8 @@ import {
2
2
  getMcpAuth,
3
3
  runWithMcpAuth,
4
4
  runWithMcpTool
5
- } from "./chunk-HCZI2UJ5.js";
5
+ } from "./chunk-V4L5RQWK.js";
6
+ import "./chunk-G3PMV62Z.js";
6
7
  export {
7
8
  getMcpAuth,
8
9
  runWithMcpAuth,
@@ -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-HCZI2UJ5.js.map
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-T6L5Z4J5.js";
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-EOAGENT6.js";
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-GZRTOCD2.js";
36
+ } from "./chunk-YZJZ5NPL.js";
37
37
  import {
38
- __commonJS,
39
- __export,
40
- __toESM,
41
38
  getMcpAuth,
42
39
  runWithMcpTool
43
- } from "./chunk-HCZI2UJ5.js";
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: `Permanently delete a form and all its nodes. This cannot be undone. Requires user confirmation before it runs.`,
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: `Permanently delete form ${form_id} and all of its nodes? This cannot be undone.`,
17645
- relay: `Confirmation required: deleting form ${form_id} permanently removes it and all its nodes, and cannot be undone. Ask the user to confirm, then call clipform_delete_form again with confirm: true.`
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 permanently deleted.`);
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-XKVU6UN7.js.map
19982
+ //# sourceMappingURL=chunk-QC4JULCW.js.map