@clipform/mcp-server 3.2.1 → 3.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.
@@ -5,7 +5,7 @@ import {
5
5
  FULL_CAPS,
6
6
  callApi,
7
7
  getSessionContext
8
- } from "./chunk-VZKMOMFJ.js";
8
+ } from "./chunk-SEZ37YSH.js";
9
9
 
10
10
  // src/lib/guides.ts
11
11
  var guidesPromise = null;
@@ -143,4 +143,4 @@ export {
143
143
  getGuideUri,
144
144
  registerResources
145
145
  };
146
- //# sourceMappingURL=chunk-236IGTEY.js.map
146
+ //# sourceMappingURL=chunk-ELK26KWM.js.map
@@ -795,6 +795,7 @@ var NODE_TYPES = {
795
795
  // Never appears in a completed submission's answers (system node, no
796
796
  // output_schema) - false is a no-op default, set for guard-test coverage.
797
797
  notify_inline: false,
798
+ owner_scoped_config_keys: [],
798
799
  default_config: null,
799
800
  config_schema: null,
800
801
  response_schema: null,
@@ -821,6 +822,7 @@ var NODE_TYPES = {
821
822
  show_in_results: true,
822
823
  // Short selected-option label - safe to render inline in a notification (#4154).
823
824
  notify_inline: true,
825
+ owner_scoped_config_keys: [],
824
826
  default_config: {
825
827
  selection_mode: "single",
826
828
  choice: { enable_branching: false, record_scores: false },
@@ -932,6 +934,7 @@ var NODE_TYPES = {
932
934
  // still swaps a recorded audio/video answer for a typed placeholder
933
935
  // based on the answer's own media type, not this flag.
934
936
  notify_inline: true,
937
+ owner_scoped_config_keys: [],
935
938
  default_config: {
936
939
  formats: [
937
940
  { order: 0, format: "text" },
@@ -1071,6 +1074,7 @@ var NODE_TYPES = {
1071
1074
  show_in_results: true,
1072
1075
  // A bare numeric value - short enough to render inline (#4154).
1073
1076
  notify_inline: true,
1077
+ owner_scoped_config_keys: [],
1074
1078
  default_config: null,
1075
1079
  config_schema: {
1076
1080
  type: "object",
@@ -1108,6 +1112,13 @@ var NODE_TYPES = {
1108
1112
  // Structured provider data (calendly/google_meet), not a flat value -
1109
1113
  // a notification renders a typed placeholder instead (#4154).
1110
1114
  notify_inline: false,
1115
+ // Object granularity, not a dotted path (#4618): every property under
1116
+ // these provider objects (scheduling_url, event_type_uri, calendar_id) is
1117
+ // the source workspace's own calendar, so save_form strips the whole
1118
+ // object on cross-workspace copy. google_meet is included even though it
1119
+ // is absent from the publish gate below (pre-existing drift, not widened
1120
+ // here) because calendar_id is owner-scoped regardless.
1121
+ owner_scoped_config_keys: ["calendly", "calcom", "google_meet"],
1111
1122
  default_config: null,
1112
1123
  config_schema: {
1113
1124
  type: "object",
@@ -1189,6 +1200,7 @@ var NODE_TYPES = {
1189
1200
  // Key contact fields (first name, email) are the whole point of a
1190
1201
  // notification for this node type - always inline (#4154).
1191
1202
  notify_inline: true,
1203
+ owner_scoped_config_keys: [],
1192
1204
  default_config: {
1193
1205
  fields: [
1194
1206
  { id: "first_name", type: "first_name", label: "First Name", enabled: true, required: true },
@@ -1365,6 +1377,7 @@ var NODE_TYPES = {
1365
1377
  show_in_results: true,
1366
1378
  // Files, not a flat value - a notification renders a typed placeholder (#4154).
1367
1379
  notify_inline: false,
1380
+ owner_scoped_config_keys: [],
1368
1381
  default_config: null,
1369
1382
  config_schema: {
1370
1383
  type: "object",
@@ -1456,6 +1469,7 @@ var NODE_TYPES = {
1456
1469
  show_in_results: true,
1457
1470
  // An image, not a flat value - a notification renders a typed placeholder (#4154).
1458
1471
  notify_inline: false,
1472
+ owner_scoped_config_keys: [],
1459
1473
  default_config: {
1460
1474
  paper_color: "#FAF9F6",
1461
1475
  stroke_colors: ["#1F2937", "#EF4444", "#3B82F6", "#22C55E", "#FACC15"],
@@ -1629,6 +1643,7 @@ var NODE_TYPES = {
1629
1643
  // A captured photo/video, not a flat value - a notification renders a
1630
1644
  // typed placeholder (#4154).
1631
1645
  notify_inline: false,
1646
+ owner_scoped_config_keys: [],
1632
1647
  default_config: null,
1633
1648
  config_schema: {
1634
1649
  type: "object",
@@ -1740,6 +1755,7 @@ var NODE_TYPES = {
1740
1755
  // notification, same as the other control nodes (redirect, link_list,
1741
1756
  // end_screen). Required by the #4154 notify_inline invariant.
1742
1757
  notify_inline: false,
1758
+ owner_scoped_config_keys: [],
1743
1759
  default_config: {
1744
1760
  options: [
1745
1761
  { content: "Branch 1" },
@@ -1766,13 +1782,14 @@ var NODE_TYPES = {
1766
1782
  supports_media: false,
1767
1783
  is_system: false,
1768
1784
  show_in_results: true,
1769
- // Config keys that reference a workspace-scoped connected account (Stripe/etc
1770
- // via workspace_integrations). The SoT for save_form to strip on cross-workspace
1771
- // copy (#2064 part 2 - migration, not yet wired). Standing convention for any
1772
- // future OAuth/connected-account node (booking, shopify), not a payment special
1773
- // case - the publish gate's own showcase waiver (graph-validation.js) still
1774
- // names workspace_integration_id directly since it's the only per-type check today.
1775
- connection_config_keys: ["workspace_integration_id"],
1785
+ // Config keys that are owner-scoped to the authoring workspace - a connected
1786
+ // account (Stripe/etc via workspace_integrations), the owner's own uploaded
1787
+ // files, or a calendar link - and so must NOT survive a cross-workspace copy
1788
+ // (#4619/#4617/#4618/#4620 generalised this from the payment-only
1789
+ // connection_config_keys). The SoT for save_form's strip. The publish gate's
1790
+ // own showcase waiver (graph-validation.js) still names workspace_integration_id
1791
+ // directly since it's the only per-type check today.
1792
+ owner_scoped_config_keys: ["workspace_integration_id"],
1776
1793
  // A payment confirmation line is the whole point of a notification for
1777
1794
  // this node type - always inline (#4154).
1778
1795
  notify_inline: true,
@@ -1922,6 +1939,7 @@ var NODE_TYPES = {
1922
1939
  show_in_results: true,
1923
1940
  // Short selected-option label - safe to render inline (#4154).
1924
1941
  notify_inline: true,
1942
+ owner_scoped_config_keys: [],
1925
1943
  default_config: {
1926
1944
  choice: { enable_branching: false },
1927
1945
  options: [
@@ -1986,6 +2004,7 @@ var NODE_TYPES = {
1986
2004
  show_in_results: false,
1987
2005
  // Short selected-option label - safe to render inline (#4154).
1988
2006
  notify_inline: true,
2007
+ owner_scoped_config_keys: [],
1989
2008
  default_config: { options: [{ content: "Continue" }] },
1990
2009
  config_schema: {
1991
2010
  type: "object",
@@ -2027,6 +2046,7 @@ var NODE_TYPES = {
2027
2046
  // Terminal node - never appears in a completed submission's answers
2028
2047
  // (filtered by NON_COUNTABLE_FILTER); false is a no-op default.
2029
2048
  notify_inline: false,
2049
+ owner_scoped_config_keys: [],
2030
2050
  default_config: { url: "", auto_redirect: true },
2031
2051
  config_schema: {
2032
2052
  type: "object",
@@ -2060,6 +2080,7 @@ var NODE_TYPES = {
2060
2080
  // Terminal node - never appears in a completed submission's answers
2061
2081
  // (filtered by NON_COUNTABLE_FILTER); false is a no-op default.
2062
2082
  notify_inline: false,
2083
+ owner_scoped_config_keys: [],
2063
2084
  default_config: { links: [{ id: "default", url: "", title: "", description: "", order: 0 }], auto_redirect: false },
2064
2085
  config_schema: {
2065
2086
  type: "object",
@@ -2107,6 +2128,10 @@ var NODE_TYPES = {
2107
2128
  show_in_results: true,
2108
2129
  // Files, not a flat value - a notification renders a typed placeholder (#4154).
2109
2130
  notify_inline: false,
2131
+ // The owner's own uploaded files (#4617) - stripped on cross-workspace
2132
+ // copy so a forked node can't keep serving the source workspace's files;
2133
+ // the publish gate's "No files uploaded" check then forces a fresh upload.
2134
+ owner_scoped_config_keys: ["files"],
2110
2135
  default_config: null,
2111
2136
  config_schema: {
2112
2137
  type: "object",
@@ -2189,6 +2214,7 @@ var NODE_TYPES = {
2189
2214
  show_in_results: false,
2190
2215
  // No response_schema - never carries a flat answer value; false is a no-op default.
2191
2216
  notify_inline: false,
2217
+ owner_scoped_config_keys: [],
2192
2218
  default_config: { provider: "shopify", cta_mode: "checkout", source_mode: "manual" },
2193
2219
  config_schema: {
2194
2220
  type: "object",
@@ -2260,6 +2286,7 @@ var NODE_TYPES = {
2260
2286
  // Terminal node - never appears in a completed submission's answers
2261
2287
  // (filtered by NON_COUNTABLE_FILTER); false is a no-op default.
2262
2288
  notify_inline: false,
2289
+ owner_scoped_config_keys: [],
2263
2290
  default_config: {
2264
2291
  title: "Thank you!",
2265
2292
  message: "Your response has been submitted."
@@ -2322,8 +2349,8 @@ for (const [type, def] of Object.entries(NODE_TYPES)) {
2322
2349
  var NODE_TYPES_LIST = Object.entries(NODE_TYPES).map(([type, def]) => ({ type, ...def })).sort((a, b) => a.sort_order - b.sort_order);
2323
2350
  var ACTIVE_NODE_TYPES = Object.entries(NODE_TYPES).filter(([, def]) => def.is_active && !def.is_system).map(([type]) => type);
2324
2351
  var NODE_TYPE_KEYS = Object.keys(NODE_TYPES);
2325
- var CONNECTION_CONFIG_KEYS = Object.fromEntries(
2326
- Object.entries(NODE_TYPES).filter(([, def]) => Array.isArray(def.connection_config_keys) && def.connection_config_keys.length > 0).map(([type, def]) => [type, def.connection_config_keys])
2352
+ var OWNER_SCOPED_CONFIG_KEYS = Object.fromEntries(
2353
+ Object.entries(NODE_TYPES).filter(([, def]) => Array.isArray(def.owner_scoped_config_keys) && def.owner_scoped_config_keys.length > 0).map(([type, def]) => [type, def.owner_scoped_config_keys])
2327
2354
  );
2328
2355
  var RESPONSE_SCHEMAS = Object.fromEntries(
2329
2356
  Object.entries(NODE_TYPES).map(([k, v]) => [k, v.response_schema])
@@ -3029,6 +3056,19 @@ var MCP_TOOL_TOOLSETS = {
3029
3056
  clipform_list_assets: "media",
3030
3057
  clipform_list_video_templates: "media"
3031
3058
  };
3059
+ var MCP_TOOL_SECURITY_SCHEMES = Object.freeze([
3060
+ Object.freeze({ type: "noauth" }),
3061
+ Object.freeze({ type: "oauth2", scopes: ["mcp"] })
3062
+ ]);
3063
+ var MCP_TOOL_SECURITY = Object.freeze(
3064
+ Object.fromEntries(
3065
+ Object.keys(MCP_TOOL_TOOLSETS).map((name) => [name, MCP_TOOL_SECURITY_SCHEMES])
3066
+ )
3067
+ );
3068
+ var MCP_ANON_PUBLISH_GATE = Object.freeze({
3069
+ tool: "clipform_update_form",
3070
+ argument: "is_live"
3071
+ });
3032
3072
 
3033
3073
  // src/lib/caps.ts
3034
3074
  var FULL_CAPS = Object.freeze({ media: true, research: true });
@@ -3136,10 +3176,14 @@ async function callApi(path, options = {}) {
3136
3176
  api_path: `${prefix}${path}`
3137
3177
  });
3138
3178
  }
3179
+ const details = data.details;
3180
+ const reason = details && typeof details.reason === "string" ? details.reason : void 0;
3139
3181
  return {
3140
3182
  ok: false,
3141
3183
  status: response.status,
3142
- error: errorMsg
3184
+ error: errorMsg,
3185
+ code: errorCode,
3186
+ reason
3143
3187
  };
3144
3188
  }
3145
3189
  return { ok: true, data };
@@ -3158,12 +3202,28 @@ function recoveryHint(status, path) {
3158
3202
  }
3159
3203
  return void 0;
3160
3204
  }
3161
- function errorResult(message) {
3205
+ function errorResult(message, meta) {
3162
3206
  return {
3163
3207
  content: [{ type: "text", text: message }],
3164
- isError: true
3208
+ isError: true,
3209
+ ...meta ? { _meta: meta } : {}
3165
3210
  };
3166
3211
  }
3212
+ var PROTECTED_RESOURCE_METADATA_URL = `${BUSINESS.urls.mcp}/.well-known/oauth-protected-resource`;
3213
+ function escapeChallengeValue(value) {
3214
+ return value.replace(/[\r\n]/g, "").replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3215
+ }
3216
+ function isAnonymousAccountRequired(result) {
3217
+ return result.status === 403 && result.code === "FORBIDDEN" && result.reason === "anonymous_not_allowed";
3218
+ }
3219
+ function authChallengeMeta(errorCode, description) {
3220
+ const challenge = [
3221
+ `Bearer error="${escapeChallengeValue(errorCode)}"`,
3222
+ `error_description="${escapeChallengeValue(description)}"`,
3223
+ `resource_metadata="${PROTECTED_RESOURCE_METADATA_URL}"`
3224
+ ].join(", ");
3225
+ return { "mcp/www_authenticate": [challenge] };
3226
+ }
3167
3227
  function textResult(text) {
3168
3228
  return {
3169
3229
  content: [{ type: "text", text }]
@@ -3245,13 +3305,17 @@ export {
3245
3305
  exposedCompositionIds,
3246
3306
  MCP_TOOL_TIERS,
3247
3307
  MCP_TOOL_TOOLSETS,
3308
+ MCP_TOOL_SECURITY,
3309
+ MCP_ANON_PUBLISH_GATE,
3248
3310
  FULL_CAPS,
3249
3311
  capsFromToolsets,
3250
3312
  callApi,
3251
3313
  errorResult,
3314
+ isAnonymousAccountRequired,
3315
+ authChallengeMeta,
3252
3316
  textResult,
3253
3317
  structuredResult,
3254
3318
  getSessionContextWithAuth,
3255
3319
  getSessionContext
3256
3320
  };
3257
- //# sourceMappingURL=chunk-VZKMOMFJ.js.map
3321
+ //# sourceMappingURL=chunk-SEZ37YSH.js.map