@clipform/mcp-server 3.0.0 → 3.2.1
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 +2 -2
- package/README.template.md +1 -1
- package/dist/auth-context.d.ts +13 -0
- package/dist/auth-context.js +1 -1
- package/dist/{chunk-EXV5M7YV.js → chunk-236IGTEY.js} +2 -2
- package/dist/{chunk-HZMMOSEM.js → chunk-A5CFGL27.js} +1 -1
- package/dist/chunk-A5CFGL27.js.map +1 -0
- package/dist/{chunk-KCF7ZVDI.js → chunk-EQ6WNIA5.js} +2 -2
- package/dist/{chunk-QBPE32AV.js → chunk-J7727374.js} +318 -80
- package/dist/chunk-J7727374.js.map +1 -0
- package/dist/{chunk-KNOCYZHG.js → chunk-VZKMOMFJ.js} +29 -10
- package/dist/chunk-VZKMOMFJ.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/prompts.js +3 -3
- package/dist/resources.js +3 -3
- package/dist/server.js +5 -5
- package/package.json +4 -3
- package/dist/chunk-HZMMOSEM.js.map +0 -1
- package/dist/chunk-KNOCYZHG.js.map +0 -1
- package/dist/chunk-QBPE32AV.js.map +0 -1
- /package/dist/{chunk-EXV5M7YV.js.map → chunk-236IGTEY.js.map} +0 -0
- /package/dist/{chunk-KCF7ZVDI.js.map → chunk-EQ6WNIA5.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getWorkflowText,
|
|
7
7
|
objectType,
|
|
8
8
|
registerPrompts
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EQ6WNIA5.js";
|
|
10
10
|
import {
|
|
11
11
|
GUIDE_TYPES,
|
|
12
12
|
QUIZ_VARIANTS,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getGuideUri,
|
|
16
16
|
guideFallbackText,
|
|
17
17
|
registerResources
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-236IGTEY.js";
|
|
19
19
|
import {
|
|
20
20
|
ACTIVE_NODE_TYPES,
|
|
21
21
|
CONTACT_FIELDS,
|
|
@@ -35,11 +35,12 @@ import {
|
|
|
35
35
|
resolveFormType,
|
|
36
36
|
structuredResult,
|
|
37
37
|
textResult
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-VZKMOMFJ.js";
|
|
39
39
|
import {
|
|
40
40
|
getMcpAuth,
|
|
41
|
+
runWithMcpAuth,
|
|
41
42
|
runWithMcpTool
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-A5CFGL27.js";
|
|
43
44
|
import {
|
|
44
45
|
__commonJS,
|
|
45
46
|
__export,
|
|
@@ -114,7 +115,7 @@ var require_code = __commonJS({
|
|
|
114
115
|
}
|
|
115
116
|
exports._ = _;
|
|
116
117
|
var plus = new _Code("+");
|
|
117
|
-
function
|
|
118
|
+
function str2(strs, ...args) {
|
|
118
119
|
const expr = [safeStringify(strs[0])];
|
|
119
120
|
let i = 0;
|
|
120
121
|
while (i < args.length) {
|
|
@@ -125,7 +126,7 @@ var require_code = __commonJS({
|
|
|
125
126
|
optimize(expr);
|
|
126
127
|
return new _Code(expr);
|
|
127
128
|
}
|
|
128
|
-
exports.str =
|
|
129
|
+
exports.str = str2;
|
|
129
130
|
function addCodeArg(code, arg) {
|
|
130
131
|
if (arg instanceof _Code)
|
|
131
132
|
code.push(...arg._items);
|
|
@@ -168,7 +169,7 @@ var require_code = __commonJS({
|
|
|
168
169
|
return;
|
|
169
170
|
}
|
|
170
171
|
function strConcat(c1, c2) {
|
|
171
|
-
return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 :
|
|
172
|
+
return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str2`${c1}${c2}`;
|
|
172
173
|
}
|
|
173
174
|
exports.strConcat = strConcat;
|
|
174
175
|
function interpolate(x) {
|
|
@@ -1130,22 +1131,22 @@ var require_util = __commonJS({
|
|
|
1130
1131
|
return (0, codegen_1._)`${topSchemaRef}${schemaPath}${(0, codegen_1.getProperty)(keyword)}`;
|
|
1131
1132
|
}
|
|
1132
1133
|
exports.schemaRefOrVal = schemaRefOrVal;
|
|
1133
|
-
function unescapeFragment(
|
|
1134
|
-
return unescapeJsonPointer(decodeURIComponent(
|
|
1134
|
+
function unescapeFragment(str2) {
|
|
1135
|
+
return unescapeJsonPointer(decodeURIComponent(str2));
|
|
1135
1136
|
}
|
|
1136
1137
|
exports.unescapeFragment = unescapeFragment;
|
|
1137
|
-
function escapeFragment(
|
|
1138
|
-
return encodeURIComponent(escapeJsonPointer(
|
|
1138
|
+
function escapeFragment(str2) {
|
|
1139
|
+
return encodeURIComponent(escapeJsonPointer(str2));
|
|
1139
1140
|
}
|
|
1140
1141
|
exports.escapeFragment = escapeFragment;
|
|
1141
|
-
function escapeJsonPointer(
|
|
1142
|
-
if (typeof
|
|
1143
|
-
return `${
|
|
1144
|
-
return
|
|
1142
|
+
function escapeJsonPointer(str2) {
|
|
1143
|
+
if (typeof str2 == "number")
|
|
1144
|
+
return `${str2}`;
|
|
1145
|
+
return str2.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1145
1146
|
}
|
|
1146
1147
|
exports.escapeJsonPointer = escapeJsonPointer;
|
|
1147
|
-
function unescapeJsonPointer(
|
|
1148
|
-
return
|
|
1148
|
+
function unescapeJsonPointer(str2) {
|
|
1149
|
+
return str2.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
1149
1150
|
}
|
|
1150
1151
|
exports.unescapeJsonPointer = unescapeJsonPointer;
|
|
1151
1152
|
function eachItem(xs, f) {
|
|
@@ -2170,8 +2171,8 @@ var require_json_schema_traverse = __commonJS({
|
|
|
2170
2171
|
post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
|
|
2171
2172
|
}
|
|
2172
2173
|
}
|
|
2173
|
-
function escapeJsonPtr(
|
|
2174
|
-
return
|
|
2174
|
+
function escapeJsonPtr(str2) {
|
|
2175
|
+
return str2.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2175
2176
|
}
|
|
2176
2177
|
}
|
|
2177
2178
|
});
|
|
@@ -3235,10 +3236,10 @@ var require_utils = __commonJS({
|
|
|
3235
3236
|
return { host, isIPV6: false };
|
|
3236
3237
|
}
|
|
3237
3238
|
}
|
|
3238
|
-
function findToken(
|
|
3239
|
+
function findToken(str2, token) {
|
|
3239
3240
|
let ind = 0;
|
|
3240
|
-
for (let i = 0; i <
|
|
3241
|
-
if (
|
|
3241
|
+
for (let i = 0; i < str2.length; i++) {
|
|
3242
|
+
if (str2[i] === token) ind++;
|
|
3242
3243
|
}
|
|
3243
3244
|
return ind;
|
|
3244
3245
|
}
|
|
@@ -3975,7 +3976,7 @@ var require_core = __commonJS({
|
|
|
3975
3976
|
var util_1 = require_util();
|
|
3976
3977
|
var $dataRefSchema = require_data();
|
|
3977
3978
|
var uri_1 = require_uri();
|
|
3978
|
-
var defaultRegExp = (
|
|
3979
|
+
var defaultRegExp = (str2, flags) => new RegExp(str2, flags);
|
|
3979
3980
|
defaultRegExp.code = "new RegExp";
|
|
3980
3981
|
var META_IGNORE_OPTIONS = ["removeAdditional", "useDefaults", "coerceTypes"];
|
|
3981
3982
|
var EXT_SCOPE_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -4770,16 +4771,16 @@ var require_ucs2length = __commonJS({
|
|
|
4770
4771
|
"../../node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/runtime/ucs2length.js"(exports) {
|
|
4771
4772
|
"use strict";
|
|
4772
4773
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4773
|
-
function ucs2length(
|
|
4774
|
-
const len =
|
|
4774
|
+
function ucs2length(str2) {
|
|
4775
|
+
const len = str2.length;
|
|
4775
4776
|
let length = 0;
|
|
4776
4777
|
let pos = 0;
|
|
4777
4778
|
let value;
|
|
4778
4779
|
while (pos < len) {
|
|
4779
4780
|
length++;
|
|
4780
|
-
value =
|
|
4781
|
+
value = str2.charCodeAt(pos++);
|
|
4781
4782
|
if (value >= 55296 && value <= 56319 && pos < len) {
|
|
4782
|
-
value =
|
|
4783
|
+
value = str2.charCodeAt(pos);
|
|
4783
4784
|
if ((value & 64512) === 56320)
|
|
4784
4785
|
pos++;
|
|
4785
4786
|
}
|
|
@@ -6662,8 +6663,8 @@ var require_formats = __commonJS({
|
|
|
6662
6663
|
}
|
|
6663
6664
|
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
6664
6665
|
var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
6665
|
-
function date3(
|
|
6666
|
-
const matches = DATE.exec(
|
|
6666
|
+
function date3(str2) {
|
|
6667
|
+
const matches = DATE.exec(str2);
|
|
6667
6668
|
if (!matches)
|
|
6668
6669
|
return false;
|
|
6669
6670
|
const year = +matches[1];
|
|
@@ -6682,8 +6683,8 @@ var require_formats = __commonJS({
|
|
|
6682
6683
|
}
|
|
6683
6684
|
var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
|
|
6684
6685
|
function getTime(strictTimeZone) {
|
|
6685
|
-
return function time3(
|
|
6686
|
-
const matches = TIME.exec(
|
|
6686
|
+
return function time3(str2) {
|
|
6687
|
+
const matches = TIME.exec(str2);
|
|
6687
6688
|
if (!matches)
|
|
6688
6689
|
return false;
|
|
6689
6690
|
const hr = +matches[1];
|
|
@@ -6729,8 +6730,8 @@ var require_formats = __commonJS({
|
|
|
6729
6730
|
var DATE_TIME_SEPARATOR = /t|\s/i;
|
|
6730
6731
|
function getDateTime(strictTimeZone) {
|
|
6731
6732
|
const time3 = getTime(strictTimeZone);
|
|
6732
|
-
return function date_time(
|
|
6733
|
-
const dateTime =
|
|
6733
|
+
return function date_time(str2) {
|
|
6734
|
+
const dateTime = str2.split(DATE_TIME_SEPARATOR);
|
|
6734
6735
|
return dateTime.length === 2 && date3(dateTime[0]) && time3(dateTime[1]);
|
|
6735
6736
|
};
|
|
6736
6737
|
}
|
|
@@ -6755,13 +6756,13 @@ var require_formats = __commonJS({
|
|
|
6755
6756
|
}
|
|
6756
6757
|
var NOT_URI_FRAGMENT = /\/|:/;
|
|
6757
6758
|
var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
|
6758
|
-
function uri(
|
|
6759
|
-
return NOT_URI_FRAGMENT.test(
|
|
6759
|
+
function uri(str2) {
|
|
6760
|
+
return NOT_URI_FRAGMENT.test(str2) && URI.test(str2);
|
|
6760
6761
|
}
|
|
6761
6762
|
var BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
|
|
6762
|
-
function byte(
|
|
6763
|
+
function byte(str2) {
|
|
6763
6764
|
BYTE.lastIndex = 0;
|
|
6764
|
-
return BYTE.test(
|
|
6765
|
+
return BYTE.test(str2);
|
|
6765
6766
|
}
|
|
6766
6767
|
var MIN_INT32 = -(2 ** 31);
|
|
6767
6768
|
var MAX_INT32 = 2 ** 31 - 1;
|
|
@@ -6775,11 +6776,11 @@ var require_formats = __commonJS({
|
|
|
6775
6776
|
return true;
|
|
6776
6777
|
}
|
|
6777
6778
|
var Z_ANCHOR = /[^\\]\\Z/;
|
|
6778
|
-
function regex(
|
|
6779
|
-
if (Z_ANCHOR.test(
|
|
6779
|
+
function regex(str2) {
|
|
6780
|
+
if (Z_ANCHOR.test(str2))
|
|
6780
6781
|
return false;
|
|
6781
6782
|
try {
|
|
6782
|
-
new RegExp(
|
|
6783
|
+
new RegExp(str2);
|
|
6783
6784
|
return true;
|
|
6784
6785
|
} catch (e) {
|
|
6785
6786
|
return false;
|
|
@@ -7115,14 +7116,14 @@ function promiseAllObject(promisesObj) {
|
|
|
7115
7116
|
}
|
|
7116
7117
|
function randomString(length = 10) {
|
|
7117
7118
|
const chars = "abcdefghijklmnopqrstuvwxyz";
|
|
7118
|
-
let
|
|
7119
|
+
let str2 = "";
|
|
7119
7120
|
for (let i = 0; i < length; i++) {
|
|
7120
|
-
|
|
7121
|
+
str2 += chars[Math.floor(Math.random() * chars.length)];
|
|
7121
7122
|
}
|
|
7122
|
-
return
|
|
7123
|
+
return str2;
|
|
7123
7124
|
}
|
|
7124
|
-
function esc(
|
|
7125
|
-
return JSON.stringify(
|
|
7125
|
+
function esc(str2) {
|
|
7126
|
+
return JSON.stringify(str2);
|
|
7126
7127
|
}
|
|
7127
7128
|
var captureStackTrace = Error.captureStackTrace ? Error.captureStackTrace : (..._args) => {
|
|
7128
7129
|
};
|
|
@@ -7210,8 +7211,8 @@ var getParsedType = (data) => {
|
|
|
7210
7211
|
};
|
|
7211
7212
|
var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
|
|
7212
7213
|
var primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
|
|
7213
|
-
function escapeRegex(
|
|
7214
|
-
return
|
|
7214
|
+
function escapeRegex(str2) {
|
|
7215
|
+
return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7215
7216
|
}
|
|
7216
7217
|
function clone(inst, def, params) {
|
|
7217
7218
|
const cl = new inst._zod.constr(def ?? inst._zod.def);
|
|
@@ -17187,6 +17188,48 @@ function applyNodeDefaults(node) {
|
|
|
17187
17188
|
}
|
|
17188
17189
|
}
|
|
17189
17190
|
|
|
17191
|
+
// src/lib/workspace-target.ts
|
|
17192
|
+
var PINNED_WORKSPACE_ERROR = "This connection is pinned to one workspace, so a workspace argument can't be used. Omit it to act in the connection's workspace.";
|
|
17193
|
+
async function runWithWorkspaceTarget(args, run) {
|
|
17194
|
+
const input = args && typeof args === "object" ? args : {};
|
|
17195
|
+
const workspaceId = typeof input.workspace_id === "string" && input.workspace_id ? input.workspace_id : void 0;
|
|
17196
|
+
const formId = typeof input.form_id === "string" && input.form_id ? input.form_id : void 0;
|
|
17197
|
+
if (!workspaceId && !formId) return run();
|
|
17198
|
+
const ctx = getMcpAuth();
|
|
17199
|
+
const resolve = ctx?.resolveWorkspace;
|
|
17200
|
+
if (!resolve) {
|
|
17201
|
+
if (workspaceId) return errorResult(PINNED_WORKSPACE_ERROR);
|
|
17202
|
+
return run();
|
|
17203
|
+
}
|
|
17204
|
+
if (workspaceId && !formId && workspaceId === ctx.default_workspace_id) {
|
|
17205
|
+
return run();
|
|
17206
|
+
}
|
|
17207
|
+
let resolved;
|
|
17208
|
+
try {
|
|
17209
|
+
resolved = await resolve({
|
|
17210
|
+
...workspaceId ? { workspace_id: workspaceId } : {},
|
|
17211
|
+
...formId ? { form_id: formId } : {}
|
|
17212
|
+
});
|
|
17213
|
+
} catch (err) {
|
|
17214
|
+
return errorResult(err instanceof Error ? err.message : "Could not resolve that workspace.");
|
|
17215
|
+
}
|
|
17216
|
+
if (!resolved) return run();
|
|
17217
|
+
return runWithMcpAuth(
|
|
17218
|
+
{
|
|
17219
|
+
...ctx,
|
|
17220
|
+
workspace_id: resolved.workspace_id,
|
|
17221
|
+
api_key: resolved.api_key
|
|
17222
|
+
},
|
|
17223
|
+
run
|
|
17224
|
+
);
|
|
17225
|
+
}
|
|
17226
|
+
var workspaceIdInput = external_exports.string().uuid().optional().describe(
|
|
17227
|
+
"Workspace to act in (id from clipform_whoami workspaces). Omit to use the connection's default workspace."
|
|
17228
|
+
);
|
|
17229
|
+
var formIdTargetInput = external_exports.string().uuid().optional().describe(
|
|
17230
|
+
"The form this is for (from clipform_create_form) - a routing hint only, to pick the right workspace. The result still lands in the workspace library, not on a node. Required on an anonymous session, or this lands in a different workspace and clipform_attach_node_media will not find it."
|
|
17231
|
+
);
|
|
17232
|
+
|
|
17190
17233
|
// src/tools/create-form.ts
|
|
17191
17234
|
function registerCreateFormTool(server) {
|
|
17192
17235
|
server.registerTool(
|
|
@@ -17211,6 +17254,7 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17211
17254
|
]
|
|
17212
17255
|
}`,
|
|
17213
17256
|
inputSchema: {
|
|
17257
|
+
workspace_id: workspaceIdInput,
|
|
17214
17258
|
title: external_exports.string().describe("Form title"),
|
|
17215
17259
|
nodes: external_exports.array(NodeSchema).min(1).describe("Ordered list of nodes/steps for the form"),
|
|
17216
17260
|
show_step_counter: external_exports.boolean().optional().describe("Show step counter (e.g. '1/5'). Set true for quizzes."),
|
|
@@ -17229,7 +17273,8 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17229
17273
|
viewer_url: external_exports.string().describe("Form URL for respondents - a live public URL once authenticated/published, or a scoped preview-only link for an anonymous session"),
|
|
17230
17274
|
dashboard_url: external_exports.string().optional().describe("Builder URL (sign in to edit)"),
|
|
17231
17275
|
nodes: external_exports.array(external_exports.object({ id: external_exports.string(), type: external_exports.string(), prompt: external_exports.string() })).describe("Created nodes in order - IDs for attach_node_media / update_node"),
|
|
17232
|
-
plan: external_exports.object({ name: external_exports.string(), auth_mode: external_exports.string() }).optional().describe("Plan and auth context for this session")
|
|
17276
|
+
plan: external_exports.object({ name: external_exports.string(), auth_mode: external_exports.string() }).optional().describe("Plan and auth context for this session"),
|
|
17277
|
+
workspace_name: external_exports.string().optional().describe("Name of the workspace the form was created in")
|
|
17233
17278
|
},
|
|
17234
17279
|
annotations: {
|
|
17235
17280
|
readOnlyHint: false,
|
|
@@ -17342,6 +17387,7 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17342
17387
|
isPreview ? `Form created as a preview draft.` : `Form created and live.`,
|
|
17343
17388
|
``,
|
|
17344
17389
|
`Title: ${title}`,
|
|
17390
|
+
...planContext?.is_authenticated && planContext.workspace_name ? [`Workspace: ${planContext.workspace_name}`] : [],
|
|
17345
17391
|
`Form ID: ${formId}`,
|
|
17346
17392
|
``,
|
|
17347
17393
|
`Node IDs (use directly with attach_node_media / update_node - no get_form round-trip needed):`,
|
|
@@ -17389,15 +17435,111 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17389
17435
|
// runtime. structuredContent should return only relevant data (ChatGPT
|
|
17390
17436
|
// App Directory response-hygiene policy, #797).
|
|
17391
17437
|
nodes: createdNodes.map((n) => ({ id: n.id, type: n.type, prompt: n.prompt })),
|
|
17392
|
-
...planContext ? { plan: { name: planContext.plan_name, auth_mode: planContext.auth_mode } } : {}
|
|
17438
|
+
...planContext ? { plan: { name: planContext.plan_name, auth_mode: planContext.auth_mode } } : {},
|
|
17439
|
+
...planContext?.is_authenticated && planContext.workspace_name ? { workspace_name: planContext.workspace_name } : {}
|
|
17393
17440
|
}
|
|
17394
17441
|
};
|
|
17395
17442
|
}
|
|
17396
17443
|
);
|
|
17397
17444
|
}
|
|
17398
17445
|
|
|
17399
|
-
//
|
|
17400
|
-
|
|
17446
|
+
// ../form-sources/dist/types.js
|
|
17447
|
+
var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17448
|
+
var str = (v) => typeof v === "string" ? v : "";
|
|
17449
|
+
var DEFAULT_QUESTION_CAP = 50;
|
|
17450
|
+
var MAX_OPTIONS = 10;
|
|
17451
|
+
|
|
17452
|
+
// ../form-sources/dist/patterns.js
|
|
17453
|
+
var firstMatch = (url, patterns) => {
|
|
17454
|
+
for (const re of patterns) {
|
|
17455
|
+
const id = re.exec(url)?.[1];
|
|
17456
|
+
if (id)
|
|
17457
|
+
return id;
|
|
17458
|
+
}
|
|
17459
|
+
return null;
|
|
17460
|
+
};
|
|
17461
|
+
var VIDEOASK_PATTERNS = [
|
|
17462
|
+
/^https?:\/\/api\.videoask\.com\/forms\/sharing\/(f[a-z0-9]{8})(?:[/?#]|$)/i,
|
|
17463
|
+
/^https?:\/\/(?:www\.)?videoask\.com\/(f[a-z0-9]{8})(?:[/?#]|$)/i
|
|
17464
|
+
];
|
|
17465
|
+
var detectVideoAskId = (url) => firstMatch(url, VIDEOASK_PATTERNS);
|
|
17466
|
+
var TYPEFORM_ATTR_KINDS = {
|
|
17467
|
+
"data-tf-widget": "inline",
|
|
17468
|
+
"data-tf-popup": "popup",
|
|
17469
|
+
"data-tf-slider": "slider",
|
|
17470
|
+
"data-tf-sidetab": "slider",
|
|
17471
|
+
"data-tf-popover": "popover"
|
|
17472
|
+
};
|
|
17473
|
+
var TALLY_ATTR_KINDS = {
|
|
17474
|
+
"data-tally-src": "inline",
|
|
17475
|
+
"data-tally-open": "popup"
|
|
17476
|
+
};
|
|
17477
|
+
var EMBED_ATTR_NAMES = [...Object.keys(TYPEFORM_ATTR_KINDS), ...Object.keys(TALLY_ATTR_KINDS)];
|
|
17478
|
+
function pushUnique(out, ref) {
|
|
17479
|
+
if (!out.some((r) => r.id === ref.id))
|
|
17480
|
+
out.push(ref);
|
|
17481
|
+
}
|
|
17482
|
+
function detectVideoAskScript(text) {
|
|
17483
|
+
const out = [];
|
|
17484
|
+
if (!/VIDEOASK_EMBED_CONFIG/.test(text))
|
|
17485
|
+
return out;
|
|
17486
|
+
for (const m of text.matchAll(/videoask\.com\/(f[a-z0-9]{8})(?![a-z0-9])/gi))
|
|
17487
|
+
pushUnique(out, { id: m[1].toLowerCase() });
|
|
17488
|
+
return out;
|
|
17489
|
+
}
|
|
17490
|
+
|
|
17491
|
+
// ../form-sources/dist/providers/videoask.js
|
|
17492
|
+
function optionText(o) {
|
|
17493
|
+
if (typeof o === "string")
|
|
17494
|
+
return o;
|
|
17495
|
+
if (isObj(o))
|
|
17496
|
+
return str(o.label) || str(o.text) || str(o.value) || str(o.title);
|
|
17497
|
+
return "";
|
|
17498
|
+
}
|
|
17499
|
+
var videoask = {
|
|
17500
|
+
id: "videoask",
|
|
17501
|
+
detect: detectVideoAskId,
|
|
17502
|
+
detectScript: detectVideoAskScript,
|
|
17503
|
+
fetchSpec: (id) => ({ url: `https://api.videoask.com/forms/sharing/${id}`, responseType: "json" }),
|
|
17504
|
+
/**
|
|
17505
|
+
* `GET api.videoask.com/forms/sharing/<id>`. Personal/account fields
|
|
17506
|
+
* (`author_id`, `organization_id`, ...) are dropped by construction: only the
|
|
17507
|
+
* fields below are copied.
|
|
17508
|
+
*/
|
|
17509
|
+
summarize(id, json, opts) {
|
|
17510
|
+
if (!isObj(json) || !Array.isArray(json.questions))
|
|
17511
|
+
throw new Error("not a VideoAsk form payload");
|
|
17512
|
+
const transcriptCap = opts?.transcriptCap;
|
|
17513
|
+
const questions = json.questions.slice(0, opts?.questionCap ?? DEFAULT_QUESTION_CAP).map((q) => {
|
|
17514
|
+
const o = isObj(q) ? q : {};
|
|
17515
|
+
const transcript = str(o.transcription);
|
|
17516
|
+
return {
|
|
17517
|
+
label: str(o.label),
|
|
17518
|
+
type: str(o.type),
|
|
17519
|
+
options: (Array.isArray(o.options) ? o.options : []).map(optionText).filter(Boolean).slice(0, MAX_OPTIONS),
|
|
17520
|
+
transcript: transcriptCap === void 0 ? transcript : transcript.slice(0, transcriptCap)
|
|
17521
|
+
};
|
|
17522
|
+
});
|
|
17523
|
+
return {
|
|
17524
|
+
provider: "videoask",
|
|
17525
|
+
id,
|
|
17526
|
+
title: str(json.title),
|
|
17527
|
+
questions,
|
|
17528
|
+
meta: {
|
|
17529
|
+
...str(json.created_at) ? { created_at: str(json.created_at) } : {},
|
|
17530
|
+
...str(json.updated_at) ? { last_edited_at: str(json.updated_at) } : {},
|
|
17531
|
+
// hide_branding is a paid-plan feature.
|
|
17532
|
+
paid_plan: json.hide_branding === true,
|
|
17533
|
+
asks_contact: ["requires_contact_email", "requires_contact_info", "requires_contact_name", "requires_contact_phone_number"].some((k) => json[k] === true),
|
|
17534
|
+
...str(json.status) ? { status: str(json.status) } : {}
|
|
17535
|
+
}
|
|
17536
|
+
};
|
|
17537
|
+
}
|
|
17538
|
+
};
|
|
17539
|
+
|
|
17540
|
+
// ../form-sources/dist/index.js
|
|
17541
|
+
var IMPORTABLE_PROVIDERS = ["google", "typeform", "tally"];
|
|
17542
|
+
function detectProvider(url) {
|
|
17401
17543
|
let parsed;
|
|
17402
17544
|
try {
|
|
17403
17545
|
parsed = new URL(url);
|
|
@@ -17405,17 +17547,22 @@ function detectImportPlatform(url) {
|
|
|
17405
17547
|
return null;
|
|
17406
17548
|
}
|
|
17407
17549
|
const hostname2 = parsed.hostname.toLowerCase();
|
|
17408
|
-
if (hostname2 === "docs.google.com" || hostname2 === "forms.gle")
|
|
17550
|
+
if (hostname2 === "docs.google.com" || hostname2 === "forms.gle")
|
|
17409
17551
|
return "google";
|
|
17410
|
-
|
|
17411
|
-
if (hostname2.includes("typeform.com") && parsed.pathname.includes("/to/")) {
|
|
17552
|
+
if (hostname2.includes("typeform.com") && parsed.pathname.includes("/to/"))
|
|
17412
17553
|
return "typeform";
|
|
17413
|
-
|
|
17414
|
-
if (hostname2.includes("tally.so")) {
|
|
17554
|
+
if (hostname2.includes("tally.so"))
|
|
17415
17555
|
return "tally";
|
|
17416
|
-
|
|
17556
|
+
if (videoask.detect(url))
|
|
17557
|
+
return "videoask";
|
|
17417
17558
|
return null;
|
|
17418
17559
|
}
|
|
17560
|
+
|
|
17561
|
+
// src/tools/import-form.ts
|
|
17562
|
+
function detectImportPlatform(url) {
|
|
17563
|
+
const provider = detectProvider(url);
|
|
17564
|
+
return provider && IMPORTABLE_PROVIDERS.includes(provider) ? provider : null;
|
|
17565
|
+
}
|
|
17419
17566
|
function pluralQuestions(n) {
|
|
17420
17567
|
return `${n} question${n === 1 ? "" : "s"}`;
|
|
17421
17568
|
}
|
|
@@ -17426,6 +17573,7 @@ function registerImportFormTool(server) {
|
|
|
17426
17573
|
title: "Import Form",
|
|
17427
17574
|
description: `Convert a public Google Form, Typeform, or Tally form into a new Clipform. Supported URLs: Google Forms (docs.google.com or forms.gle - must be shared as "Anyone with the link"), Typeform (form.typeform.com/to/...), and Tally (tally.so - must be public). The source form must be publicly accessible; a private form's questions cannot be read. The new Clipform is created as a DRAFT - review it, then republish with clipform_update_form (is_live: true) once it's ready. Some question types don't map cleanly to a Clipform node and are skipped rather than guessed at; the result always reports exactly what was imported vs skipped, and why.`,
|
|
17428
17575
|
inputSchema: {
|
|
17576
|
+
workspace_id: workspaceIdInput,
|
|
17429
17577
|
url: external_exports.string().url().describe("Public URL of the Google Form, Typeform, or Tally form to import")
|
|
17430
17578
|
},
|
|
17431
17579
|
outputSchema: {
|
|
@@ -17438,7 +17586,8 @@ function registerImportFormTool(server) {
|
|
|
17438
17586
|
skipped: external_exports.number().describe("Questions that could not be converted"),
|
|
17439
17587
|
skipped_details: external_exports.array(external_exports.record(external_exports.string(), external_exports.string())).describe("Per-skipped-question title, reason, and source question type"),
|
|
17440
17588
|
warnings: external_exports.array(external_exports.string()).describe("Non-fatal issues surfaced during the import")
|
|
17441
|
-
})
|
|
17589
|
+
}),
|
|
17590
|
+
workspace_name: external_exports.string().optional().describe("Name of the workspace the form was created in")
|
|
17442
17591
|
},
|
|
17443
17592
|
annotations: {
|
|
17444
17593
|
readOnlyHint: false,
|
|
@@ -17462,6 +17611,7 @@ function registerImportFormTool(server) {
|
|
|
17462
17611
|
}
|
|
17463
17612
|
const me = meResult.data;
|
|
17464
17613
|
const workspaceId = me.workspace?.id ?? null;
|
|
17614
|
+
const workspaceName = me.auth_mode && me.auth_mode !== "anonymous" ? me.workspace?.name ?? void 0 : void 0;
|
|
17465
17615
|
if (!workspaceId) {
|
|
17466
17616
|
return errorResult(
|
|
17467
17617
|
"No workspace available. This usually means authentication is misconfigured - check your API key or OAuth connection."
|
|
@@ -17504,7 +17654,9 @@ function registerImportFormTool(server) {
|
|
|
17504
17654
|
`Pass form_id (the UUID above, not a share_id) to follow-up tools (get_form, add_node, update_node, etc.).`
|
|
17505
17655
|
);
|
|
17506
17656
|
}
|
|
17657
|
+
if (formId && workspaceName) lines.push(``, `Created in workspace '${workspaceName}'.`);
|
|
17507
17658
|
return structuredResult(lines.join("\n"), {
|
|
17659
|
+
...workspaceName ? { workspace_name: workspaceName } : {},
|
|
17508
17660
|
form_id: formId,
|
|
17509
17661
|
viewer_url: viewerUrl,
|
|
17510
17662
|
import_summary: {
|
|
@@ -17528,6 +17680,7 @@ function registerListFormsTool(server) {
|
|
|
17528
17680
|
title: "List Clipforms",
|
|
17529
17681
|
description: `List forms in your workspace with optional filtering. Returns paginated results (cursor-based). next_cursor is included when more results exist. To find or open a form by name, pass search with part of its title instead of paging through results.`,
|
|
17530
17682
|
inputSchema: {
|
|
17683
|
+
workspace_id: workspaceIdInput,
|
|
17531
17684
|
limit: external_exports.number().int().min(1).max(100).optional().describe("Number of forms to return (default 25, max 100)"),
|
|
17532
17685
|
cursor: external_exports.string().optional().describe(
|
|
17533
17686
|
"Pagination cursor from previous response's next_cursor"
|
|
@@ -18347,7 +18500,8 @@ function registerWhoamiTool(server) {
|
|
|
18347
18500
|
node_limit: external_exports.number().nullable().describe("Max nodes per form, or null if unlimited"),
|
|
18348
18501
|
form_limit: external_exports.number().nullable().describe("Max forms in the workspace, or null if unlimited")
|
|
18349
18502
|
}).describe("Plan limits for the active workspace"),
|
|
18350
|
-
workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string() })).optional().describe("
|
|
18503
|
+
workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string() })).optional().describe("Workspaces the caller can target with workspace_id - present for session (dashboard) auth and the OAuth connector"),
|
|
18504
|
+
default_workspace_id: external_exports.string().optional().describe("OAuth connector only: the workspace used when a tool call omits workspace_id"),
|
|
18351
18505
|
links: external_exports.object({
|
|
18352
18506
|
dashboard: external_exports.string().describe("Dashboard home for the active workspace."),
|
|
18353
18507
|
forms: external_exports.string().describe("Forms list for the active workspace.")
|
|
@@ -18385,11 +18539,26 @@ function registerWhoamiTool(server) {
|
|
|
18385
18539
|
if (Array.isArray(me.workspaces)) {
|
|
18386
18540
|
structured.workspaces = me.workspaces.map((w) => ({ id: w.id, name: w.name }));
|
|
18387
18541
|
}
|
|
18542
|
+
const ctx = getMcpAuth();
|
|
18543
|
+
if (!structured.workspaces && ctx?.listWorkspaces) {
|
|
18544
|
+
try {
|
|
18545
|
+
const list = await ctx.listWorkspaces();
|
|
18546
|
+
structured.workspaces = list.map((w) => ({ id: w.id, name: w.name }));
|
|
18547
|
+
if (ctx.default_workspace_id) structured.default_workspace_id = ctx.default_workspace_id;
|
|
18548
|
+
} catch {
|
|
18549
|
+
}
|
|
18550
|
+
}
|
|
18388
18551
|
if (me.links && typeof me.links.dashboard === "string" && typeof me.links.forms === "string") {
|
|
18389
18552
|
structured.links = { dashboard: me.links.dashboard, forms: me.links.forms };
|
|
18390
18553
|
}
|
|
18391
18554
|
const workspaceLine = workspace ? `workspace '${workspace.name}'` : "no workspace (anonymous)";
|
|
18392
18555
|
const lines = [`Auth: ${authMode}. ${workspaceLine}. Plan: ${plan.name}.`];
|
|
18556
|
+
if (Array.isArray(structured.workspaces) && ctx?.listWorkspaces) {
|
|
18557
|
+
const list = structured.workspaces;
|
|
18558
|
+
lines.push(
|
|
18559
|
+
`Workspaces you can act in (pass one of these ids as the workspace argument to target it; omit it to use the default): ` + list.map((w) => `${w.name} (${w.id})`).join(", ")
|
|
18560
|
+
);
|
|
18561
|
+
}
|
|
18393
18562
|
if (structured.links) {
|
|
18394
18563
|
const links = structured.links;
|
|
18395
18564
|
lines.push(`Dashboard: ${links.dashboard}`, `Forms list: ${links.forms}`);
|
|
@@ -18578,7 +18747,8 @@ function registerDeleteNodeTool(server) {
|
|
|
18578
18747
|
|
|
18579
18748
|
// src/tools/upload-media-asset.ts
|
|
18580
18749
|
var MediaAssetItemSchema = external_exports.object({
|
|
18581
|
-
media_type: external_exports.enum(["video", "still"]).describe("Type of media"),
|
|
18750
|
+
media_type: external_exports.enum(["video", "still", "document"]).describe("Type of media. Use document for a consent-agreement PDF (url required, PDF only)."),
|
|
18751
|
+
filename: external_exports.string().max(200).optional().describe("Display filename for a document (media_type document). Defaults to the URL's file name."),
|
|
18582
18752
|
media_source: external_exports.enum(["uploaded", "recorded"]).default("uploaded").describe("How the media was created"),
|
|
18583
18753
|
url: external_exports.string().url().optional().describe("Public URL that links directly to the media file itself. When provided, the server fetches and stores it directly."),
|
|
18584
18754
|
captions: external_exports.array(
|
|
@@ -18624,9 +18794,16 @@ function mapFileEntryToItem(file) {
|
|
|
18624
18794
|
if (category === "video") {
|
|
18625
18795
|
return { ok: true, item: { media_type: "video", media_source: "uploaded", url: file.download_url } };
|
|
18626
18796
|
}
|
|
18797
|
+
if (mimeType === "application/pdf") {
|
|
18798
|
+
const filename = file.name ?? file.file_name;
|
|
18799
|
+
return {
|
|
18800
|
+
ok: true,
|
|
18801
|
+
item: { media_type: "document", media_source: "uploaded", url: file.download_url, ...filename ? { filename } : {} }
|
|
18802
|
+
};
|
|
18803
|
+
}
|
|
18627
18804
|
return {
|
|
18628
18805
|
ok: false,
|
|
18629
|
-
error: `Attached file type "${mimeType || "unknown"}" is not supported. Attach an image or
|
|
18806
|
+
error: `Attached file type "${mimeType || "unknown"}" is not supported. Attach an image, video or PDF file, or provide a direct URL instead.`
|
|
18630
18807
|
};
|
|
18631
18808
|
}
|
|
18632
18809
|
function registerUploadMediaAssetTool(server) {
|
|
@@ -18636,38 +18813,55 @@ function registerUploadMediaAssetTool(server) {
|
|
|
18636
18813
|
title: "Upload Media Asset",
|
|
18637
18814
|
description: `Put one or more media files into your workspace media library (max 10, uploaded sequentially). This is step one of attaching media to a node - follow up with clipform_attach_node_media to place the returned media_asset_id on a node.
|
|
18638
18815
|
|
|
18639
|
-
When a public URL is provided, the media is fetched and stored automatically.
|
|
18816
|
+
When a public URL is provided, the media is fetched and stored automatically. The API picks where each asset is stored based on its size and type. Word-level captions from clipform_generate_tts enable per-word highlighting in the viewer once attached - pass the caption_ref it returned instead of hand-copying the captions array.
|
|
18817
|
+
|
|
18818
|
+
PDFs (media_type document) are for consent agreements: they return a document descriptor, not a media_asset_id.
|
|
18640
18819
|
|
|
18641
18820
|
Provide media via \`items\` (explicit type + URL), \`files\` (files attached by the host client), or both. At least one is required.`,
|
|
18642
18821
|
inputSchema: {
|
|
18822
|
+
workspace_id: workspaceIdInput,
|
|
18823
|
+
form_id: formIdTargetInput,
|
|
18643
18824
|
items: external_exports.array(MediaAssetItemSchema).min(1).max(10).optional().describe("One or more media items to create as workspace library assets"),
|
|
18644
|
-
files: external_exports.array(FileEntrySchema).min(1).max(10).optional().describe("Files attached by the host client. Each becomes a video or still library asset based on its declared mime_type.")
|
|
18825
|
+
files: external_exports.array(FileEntrySchema).min(1).max(10).optional().describe("Files attached by the host client. Each becomes a video or still library asset (or a consent-agreement document for application/pdf) based on its declared mime_type.")
|
|
18645
18826
|
},
|
|
18646
18827
|
outputSchema: {
|
|
18647
18828
|
results: external_exports.array(
|
|
18648
18829
|
external_exports.object({
|
|
18649
|
-
media_asset_id: external_exports.string().optional(),
|
|
18830
|
+
media_asset_id: external_exports.string().optional().describe("Absent for documents"),
|
|
18650
18831
|
media_type: external_exports.string(),
|
|
18832
|
+
document: external_exports.object({
|
|
18833
|
+
storage_path: external_exports.string(),
|
|
18834
|
+
filename: external_exports.string(),
|
|
18835
|
+
url: external_exports.string(),
|
|
18836
|
+
version: external_exports.string()
|
|
18837
|
+
}).optional().describe("Consent-agreement descriptor (documents only) - set as consent_items[i].document via clipform_update_node"),
|
|
18651
18838
|
stored: external_exports.boolean().describe("Bytes already stored (URL-based); false when an upload_url is pending"),
|
|
18652
18839
|
upload_url: external_exports.string().optional(),
|
|
18653
18840
|
upload_method: external_exports.string().optional(),
|
|
18654
18841
|
ok: external_exports.boolean(),
|
|
18655
18842
|
error: external_exports.string().optional()
|
|
18656
18843
|
})
|
|
18657
|
-
).describe("One result per item, in order")
|
|
18844
|
+
).describe("One result per item, in order"),
|
|
18845
|
+
workspace_name: external_exports.string().optional().describe("Name of the workspace the media library entries were created in")
|
|
18658
18846
|
},
|
|
18659
18847
|
annotations: {
|
|
18660
18848
|
readOnlyHint: false,
|
|
18661
18849
|
destructiveHint: false,
|
|
18662
18850
|
idempotentHint: false,
|
|
18663
|
-
|
|
18851
|
+
// Open-world: fetches an arbitrary caller-supplied URL (and may hand
|
|
18852
|
+
// larger video to a third-party streaming provider) (#4434).
|
|
18853
|
+
openWorldHint: true
|
|
18664
18854
|
},
|
|
18665
18855
|
// Apps SDK convention (openai-apps-sdk-examples#185): a host client only
|
|
18666
18856
|
// hydrates a file attachment into a TOP-LEVEL tool argument named here -
|
|
18667
18857
|
// same mechanism create-form.ts uses for anthropic/alwaysLoad.
|
|
18668
18858
|
_meta: { "openai/fileParams": ["files"] }
|
|
18669
18859
|
},
|
|
18670
|
-
|
|
18860
|
+
// `form_id` is consumed centrally by `runWithWorkspaceTarget` (server.ts)
|
|
18861
|
+
// BEFORE this handler runs - it's a routing hint only (#4621), never
|
|
18862
|
+
// forwarded to the API: this route takes no form_id and /me below still
|
|
18863
|
+
// resolves the (now-targeted) workspace.
|
|
18864
|
+
async ({ items, files, form_id: _form_id }) => {
|
|
18671
18865
|
if ((!items || items.length === 0) && (!files || files.length === 0)) {
|
|
18672
18866
|
return errorResult("Provide at least one media item via `items` or `files`.");
|
|
18673
18867
|
}
|
|
@@ -18681,6 +18875,7 @@ Provide media via \`items\` (explicit type + URL), \`files\` (files attached by
|
|
|
18681
18875
|
}
|
|
18682
18876
|
const me = meResult.data;
|
|
18683
18877
|
const workspaceId = me.workspace?.id ?? null;
|
|
18878
|
+
const workspaceName = me.auth_mode && me.auth_mode !== "anonymous" ? me.workspace?.name ?? void 0 : void 0;
|
|
18684
18879
|
if (!workspaceId) {
|
|
18685
18880
|
return errorResult(
|
|
18686
18881
|
"No workspace available. This usually means authentication is misconfigured - check your API key or OAuth connection."
|
|
@@ -18712,6 +18907,7 @@ Provide media via \`items\` (explicit type + URL), \`files\` (files attached by
|
|
|
18712
18907
|
media_source: item.media_source
|
|
18713
18908
|
};
|
|
18714
18909
|
if (item.url) createBody.url = item.url;
|
|
18910
|
+
if (item.filename) createBody.filename = item.filename;
|
|
18715
18911
|
if (item.captions) createBody.captions = item.captions;
|
|
18716
18912
|
if (item.caption_ref) createBody.caption_ref = item.caption_ref;
|
|
18717
18913
|
if (item.ai_generated !== void 0) createBody.ai_generated = item.ai_generated;
|
|
@@ -18722,6 +18918,33 @@ Provide media via \`items\` (explicit type + URL), \`files\` (files attached by
|
|
|
18722
18918
|
results.push({ media_type: item.media_type, stored: false, ok: false, error: created.error });
|
|
18723
18919
|
continue;
|
|
18724
18920
|
}
|
|
18921
|
+
if (item.media_type === "document") {
|
|
18922
|
+
const d = created.data;
|
|
18923
|
+
if (typeof d.storage_path !== "string" || typeof d.url !== "string" || typeof d.version !== "string" || !d.version) {
|
|
18924
|
+
const error2 = "document upload did not return a document descriptor.";
|
|
18925
|
+
lines.push(`FAILED: ${error2}`);
|
|
18926
|
+
lines.push("");
|
|
18927
|
+
results.push({ media_type: "document", stored: false, ok: false, error: error2 });
|
|
18928
|
+
continue;
|
|
18929
|
+
}
|
|
18930
|
+
const document = {
|
|
18931
|
+
storage_path: d.storage_path,
|
|
18932
|
+
filename: String(d.filename ?? item.filename ?? "agreement.pdf"),
|
|
18933
|
+
url: d.url,
|
|
18934
|
+
version: d.version
|
|
18935
|
+
};
|
|
18936
|
+
successCount++;
|
|
18937
|
+
results.push({ media_type: "document", stored: true, ok: true, document });
|
|
18938
|
+
lines.push(
|
|
18939
|
+
[
|
|
18940
|
+
`Document stored: ${document.filename}`,
|
|
18941
|
+
`Descriptor: ${JSON.stringify(document)}`,
|
|
18942
|
+
`Set this on a Details node consent item via clipform_update_node: consent_items[i].document = <descriptor>, require_scroll_to_accept: true. Do not use clipform_attach_node_media.`
|
|
18943
|
+
].join("\n")
|
|
18944
|
+
);
|
|
18945
|
+
lines.push("");
|
|
18946
|
+
continue;
|
|
18947
|
+
}
|
|
18725
18948
|
const mediaAssetId = created.data.media_asset_id;
|
|
18726
18949
|
if (!mediaAssetId) {
|
|
18727
18950
|
const error2 = `upload did not return a media asset id (route ${String(created.data.route ?? "unknown")}).`;
|
|
@@ -18763,9 +18986,12 @@ Provide media via \`items\` (explicit type + URL), \`files\` (files attached by
|
|
|
18763
18986
|
lines.unshift(`Media asset upload: ${successCount}/${entries.length} succeeded
|
|
18764
18987
|
`);
|
|
18765
18988
|
}
|
|
18766
|
-
|
|
18989
|
+
if (results.some((r) => r.ok && r.media_asset_id)) {
|
|
18990
|
+
lines.push(`Attach these to nodes with clipform_attach_node_media.`);
|
|
18991
|
+
}
|
|
18767
18992
|
if (successCount === 0) return errorResult(lines.join("\n"));
|
|
18768
|
-
|
|
18993
|
+
if (workspaceName) lines.push(`Workspace: ${workspaceName}`);
|
|
18994
|
+
return structuredResult(lines.join("\n"), { results, ...workspaceName ? { workspace_name: workspaceName } : {} });
|
|
18769
18995
|
}
|
|
18770
18996
|
);
|
|
18771
18997
|
}
|
|
@@ -18776,9 +19002,10 @@ function registerCompleteMediaUploadTool(server) {
|
|
|
18776
19002
|
"clipform_complete_media_upload",
|
|
18777
19003
|
{
|
|
18778
19004
|
title: "Complete Media Upload",
|
|
18779
|
-
description: `Confirm a signed-PUT still image upload finished, after PUTting the bytes to the upload_url returned by clipform_upload_media_asset. The API verifies the object actually landed in storage before flipping the asset from processing to ready - call this right after the PUT succeeds, or the asset stays invisible in the library. Not needed for video uploads (
|
|
19005
|
+
description: `Confirm a signed-PUT still image upload finished, after PUTting the bytes to the upload_url returned by clipform_upload_media_asset. The API verifies the object actually landed in storage before flipping the asset from processing to ready - call this right after the PUT succeeds, or the asset stays invisible in the library. Not needed for video uploads (they settle automatically).`,
|
|
18780
19006
|
inputSchema: {
|
|
18781
|
-
media_asset_id: external_exports.string().uuid().describe("The media_asset_id returned by clipform_upload_media_asset for the still image")
|
|
19007
|
+
media_asset_id: external_exports.string().uuid().describe("The media_asset_id returned by clipform_upload_media_asset for the still image"),
|
|
19008
|
+
form_id: formIdTargetInput
|
|
18782
19009
|
},
|
|
18783
19010
|
outputSchema: {
|
|
18784
19011
|
media_asset_id: external_exports.string(),
|
|
@@ -18791,7 +19018,10 @@ function registerCompleteMediaUploadTool(server) {
|
|
|
18791
19018
|
openWorldHint: false
|
|
18792
19019
|
}
|
|
18793
19020
|
},
|
|
18794
|
-
|
|
19021
|
+
// `form_id` (#4621) is a routing hint only, consumed centrally by
|
|
19022
|
+
// `runWithWorkspaceTarget` (server.ts) before this handler runs - never
|
|
19023
|
+
// forwarded to the API below (this route takes no form_id).
|
|
19024
|
+
async ({ media_asset_id, form_id: _form_id }) => {
|
|
18795
19025
|
const meResult = await callApi("/me", { method: "GET" });
|
|
18796
19026
|
if (!meResult.ok) {
|
|
18797
19027
|
return errorResult(`Unable to determine workspace: ${meResult.error}`);
|
|
@@ -18970,7 +19200,7 @@ function registerDeleteNodeMediaTool(server) {
|
|
|
18970
19200
|
"clipform_delete_node_media",
|
|
18971
19201
|
{
|
|
18972
19202
|
title: "Delete Node Media",
|
|
18973
|
-
description: `Remove media from a node. Deletes the media record and
|
|
19203
|
+
description: `Remove media from a node. Deletes the media record and the stored media asset (including any copy held by a third-party video provider). Requires user confirmation before it runs.`,
|
|
18974
19204
|
inputSchema: {
|
|
18975
19205
|
form_id: external_exports.string().uuid().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)"),
|
|
18976
19206
|
node_id: external_exports.string().describe("The node ID"),
|
|
@@ -18982,7 +19212,9 @@ function registerDeleteNodeMediaTool(server) {
|
|
|
18982
19212
|
// Deleting already-removed media has no further effect - textbook
|
|
18983
19213
|
// idempotent delete (#2976).
|
|
18984
19214
|
idempotentHint: true,
|
|
18985
|
-
|
|
19215
|
+
// Open-world: also deletes any copy held by a third-party video
|
|
19216
|
+
// provider (#4434).
|
|
19217
|
+
openWorldHint: true
|
|
18986
19218
|
}
|
|
18987
19219
|
},
|
|
18988
19220
|
async ({ form_id, node_id, confirm }) => {
|
|
@@ -19124,10 +19356,10 @@ function registerSearchNewsTool(server) {
|
|
|
19124
19356
|
server.registerTool(
|
|
19125
19357
|
"clipform_search_news",
|
|
19126
19358
|
{
|
|
19127
|
-
title: "Search News
|
|
19128
|
-
description: `
|
|
19359
|
+
title: "Search Recent News",
|
|
19360
|
+
description: `Search recent news articles from NewsAPI and The Guardian and return them as structured results.
|
|
19129
19361
|
|
|
19130
|
-
Coverage: recent events, people, and topics (post-May-2025). Does NOT cover timeless topics (history, geography, science).
|
|
19362
|
+
Coverage: recent events, people, and topics (post-May-2025). Does NOT cover timeless topics (history, geography, science).
|
|
19131
19363
|
|
|
19132
19364
|
Returns: article title, source, author, date, URL, description, and image URL per result.`,
|
|
19133
19365
|
inputSchema: {
|
|
@@ -19212,6 +19444,8 @@ Use the tone parameter to direct HOW the voice speaks. Always set a tone that ma
|
|
|
19212
19444
|
|
|
19213
19445
|
Pass one item or many (max 10) - multiple items run in parallel. Returns audio_url and caption_ref per item - pass caption_ref downstream to clipform_render_composition / clipform_render_video_template / clipform_upload_media_asset to attach this run's word-level captions instead of hand-copying the captions array.`,
|
|
19214
19446
|
inputSchema: {
|
|
19447
|
+
workspace_id: workspaceIdInput,
|
|
19448
|
+
form_id: formIdTargetInput,
|
|
19215
19449
|
items: external_exports.array(TtsItemSchema).min(1).max(10).describe("One or more TTS items to generate")
|
|
19216
19450
|
},
|
|
19217
19451
|
outputSchema: {
|
|
@@ -19227,7 +19461,11 @@ Pass one item or many (max 10) - multiple items run in parallel. Returns audio_u
|
|
|
19227
19461
|
},
|
|
19228
19462
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
19229
19463
|
},
|
|
19230
|
-
|
|
19464
|
+
// `form_id` (#4621) is a routing hint only, consumed centrally by
|
|
19465
|
+
// `runWithWorkspaceTarget` (server.ts) before this handler runs - it
|
|
19466
|
+
// swaps the auth context's workspace_id read below, but is never
|
|
19467
|
+
// forwarded to the API itself (the /internal/tts route takes no form_id).
|
|
19468
|
+
async ({ items, form_id: _form_id }) => {
|
|
19231
19469
|
const workspace_id = getMcpAuth()?.workspace_id;
|
|
19232
19470
|
const results = await Promise.allSettled(
|
|
19233
19471
|
items.map(
|
|
@@ -20632,7 +20870,7 @@ function createServer(options) {
|
|
|
20632
20870
|
config2,
|
|
20633
20871
|
(...args) => runWithMcpTool(name, async () => {
|
|
20634
20872
|
try {
|
|
20635
|
-
return await handler(...args);
|
|
20873
|
+
return await runWithWorkspaceTarget(args[0], () => handler(...args));
|
|
20636
20874
|
} catch (err) {
|
|
20637
20875
|
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
20638
20876
|
options?.onToolError?.(name, error2);
|
|
@@ -20685,4 +20923,4 @@ export {
|
|
|
20685
20923
|
buildInstructions,
|
|
20686
20924
|
createServer
|
|
20687
20925
|
};
|
|
20688
|
-
//# sourceMappingURL=chunk-
|
|
20926
|
+
//# sourceMappingURL=chunk-J7727374.js.map
|