flow-codeblock-rust-mcp 0.1.1 → 0.1.2
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 +7 -3
- package/dist/index.js +193 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Flow Codeblock Rust+Bun 的本地 stdio MCP Server。它只调用服务端 Rust
|
|
|
7
7
|
需要 Bun 1.4.0 或更高版本:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
bunx --bun flow-codeblock-rust-mcp@0.1.
|
|
10
|
+
bunx --bun flow-codeblock-rust-mcp@0.1.2
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
配置环境变量:
|
|
@@ -26,7 +26,7 @@ export FLOW_CODEBLOCK_TOKEN='<YOUR_INTERNAL_ACCESS_TOKEN>'
|
|
|
26
26
|
"mcpServers": {
|
|
27
27
|
"flow-codeblock-rust": {
|
|
28
28
|
"command": "bunx",
|
|
29
|
-
"args": ["--bun", "flow-codeblock-rust-mcp@0.1.
|
|
29
|
+
"args": ["--bun", "flow-codeblock-rust-mcp@0.1.2"],
|
|
30
30
|
"env": {
|
|
31
31
|
"FLOW_CODEBLOCK_BASE_URL": "https://flow.example.com",
|
|
32
32
|
"FLOW_CODEBLOCK_TOKEN": "<YOUR_INTERNAL_ACCESS_TOKEN>"
|
|
@@ -38,7 +38,9 @@ export FLOW_CODEBLOCK_TOKEN='<YOUR_INTERNAL_ACCESS_TOKEN>'
|
|
|
38
38
|
|
|
39
39
|
## 工具边界
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
工具覆盖代码生成、未发布代码测试、脚本列表、版本读取、接口文档校验/预览/保存、脚本创建/更新、锁定/解锁和已发布脚本执行。创建或代码更新可提交完整接口文档或 RFC 6902 `interface_doc_patch`;预览会调用 `/flow/scripts/validate`,应用时会再次透传补丁并使用事务级 `expected_version` 检测并发冲突。所有脚本写操作需要预览后显式 `confirm: true`。
|
|
42
|
+
|
|
43
|
+
最终用户交付按模式区分:`non_script` 输出完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和完整 `execution_url`;`script` 默认不主动回显 JavaScript 或原始 `interface_doc`,只输出接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的完整 `script_url`。脚本代码与 `interface_doc` 仍由 MCP 内部用于预览、校验和发布,除非用户明确索要源码或原始文档。
|
|
42
44
|
|
|
43
45
|
MCP 不提供脚本删除、紧急恢复解锁、Token 查询、执行统计、所有权转移或任意 HTTP 代理工具。当前版本只提供本地 stdio 连接,不提供远程 HTTP、SSE 或 Streamable HTTP 连接。
|
|
44
46
|
|
|
@@ -50,6 +52,8 @@ MCP 不提供脚本删除、紧急恢复解锁、Token 查询、执行统计、
|
|
|
50
52
|
|
|
51
53
|
接口文档的 `endpoint.path` 使用相对路径:创建时省略,更新时使用 `/flow/codeblock/<实际脚本ID>`。对外展示完整请求地址时,将用户提供的服务域名与 `/flow/codeblock/{{脚本ID}}` 拼接;不要把真实令牌、密码、Cookie 或 Authorization 值写入代码、文档、示例或 URL。
|
|
52
54
|
|
|
55
|
+
`interface_doc_patch` / `document_patch` 必须携带正整数 `expected_version`,最多 256 个 `add/remove/replace/move/copy/test` 操作。补丁预览仅返回操作数量、JSON Pointer 路径、警告和版本信息,不返回完整合并文档。
|
|
56
|
+
|
|
53
57
|
## 安全行为
|
|
54
58
|
|
|
55
59
|
- 管理请求使用 `Authorization: Bearer`,执行已发布脚本时不会把 MCP Token 转发到脚本输入。
|
package/dist/index.js
CHANGED
|
@@ -27901,6 +27901,44 @@ var interfaceDocInputDescription = [
|
|
|
27901
27901
|
"endpoint.path is relative and must be /flow/codeblock/<actual-script-id> on update; the final public URL is the caller-provided domain followed by /flow/codeblock/<script-id>.",
|
|
27902
27902
|
"Never include real tokens, passwords, cookies, Authorization values, or other credentials in the document or examples."
|
|
27903
27903
|
].join(" ");
|
|
27904
|
+
var patchPathSchema = exports_external.string().describe("RFC 6901 JSON Pointer 路径;数组路径使用当前 canonical 文档的索引。");
|
|
27905
|
+
var interfaceDocPatchOperationSchema = exports_external.union([
|
|
27906
|
+
exports_external.object({ op: exports_external.literal("add"), path: patchPathSchema, value: exports_external.unknown() }).strict(),
|
|
27907
|
+
exports_external.object({ op: exports_external.literal("remove"), path: patchPathSchema }).strict(),
|
|
27908
|
+
exports_external.object({ op: exports_external.literal("replace"), path: patchPathSchema, value: exports_external.unknown() }).strict(),
|
|
27909
|
+
exports_external.object({ op: exports_external.literal("move"), from: patchPathSchema, path: patchPathSchema }).strict(),
|
|
27910
|
+
exports_external.object({ op: exports_external.literal("copy"), from: patchPathSchema, path: patchPathSchema }).strict(),
|
|
27911
|
+
exports_external.object({ op: exports_external.literal("test"), path: patchPathSchema, value: exports_external.unknown() }).strict()
|
|
27912
|
+
]).superRefine((operation, context) => {
|
|
27913
|
+
if (["add", "replace", "test"].includes(operation.op) && !Object.prototype.hasOwnProperty.call(operation, "value")) {
|
|
27914
|
+
context.addIssue({ code: "custom", path: ["value"], message: "value is required for this operation" });
|
|
27915
|
+
}
|
|
27916
|
+
});
|
|
27917
|
+
var interfaceDocPatchSchema = exports_external.array(interfaceDocPatchOperationSchema).min(1).max(256).describe("RFC 6902 JSON Patch 操作数组;按顺序应用,不能与完整 interface_doc 同时提供。");
|
|
27918
|
+
var interfaceDocPatchJsonSchema = {
|
|
27919
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
27920
|
+
$id: "https://flow-codeblock.local/schemas/script-interface-doc.patch.v1.json",
|
|
27921
|
+
title: "script-interface-doc.v1 JSON Patch",
|
|
27922
|
+
description: "RFC 6902 operations applied in order to an existing canonical script interface document.",
|
|
27923
|
+
type: "array",
|
|
27924
|
+
minItems: 1,
|
|
27925
|
+
maxItems: 256,
|
|
27926
|
+
items: {
|
|
27927
|
+
oneOf: [
|
|
27928
|
+
{ type: "object", additionalProperties: false, required: ["op", "path", "value"], properties: { op: { const: "add" }, path: { type: "string" }, value: {} } },
|
|
27929
|
+
{ type: "object", additionalProperties: false, required: ["op", "path"], properties: { op: { const: "remove" }, path: { type: "string" } } },
|
|
27930
|
+
{ type: "object", additionalProperties: false, required: ["op", "path", "value"], properties: { op: { const: "replace" }, path: { type: "string" }, value: {} } },
|
|
27931
|
+
{ type: "object", additionalProperties: false, required: ["op", "from", "path"], properties: { op: { const: "move" }, from: { type: "string" }, path: { type: "string" } } },
|
|
27932
|
+
{ type: "object", additionalProperties: false, required: ["op", "from", "path"], properties: { op: { const: "copy" }, from: { type: "string" }, path: { type: "string" } } },
|
|
27933
|
+
{ type: "object", additionalProperties: false, required: ["op", "path", "value"], properties: { op: { const: "test" }, path: { type: "string" }, value: {} } }
|
|
27934
|
+
]
|
|
27935
|
+
}
|
|
27936
|
+
};
|
|
27937
|
+
function assertInterfaceDocPatch(patch) {
|
|
27938
|
+
const parsed = interfaceDocPatchSchema.safeParse(patch);
|
|
27939
|
+
if (!parsed.success)
|
|
27940
|
+
throw new Error(`interface_doc_patch 格式无效: ${parsed.error.message}`);
|
|
27941
|
+
}
|
|
27904
27942
|
function isObject2(value) {
|
|
27905
27943
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27906
27944
|
}
|
|
@@ -28334,7 +28372,7 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
|
|
|
28334
28372
|
rule: "除非用户明确要求测试,否则不要调用 flow_execute_code。",
|
|
28335
28373
|
response_format: [
|
|
28336
28374
|
"除非用户明确要求只返回代码,否则先说明模式和输出方式,再给 JavaScript 代码块,最后给请求/响应示例。",
|
|
28337
|
-
"
|
|
28375
|
+
"非脚本接口交付完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和 execution_url。"
|
|
28338
28376
|
]
|
|
28339
28377
|
};
|
|
28340
28378
|
}
|
|
@@ -28356,13 +28394,24 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
|
|
|
28356
28394
|
},
|
|
28357
28395
|
endpoint_url_template: normalizedBaseUrl ? `${normalizedBaseUrl}${endpointPathTemplate}` : endpointPathTemplate,
|
|
28358
28396
|
endpoint_url_rule: "提供域名时,输出该域名 + /flow/codeblock/{{script_id}};URL 中不得包含凭据。",
|
|
28359
|
-
|
|
28397
|
+
internal_artifacts: [
|
|
28398
|
+
"只含可执行代码的 JavaScript 代码块(提交预览、校验和发布;默认不回显)",
|
|
28399
|
+
"独立且完整的 script-interface-doc.v1 JSON 对象(提交预览、校验和发布;默认不回显)"
|
|
28400
|
+
],
|
|
28401
|
+
final_deliverables: [
|
|
28402
|
+
"接口调用说明",
|
|
28403
|
+
"请求参数及示例",
|
|
28404
|
+
"执行逻辑",
|
|
28405
|
+
"成功/错误输出示例",
|
|
28406
|
+
"发布后的完整 script_url"
|
|
28407
|
+
],
|
|
28360
28408
|
interface_doc_contract: {
|
|
28361
28409
|
strict_preview_gate: true,
|
|
28362
28410
|
required_fields: interfaceDocRequiredFields,
|
|
28363
28411
|
nested_rules: interfaceDocNestedRules,
|
|
28364
28412
|
body_example_schema: schemaFromExample(bodyExample),
|
|
28365
28413
|
full_json_schema: includeFullSchema ? interfaceDocSchema : undefined,
|
|
28414
|
+
patch_json_schema: includeFullSchema ? interfaceDocPatchJsonSchema : undefined,
|
|
28366
28415
|
separation: [
|
|
28367
28416
|
"javascript 代码块只含可执行代码,不写接口文档注释。",
|
|
28368
28417
|
"json 代码块只含一个合法 script-interface-doc.v1 对象,不混入 Markdown、注释或尾随逗号。"
|
|
@@ -28381,9 +28430,9 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
|
|
|
28381
28430
|
"版本冲突、预览过期或校验失败时停止并重新读取、重新预览,不重试旧 preview_id。"
|
|
28382
28431
|
],
|
|
28383
28432
|
response_format: [
|
|
28384
|
-
"
|
|
28385
|
-
"
|
|
28386
|
-
"
|
|
28433
|
+
"脚本模式默认不回显 JavaScript 或原始 interface_doc;只展示接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的 script_url,除非用户明确索要源码或原始文档。",
|
|
28434
|
+
"脚本代码与 interface_doc 仍必须在内部提交给预览、校验和发布工具。",
|
|
28435
|
+
"说明请求参数、主要业务行为、响应和错误处理,并提供与模式匹配的 HTTP 方法、路径、Headers/Query/Body/Cookie 和响应示例。"
|
|
28387
28436
|
]
|
|
28388
28437
|
};
|
|
28389
28438
|
}
|
|
@@ -28454,12 +28503,13 @@ var serverInstructions = [
|
|
|
28454
28503
|
"这是 Flow Codeblock Rust+Bun MCP Server。除 flow_write_code 外,工具直接调用服务端 REST API;flow_write_code 只返回生成契约。不要猜测 REST 路径,也不要把 MCP 内部令牌放入业务参数。",
|
|
28455
28504
|
"代码运行于服务端 Bun 异步函数上下文,支持现代 JavaScript、async/await、Promise、箭头函数和顶层 return;默认最小超时 100ms、最大超时 15000ms,代码 65535 字节、输入 2MiB、结果 10MiB。",
|
|
28456
28505
|
"工具选择:flow_write_code 只生成代码与契约,不执行、不写库;flow_execute_code 只用于用户明确要求的未发布非脚本测试;flow_execute_script 只执行已发布脚本。",
|
|
28457
|
-
"脚本读取、创建和更新流程:更新前先 flow_get_script 读取当前 version
|
|
28506
|
+
"脚本读取、创建和更新流程:更新前先 flow_get_script 读取当前 version;创建必须提供完整 interface_doc,更新代码或文档可提供完整 interface_doc 或 RFC 6902 interface_doc_patch(二选一,补丁必须带 expected_version);先 flow_preview_script_change,再在用户明确确认后 flow_apply_script_change(confirm=true)。文档单独修改使用 flow_preview_script_documentation -> flow_apply_script_documentation。",
|
|
28458
28507
|
"预览 ID 是一次性且有时效的;版本冲突、预览过期或校验失败时停止,重新读取并预览,不要重试旧 preview_id。flow_apply_* 永远需要 confirm=true。",
|
|
28459
|
-
"script-interface-doc.v1 必须包含 schema_version、title、summary、endpoint、request、responses、logic_description。endpoint 必须包含 methods 和 description;request.query、request.headers 必须存在(没有参数用 []);POST 必须有 request.body,GET-only
|
|
28508
|
+
"script-interface-doc.v1 必须包含 schema_version、title、summary、endpoint、request、responses、logic_description。endpoint 必须包含 methods 和 description;request.query、request.headers 必须存在(没有参数用 []);POST 必须有 request.body,GET-only 必须省略。增量文档使用最多 256 项的 add/remove/replace/move/copy/test JSON Patch,预览只回显操作数量和路径,不回显合并文档。",
|
|
28460
28509
|
"查询参数和请求头的每一项必须有 name、type、required、description、example。请求体和每个响应必须有 content_type=application/json、schema、example;每个响应还必须有 status、description。JSON Schema 的每个节点必须声明 type,数组必须有 items,对象和 example 必须互相覆盖。",
|
|
28461
28510
|
"接口文档 endpoint.path 只写相对路径:创建时省略,更新时写 /flow/codeblock/<实际脚本ID>。对外展示的完整调用地址必须使用用户提供的域名拼接 /flow/codeblock/{{脚本ID}};不要把真实 Token、密码、Cookie 或 Authorization 值写入代码、文档、示例或 URL。",
|
|
28462
28511
|
"脚本模式输入来自 input.query、input.header、input.body、input.cookies;即时非脚本模式 POST /flow/codeblock 的 body.input 原样成为全局 input。代码默认使用顶层 return;只有事件式/异步流程或用户明确要求时才使用裸 qf_output 赋值,不能混用。",
|
|
28512
|
+
"最终用户交付按模式区分:non_script 输出完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和完整 execution_url;script 默认不主动回显 JavaScript 或原始 interface_doc,只输出接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的完整 script_url,除非用户明确索要源码或原始文档。script 的代码与 interface_doc 仍必须内部提交给预览、校验和发布工具。",
|
|
28463
28513
|
"优先原生 JavaScript、URL/URLSearchParams 和 fetch;禁止浏览器 API、定时器、动态模块加载、黑名单 Node 模块和危险标识符。HTTP 请求必须检查状态并处理 JSON/文本/空响应,所有异步任务必须显式 await 或 return。",
|
|
28464
28514
|
"执行脚本时 method 只能是 GET 或 POST;MCP 认证、Cookie、CSRF、代理来源头和测试工具标识会被过滤。不要使用删除脚本、紧急恢复解锁或任意 HTTP 代理能力,本 MCP 不提供这些工具。"
|
|
28465
28515
|
].join(`
|
|
@@ -28467,6 +28517,27 @@ var serverInstructions = [
|
|
|
28467
28517
|
function encodedScriptId(scriptId) {
|
|
28468
28518
|
return encodeURIComponent(scriptId);
|
|
28469
28519
|
}
|
|
28520
|
+
function scriptUrl(api2, scriptId) {
|
|
28521
|
+
return new URL(`/flow/codeblock/${encodedScriptId(scriptId)}`, api2.baseUrl).toString();
|
|
28522
|
+
}
|
|
28523
|
+
function executionUrl(api2) {
|
|
28524
|
+
return new URL("/flow/codeblock", api2.baseUrl).toString();
|
|
28525
|
+
}
|
|
28526
|
+
function withScriptUrl(api2, payload, fallbackScriptId) {
|
|
28527
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
28528
|
+
return payload;
|
|
28529
|
+
const data = responseData(payload);
|
|
28530
|
+
const scriptId = typeof data.script_id === "string" && data.script_id.length > 0 ? data.script_id : fallbackScriptId;
|
|
28531
|
+
if (!scriptId)
|
|
28532
|
+
return payload;
|
|
28533
|
+
return {
|
|
28534
|
+
...payload,
|
|
28535
|
+
data: {
|
|
28536
|
+
...data,
|
|
28537
|
+
script_url: scriptUrl(api2, scriptId)
|
|
28538
|
+
}
|
|
28539
|
+
};
|
|
28540
|
+
}
|
|
28470
28541
|
function encodeCode(code, codeBase64) {
|
|
28471
28542
|
if (code === undefined && codeBase64 === undefined)
|
|
28472
28543
|
return;
|
|
@@ -28541,9 +28612,11 @@ function withApiErrors(handler) {
|
|
|
28541
28612
|
};
|
|
28542
28613
|
}
|
|
28543
28614
|
var documentationFields = {
|
|
28544
|
-
document: exports_external.unknown().optional().describe(`规范化的 script-interface-doc.v1 JSON 对象。与 raw_document
|
|
28545
|
-
raw_document: exports_external.string().optional().describe("待服务端解析的 JSON/OpenAPI 文档文本。与 document
|
|
28546
|
-
format: exports_external.literal("json").optional().describe("raw_document 的格式,目前只支持 json。")
|
|
28615
|
+
document: exports_external.unknown().optional().describe(`规范化的 script-interface-doc.v1 JSON 对象。与 raw_document、document_patch 三选一;保存或代码更新时必须完整。${interfaceDocInputDescription}`),
|
|
28616
|
+
raw_document: exports_external.string().optional().describe("待服务端解析的 JSON/OpenAPI 文档文本。与 document、document_patch 三选一;format=json 时按 JSON 解析。"),
|
|
28617
|
+
format: exports_external.literal("json").optional().describe("raw_document 的格式,目前只支持 json。"),
|
|
28618
|
+
document_patch: interfaceDocPatchSchema.optional().describe("仅已有脚本使用的 RFC 6902 增量补丁;与 document、raw_document 三选一。"),
|
|
28619
|
+
expected_version: exports_external.number().int().positive().optional().describe("补丁的当前脚本版本;提交补丁时必填,必须来自刚读取的当前版本。")
|
|
28547
28620
|
};
|
|
28548
28621
|
var changeSchema = exports_external.object({
|
|
28549
28622
|
operation: exports_external.enum(["create", "update"]).describe("create 创建脚本;update 更新已有脚本。"),
|
|
@@ -28553,18 +28626,26 @@ var changeSchema = exports_external.object({
|
|
|
28553
28626
|
description: exports_external.string().optional().describe("脚本说明。可在不改代码时单独更新。"),
|
|
28554
28627
|
ip_whitelist: exports_external.array(exports_external.string()).nullable().optional().describe("来源 IP/CIDR 白名单。省略表示更新时保持原值;null 或 [] 表示清除限制。"),
|
|
28555
28628
|
interface_doc: exports_external.unknown().optional().describe(interfaceDocInputDescription),
|
|
28556
|
-
|
|
28629
|
+
interface_doc_patch: interfaceDocPatchSchema.optional().describe("仅 update 使用的 RFC 6902 JSON Patch;与完整 interface_doc 互斥,create 禁止使用。"),
|
|
28630
|
+
rollback_to_version: exports_external.number().int().positive().optional().describe("回滚到的历史版本号。只能与单独的 update 操作使用,不能和 code、interface_doc 或 interface_doc_patch 同时传入。"),
|
|
28557
28631
|
expected_version: exports_external.number().int().positive().optional().describe("更新时必填的当前版本号。必须来自刚读取的 flow_get_script,用于并发冲突保护;create 不得传入。")
|
|
28558
28632
|
});
|
|
28559
28633
|
var documentationSchema = exports_external.object({
|
|
28560
28634
|
script_id: exports_external.string().min(1).describe("目标脚本 ID,不是完整 URL;校验或预览现有脚本的文档。"),
|
|
28561
28635
|
...documentationFields
|
|
28562
28636
|
}).superRefine((input, context) => {
|
|
28563
|
-
|
|
28564
|
-
|
|
28637
|
+
const supplied = [input.document, input.raw_document, input.document_patch].filter((value) => value !== undefined).length;
|
|
28638
|
+
if (supplied !== 1) {
|
|
28639
|
+
context.addIssue({ code: "custom", message: "Provide exactly one of document, raw_document, or document_patch" });
|
|
28640
|
+
}
|
|
28641
|
+
if (input.document_patch !== undefined && input.expected_version === undefined) {
|
|
28642
|
+
context.addIssue({ code: "custom", message: "document_patch requires expected_version" });
|
|
28565
28643
|
}
|
|
28566
28644
|
});
|
|
28567
28645
|
function documentationBody(input) {
|
|
28646
|
+
if (input.document_patch !== undefined) {
|
|
28647
|
+
return { document_patch: input.document_patch, expected_version: input.expected_version };
|
|
28648
|
+
}
|
|
28568
28649
|
if (input.raw_document !== undefined) {
|
|
28569
28650
|
return { raw_document: input.raw_document, ...input.format ? { format: input.format } : {} };
|
|
28570
28651
|
}
|
|
@@ -28584,6 +28665,9 @@ function assertScriptChangeInput(input) {
|
|
|
28584
28665
|
}
|
|
28585
28666
|
if (!hasCode)
|
|
28586
28667
|
throw new Error("Create preview requires code or code_base64");
|
|
28668
|
+
if (input.interface_doc_patch !== undefined) {
|
|
28669
|
+
throw new Error("Create preview cannot use interface_doc_patch; submit a complete interface_doc");
|
|
28670
|
+
}
|
|
28587
28671
|
if (input.interface_doc === undefined) {
|
|
28588
28672
|
throw new Error("Create preview requires a complete interface_doc");
|
|
28589
28673
|
}
|
|
@@ -28594,34 +28678,64 @@ function assertScriptChangeInput(input) {
|
|
|
28594
28678
|
if (!input.script_id || input.expected_version === undefined) {
|
|
28595
28679
|
throw new Error("Update preview requires script_id and expected_version");
|
|
28596
28680
|
}
|
|
28597
|
-
if (!hasCode && input.description === undefined && input.ip_whitelist === undefined && input.interface_doc === undefined && input.rollback_to_version === undefined) {
|
|
28598
|
-
throw new Error("Update preview requires code, description, ip_whitelist, interface_doc, or rollback_to_version");
|
|
28681
|
+
if (!hasCode && input.description === undefined && input.ip_whitelist === undefined && input.interface_doc === undefined && input.interface_doc_patch === undefined && input.rollback_to_version === undefined) {
|
|
28682
|
+
throw new Error("Update preview requires code, description, ip_whitelist, interface_doc, interface_doc_patch, or rollback_to_version");
|
|
28599
28683
|
}
|
|
28600
|
-
if (hasCode && input.interface_doc === undefined) {
|
|
28601
|
-
throw new Error("Updating code requires a complete interface_doc");
|
|
28684
|
+
if (hasCode && input.interface_doc === undefined && input.interface_doc_patch === undefined) {
|
|
28685
|
+
throw new Error("Updating code requires a complete interface_doc or interface_doc_patch");
|
|
28602
28686
|
}
|
|
28603
28687
|
}
|
|
28604
|
-
if (input.
|
|
28605
|
-
throw new Error("
|
|
28688
|
+
if (input.interface_doc !== undefined && input.interface_doc_patch !== undefined) {
|
|
28689
|
+
throw new Error("interface_doc and interface_doc_patch are mutually exclusive");
|
|
28690
|
+
}
|
|
28691
|
+
if (input.rollback_to_version !== undefined && (hasCode || input.interface_doc !== undefined || input.interface_doc_patch !== undefined)) {
|
|
28692
|
+
throw new Error("rollback_to_version cannot be combined with code, interface_doc, or interface_doc_patch");
|
|
28606
28693
|
}
|
|
28607
28694
|
if (input.interface_doc !== undefined) {
|
|
28608
28695
|
assertCompleteInterfaceDoc(input.interface_doc, input.operation);
|
|
28609
28696
|
}
|
|
28697
|
+
if (input.interface_doc_patch !== undefined)
|
|
28698
|
+
assertInterfaceDocPatch(input.interface_doc_patch);
|
|
28610
28699
|
}
|
|
28611
28700
|
async function validateScriptChange(api2, operation, payload) {
|
|
28612
28701
|
const hasCode = typeof payload.code_base64 === "string";
|
|
28613
28702
|
const hasDocument = payload.interface_doc !== undefined && payload.interface_doc !== null;
|
|
28703
|
+
const hasPatch = payload.interface_doc_patch !== undefined;
|
|
28614
28704
|
const hasWhitelist = payload.ip_whitelist !== undefined;
|
|
28615
|
-
if (!hasCode && !hasDocument && !hasWhitelist) {
|
|
28705
|
+
if (!hasCode && !hasDocument && !hasPatch && !hasWhitelist) {
|
|
28616
28706
|
return { success: true, data: { valid: true, warnings: [] } };
|
|
28617
28707
|
}
|
|
28618
28708
|
return api2.post("/flow/scripts/validate", {
|
|
28619
28709
|
...hasCode ? { code_base64: payload.code_base64 } : {},
|
|
28620
28710
|
...operation === "update" ? { script_id: payload.script_id } : {},
|
|
28711
|
+
...hasPatch ? { expected_version: payload.expected_version } : {},
|
|
28621
28712
|
...hasWhitelist ? { ip_whitelist: payload.ip_whitelist } : {},
|
|
28622
|
-
...hasDocument ? { interface_doc: payload.interface_doc } : {}
|
|
28713
|
+
...hasDocument ? { interface_doc: payload.interface_doc } : {},
|
|
28714
|
+
...hasPatch ? { interface_doc_patch: payload.interface_doc_patch } : {}
|
|
28623
28715
|
});
|
|
28624
28716
|
}
|
|
28717
|
+
function compactPatchValidation(validation, patch, currentVersion2) {
|
|
28718
|
+
const data = responseData(validation);
|
|
28719
|
+
const operations = Array.isArray(patch) ? patch : [];
|
|
28720
|
+
return {
|
|
28721
|
+
valid: data.valid ?? true,
|
|
28722
|
+
warnings: Array.isArray(data.warnings) ? data.warnings : [],
|
|
28723
|
+
current_version: currentVersion2,
|
|
28724
|
+
interface_doc_patch: {
|
|
28725
|
+
operation_count: operations.length,
|
|
28726
|
+
paths: operations.map((operation) => {
|
|
28727
|
+
if (!operation || typeof operation !== "object")
|
|
28728
|
+
return null;
|
|
28729
|
+
const value = operation;
|
|
28730
|
+
return {
|
|
28731
|
+
op: typeof value.op === "string" ? value.op : "unknown",
|
|
28732
|
+
path: typeof value.path === "string" ? value.path : "",
|
|
28733
|
+
...typeof value.from === "string" ? { from: value.from } : {}
|
|
28734
|
+
};
|
|
28735
|
+
})
|
|
28736
|
+
}
|
|
28737
|
+
};
|
|
28738
|
+
}
|
|
28625
28739
|
function assertPreview(record3, operation) {
|
|
28626
28740
|
if (!record3 || record3.operation !== operation)
|
|
28627
28741
|
throw new Error("Preview is missing, expired, or has the wrong operation");
|
|
@@ -28631,9 +28745,9 @@ function assertPreview(record3, operation) {
|
|
|
28631
28745
|
return record3;
|
|
28632
28746
|
}
|
|
28633
28747
|
function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
28634
|
-
const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.
|
|
28748
|
+
const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.2" }, { instructions: serverInstructions });
|
|
28635
28749
|
server.registerTool("flow_write_code", {
|
|
28636
|
-
description: "生成代码实现契约,不写数据库、不发布脚本、不执行代码。mode=non_script 生成即时 POST /flow/codeblock
|
|
28750
|
+
description: "生成代码实现契约,不写数据库、不发布脚本、不执行代码。mode=non_script 生成即时 POST /flow/codeblock 代码,最终交付包含完整 execution_url;mode=script 生成 GET/POST /flow/codeblock/{{script_id}} 代码,内部生成完整 script-interface-doc.v1 供预览、校验和发布,最终交付默认只展示接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和 script_url,除非用户明确索要源码或原始 interface_doc。脚本文档的 title、summary、endpoint.methods、endpoint.description、request、responses、logic_description 必须齐全;query/header 参数必须有 name/type/description/example,body 和 response 字段必须有 content_type/schema/example。需要展示用户指定的完整地址时可传入 base_url。",
|
|
28637
28751
|
inputSchema: {
|
|
28638
28752
|
mode: exports_external.enum(["non_script", "script"]).describe("执行模式:non_script 为即时接口;script 为按脚本 ID 发布的 GET/POST 接口。未明确要求重定向时使用 non_script。"),
|
|
28639
28753
|
requirement: exports_external.string().min(1).max(20000).describe("用户的业务需求、输入字段、同步/异步要求和错误行为。只写与本次代码有关的需求。"),
|
|
@@ -28648,7 +28762,10 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28648
28762
|
}
|
|
28649
28763
|
}, "base_url must be an http(s) URL without credentials or control characters").optional().describe("可选的用户服务域名,例如 https://flow.example.com。仅用于输出完整调用地址,会拼接 /flow/codeblock/{{script_id}};不得包含用户名、密码或 Token。")
|
|
28650
28764
|
}
|
|
28651
|
-
}, async ({ mode, requirement, input_example, include_full_schema, base_url }) =>
|
|
28765
|
+
}, async ({ mode, requirement, input_example, include_full_schema, base_url }) => {
|
|
28766
|
+
const context = codeWriterContext(mode, requirement, input_example, include_full_schema ?? false, base_url);
|
|
28767
|
+
return result(mode === "non_script" ? { ...context, execution_url: executionUrl(api2) } : context);
|
|
28768
|
+
});
|
|
28652
28769
|
server.registerTool("flow_list_scripts", {
|
|
28653
28770
|
description: "只读分页查询脚本。默认使用 page/size 偏移分页;需要连续遍历时使用 pagination=cursor,首次不传 cursor,后续使用响应中的游标。不会创建、更新或执行脚本。",
|
|
28654
28771
|
inputSchema: {
|
|
@@ -28699,22 +28816,28 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28699
28816
|
return result(await api2.get(`/flow/scripts/${encodedScriptId(script_id)}/documentation${query}`));
|
|
28700
28817
|
}));
|
|
28701
28818
|
server.registerTool("flow_validate_script_documentation", {
|
|
28702
|
-
description: "
|
|
28819
|
+
description: "只读校验并规范化指定脚本的接口文档,不写入数据库。完整 document、raw_document 和 RFC 6902 document_patch 三选一;补丁必须带 expected_version,响应不会用于发布确认。",
|
|
28703
28820
|
inputSchema: documentationSchema.shape
|
|
28704
28821
|
}, withApiErrors(async (input) => {
|
|
28705
28822
|
const parsed = documentationSchema.parse(input);
|
|
28706
28823
|
if (parsed.document !== undefined) {
|
|
28707
28824
|
assertCompleteInterfaceDoc(parsed.document, "update");
|
|
28708
28825
|
}
|
|
28709
|
-
|
|
28710
|
-
|
|
28826
|
+
if (parsed.document_patch !== undefined)
|
|
28827
|
+
assertInterfaceDocPatch(parsed.document_patch);
|
|
28828
|
+
const validation = parsed.document_patch !== undefined ? await api2.post("/flow/scripts/validate", {
|
|
28829
|
+
script_id: parsed.script_id,
|
|
28830
|
+
expected_version: parsed.expected_version,
|
|
28831
|
+
interface_doc_patch: parsed.document_patch
|
|
28832
|
+
}) : await api2.post(`/flow/scripts/${encodedScriptId(parsed.script_id)}/documentation`, documentationBody(parsed));
|
|
28833
|
+
const document = responseData(validation).document ?? responseData(validation).interface_doc;
|
|
28711
28834
|
if (document === undefined)
|
|
28712
28835
|
throw new Error("Documentation validation response did not include document");
|
|
28713
28836
|
assertCompleteInterfaceDoc(document, "update");
|
|
28714
28837
|
return result(validation);
|
|
28715
28838
|
}));
|
|
28716
28839
|
server.registerTool("flow_preview_script_change", {
|
|
28717
|
-
description: "预览脚本创建或更新,不写数据库。create 必须传 code/code_base64 和完整 interface_doc,且不得传 script_id/expected_version;update 必须传 script_id 和刚读取的 expected_version,修改代码时必须同时传完整 interface_doc。预览成功后只能在用户明确确认时调用 flow_apply_script_change(confirm=true)。",
|
|
28840
|
+
description: "预览脚本创建或更新,不写数据库。create 必须传 code/code_base64 和完整 interface_doc,且不得传 script_id/expected_version;update 必须传 script_id 和刚读取的 expected_version,修改代码时必须同时传完整 interface_doc 或 interface_doc_patch。预览成功后只能在用户明确确认时调用 flow_apply_script_change(confirm=true)。",
|
|
28718
28841
|
inputSchema: changeSchema.shape
|
|
28719
28842
|
}, withApiErrors(async (input) => {
|
|
28720
28843
|
const parsed = changeSchema.parse(input);
|
|
@@ -28727,6 +28850,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28727
28850
|
...parsed.description !== undefined ? { description: parsed.description } : {},
|
|
28728
28851
|
...parsed.ip_whitelist !== undefined ? { ip_whitelist: parsed.ip_whitelist } : {},
|
|
28729
28852
|
...parsed.interface_doc !== undefined ? { interface_doc: parsed.operation === "create" ? removeCreatePath(parsed.interface_doc) : parsed.interface_doc } : {},
|
|
28853
|
+
...parsed.interface_doc_patch !== undefined ? { interface_doc_patch: parsed.interface_doc_patch } : {},
|
|
28730
28854
|
...parsed.rollback_to_version !== undefined ? { rollback_to_version: parsed.rollback_to_version } : {}
|
|
28731
28855
|
};
|
|
28732
28856
|
const expectedVersion = parsed.operation === "update" ? await fetchCurrentVersion(api2, parsed.script_id) : undefined;
|
|
@@ -28735,8 +28859,9 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28735
28859
|
}
|
|
28736
28860
|
const validation = await validateScriptChange(api2, parsed.operation, payload);
|
|
28737
28861
|
const normalized = responseData(validation).interface_doc;
|
|
28738
|
-
if (normalized !== undefined)
|
|
28862
|
+
if (parsed.interface_doc !== undefined && normalized !== undefined)
|
|
28739
28863
|
payload.interface_doc = normalized;
|
|
28864
|
+
const previewValidation = parsed.interface_doc_patch !== undefined ? compactPatchValidation(validation, parsed.interface_doc_patch, expectedVersion) : { valid: true, server_validation: validation };
|
|
28740
28865
|
const previewId = randomUUID();
|
|
28741
28866
|
const storedPreview = previews.put(previewId, "script_change", payload, expectedVersion);
|
|
28742
28867
|
return result({
|
|
@@ -28745,20 +28870,20 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28745
28870
|
expected_version: expectedVersion,
|
|
28746
28871
|
expires_at: new Date(storedPreview.expiresAt).toISOString(),
|
|
28747
28872
|
validation: {
|
|
28748
|
-
|
|
28749
|
-
server_validation: validation
|
|
28873
|
+
...previewValidation
|
|
28750
28874
|
},
|
|
28751
28875
|
changes: {
|
|
28752
28876
|
code: codeBase64 !== undefined,
|
|
28753
28877
|
description: parsed.description !== undefined,
|
|
28754
28878
|
ip_whitelist: parsed.ip_whitelist !== undefined,
|
|
28755
28879
|
interface_doc: parsed.interface_doc !== undefined,
|
|
28880
|
+
interface_doc_patch: parsed.interface_doc_patch !== undefined,
|
|
28756
28881
|
rollback_to_version: parsed.rollback_to_version !== undefined
|
|
28757
28882
|
}
|
|
28758
28883
|
});
|
|
28759
28884
|
}));
|
|
28760
28885
|
server.registerTool("flow_apply_script_change", {
|
|
28761
|
-
description: "应用 flow_preview_script_change 返回的一次性 preview_id。必须传 confirm=true
|
|
28886
|
+
description: "应用 flow_preview_script_change 返回的一次性 preview_id。必须传 confirm=true;工具会再次检查版本并在成功或失败后销毁预览。发布成功时返回由 FLOW_CODEBLOCK_BASE_URL 生成的完整 script_url。不支持删除脚本。版本冲突时重新读取并预览。",
|
|
28762
28887
|
inputSchema: {
|
|
28763
28888
|
preview_id: exports_external.string().uuid().describe("最近一次脚本变更预览返回的 UUID;不能复用过期或已应用的 ID。"),
|
|
28764
28889
|
confirm: exports_external.literal(true).describe("必须为 true,表示用户已明确确认写入。")
|
|
@@ -28774,44 +28899,56 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28774
28899
|
if (actualVersion !== record3.expectedVersion) {
|
|
28775
28900
|
throw new Error(`Script version changed from ${record3.expectedVersion} to ${actualVersion}; read and preview again`);
|
|
28776
28901
|
}
|
|
28902
|
+
if (payload.interface_doc_patch !== undefined) {
|
|
28903
|
+
await validateScriptChange(api2, "update", payload);
|
|
28904
|
+
}
|
|
28777
28905
|
const body = { ...payload };
|
|
28778
28906
|
delete body.script_id;
|
|
28779
28907
|
response = await api2.put(`/flow/scripts/${encodedScriptId(scriptId)}`, body);
|
|
28780
28908
|
} else {
|
|
28781
28909
|
response = await api2.post("/flow/scripts", payload);
|
|
28782
28910
|
}
|
|
28783
|
-
return result(response);
|
|
28911
|
+
return result(withScriptUrl(api2, response, scriptId));
|
|
28784
28912
|
} finally {
|
|
28785
28913
|
previews.delete(preview_id);
|
|
28786
28914
|
}
|
|
28787
28915
|
}));
|
|
28788
28916
|
server.registerTool("flow_preview_script_documentation", {
|
|
28789
|
-
description: "预览接口文档保存,不写数据库。先读取脚本当前版本;document
|
|
28917
|
+
description: "预览接口文档保存,不写数据库。先读取脚本当前版本;document、raw_document 和 document_patch 三选一,补丁必须带 expected_version,完整文档必须包含所有强制字段。成功后只有 flow_apply_script_documentation(confirm=true) 才会写入。",
|
|
28790
28918
|
inputSchema: documentationSchema.shape
|
|
28791
28919
|
}, withApiErrors(async (input) => {
|
|
28792
28920
|
const parsed = documentationSchema.parse(input);
|
|
28793
28921
|
const expectedVersion = await fetchCurrentVersion(api2, parsed.script_id);
|
|
28922
|
+
if (parsed.document_patch !== undefined && parsed.expected_version !== expectedVersion) {
|
|
28923
|
+
throw new Error(`Script version changed from ${parsed.expected_version} to ${expectedVersion}; read and preview again`);
|
|
28924
|
+
}
|
|
28794
28925
|
const rawBody = documentationBody(parsed);
|
|
28795
|
-
const validation = parsed.
|
|
28926
|
+
const validation = parsed.document_patch !== undefined ? await api2.post("/flow/scripts/validate", {
|
|
28927
|
+
script_id: parsed.script_id,
|
|
28928
|
+
expected_version: parsed.expected_version,
|
|
28929
|
+
interface_doc_patch: parsed.document_patch
|
|
28930
|
+
}) : parsed.raw_document !== undefined ? await api2.post(`/flow/scripts/${encodedScriptId(parsed.script_id)}/documentation`, rawBody) : await api2.post("/flow/scripts/validate", {
|
|
28796
28931
|
script_id: parsed.script_id,
|
|
28797
28932
|
interface_doc: rawBody.document
|
|
28798
28933
|
});
|
|
28799
28934
|
const document = responseData(validation).interface_doc ?? responseData(validation).document;
|
|
28800
|
-
if (
|
|
28801
|
-
|
|
28802
|
-
|
|
28935
|
+
if (parsed.document_patch === undefined) {
|
|
28936
|
+
if (document === undefined)
|
|
28937
|
+
throw new Error("Documentation validation response did not include document");
|
|
28938
|
+
assertCompleteInterfaceDoc(document, "update");
|
|
28939
|
+
}
|
|
28803
28940
|
const previewId = randomUUID();
|
|
28804
|
-
const storedPreview = previews.put(previewId, "documentation", { script_id: parsed.script_id, document }, expectedVersion);
|
|
28941
|
+
const storedPreview = previews.put(previewId, "documentation", parsed.document_patch !== undefined ? { script_id: parsed.script_id, expected_version: expectedVersion, document_patch: parsed.document_patch } : { script_id: parsed.script_id, document }, expectedVersion);
|
|
28805
28942
|
return result({
|
|
28806
28943
|
preview_id: previewId,
|
|
28807
28944
|
script_id: parsed.script_id,
|
|
28808
28945
|
expected_version: expectedVersion,
|
|
28809
28946
|
expires_at: new Date(storedPreview.expiresAt).toISOString(),
|
|
28810
|
-
validation: responseData(validation)
|
|
28947
|
+
validation: parsed.document_patch !== undefined ? compactPatchValidation(validation, parsed.document_patch, expectedVersion) : responseData(validation)
|
|
28811
28948
|
});
|
|
28812
28949
|
}));
|
|
28813
28950
|
server.registerTool("flow_apply_script_documentation", {
|
|
28814
|
-
description: "应用 flow_preview_script_documentation 返回的一次性预览。必须传 confirm=true
|
|
28951
|
+
description: "应用 flow_preview_script_documentation 返回的一次性预览。必须传 confirm=true;工具会再次检查脚本版本并在成功或失败后销毁预览。发布成功时返回完整 script_url。版本冲突时重新读取、预览。",
|
|
28815
28952
|
inputSchema: {
|
|
28816
28953
|
preview_id: exports_external.string().uuid().describe("最近一次接口文档预览返回的 UUID;不能复用过期或已应用的 ID。"),
|
|
28817
28954
|
confirm: exports_external.literal(true).describe("必须为 true,表示用户已明确确认写入。")
|
|
@@ -28824,11 +28961,20 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28824
28961
|
if (actualVersion !== record3.expectedVersion) {
|
|
28825
28962
|
throw new Error(`Script version changed from ${record3.expectedVersion} to ${actualVersion}; read and preview again`);
|
|
28826
28963
|
}
|
|
28964
|
+
const patch = record3.payload.document_patch;
|
|
28965
|
+
if (patch !== undefined) {
|
|
28966
|
+
assertInterfaceDocPatch(patch);
|
|
28967
|
+
await api2.post("/flow/scripts/validate", {
|
|
28968
|
+
script_id: scriptId,
|
|
28969
|
+
expected_version: record3.expectedVersion,
|
|
28970
|
+
interface_doc_patch: patch
|
|
28971
|
+
});
|
|
28972
|
+
}
|
|
28827
28973
|
const response = await api2.put(`/flow/scripts/${encodedScriptId(scriptId)}/documentation`, {
|
|
28828
|
-
document: record3.payload.document,
|
|
28974
|
+
...patch !== undefined ? { document_patch: patch } : { document: record3.payload.document },
|
|
28829
28975
|
expected_version: record3.expectedVersion
|
|
28830
28976
|
});
|
|
28831
|
-
return result(response);
|
|
28977
|
+
return result(withScriptUrl(api2, response, scriptId));
|
|
28832
28978
|
} finally {
|
|
28833
28979
|
previews.delete(preview_id);
|
|
28834
28980
|
}
|
|
@@ -28843,7 +28989,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28843
28989
|
server.registerTool("flow_unlock_script", { description: "使用所有者名称和口令正常解锁脚本。必须显式传入 confirm=true;锁定口令不会被 MCP 保存。不提供紧急恢复解锁。", inputSchema: lockSchema }, withApiErrors(async ({ script_id, owner_name, lock_password }) => result(await api2.post(`/flow/scripts/${encodedScriptId(script_id)}/unlock`, { owner_name, lock_password }))));
|
|
28844
28990
|
const queryValueSchema = exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean(), exports_external.array(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()]))]);
|
|
28845
28991
|
server.registerTool("flow_execute_script", {
|
|
28846
|
-
description: "执行已发布脚本,仅用于用户明确要求测试或调用时。method 只能是 GET/POST
|
|
28992
|
+
description: "执行已发布脚本,仅用于用户明确要求测试或调用时。method 只能是 GET/POST;结果包含由 FLOW_CODEBLOCK_BASE_URL 和 script_id 生成的完整 script_url。query 数组会生成重复参数,POST 的 body 作为 JSON 发送。MCP 认证、Cookie、CSRF、代理来源头和测试工具标识会被过滤,qingcodeToken/qingcodeTimeout 不能作为业务参数传入。",
|
|
28847
28993
|
inputSchema: {
|
|
28848
28994
|
script_id: exports_external.string().min(1).describe("已发布脚本 ID;工具会调用 /flow/codeblock/{script_id}。"),
|
|
28849
28995
|
method: exports_external.enum(["GET", "POST"]).default("POST").describe("脚本请求方法,只能是 GET 或 POST;默认 POST。"),
|
|
@@ -28876,12 +29022,10 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28876
29022
|
authenticated: false,
|
|
28877
29023
|
execution: true
|
|
28878
29024
|
});
|
|
28879
|
-
|
|
28880
|
-
requestUrl.search = "";
|
|
28881
|
-
return result({ request_url: requestUrl.toString(), method, response });
|
|
29025
|
+
return result({ script_url: scriptUrl(api2, script_id), method, response });
|
|
28882
29026
|
}));
|
|
28883
29027
|
server.registerTool("flow_execute_code", {
|
|
28884
|
-
description: "执行未发布的非脚本 JavaScript
|
|
29028
|
+
description: "执行未发布的非脚本 JavaScript,仅在用户明确要求测试时使用。结果包含完整 execution_url。请求固定为 POST /flow/codeblock,body.input 原样注入全局 input;代码和 code_base64 二选一。不会把 MCP 认证信息写入用户脚本输入,也不会创建或发布脚本。",
|
|
28885
29029
|
inputSchema: {
|
|
28886
29030
|
code: exports_external.string().min(1).optional().describe("UTF-8 JavaScript 源码,与 code_base64 二选一。"),
|
|
28887
29031
|
code_base64: exports_external.string().min(1).optional().describe("JavaScript 源码的非空 Base64,与 code 二选一。"),
|
|
@@ -28897,6 +29041,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28897
29041
|
};
|
|
28898
29042
|
return result({
|
|
28899
29043
|
mode: "non_script",
|
|
29044
|
+
execution_url: executionUrl(api2),
|
|
28900
29045
|
response: await api2.request("/flow/codeblock", {
|
|
28901
29046
|
method: "POST",
|
|
28902
29047
|
body: JSON.stringify(body),
|