flow-codeblock-rust-mcp 0.1.3 → 0.1.4

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.
Files changed (3) hide show
  1. package/README.md +22 -22
  2. package/dist/index.js +136 -125
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,32 +1,32 @@
1
1
  # flow-codeblock-rust-mcp
2
2
 
3
- Flow Codeblock Rust+Bun 的本地 stdio MCP Server。它只调用服务端 Rust REST API,不在用户电脑执行脚本;用户 JavaScript 仍由服务端 Bun 执行器运行。
3
+ Local stdio MCP server for Flow Codeblock Rust+Bun. It calls the server-side Rust REST API and never executes scripts on the user's machine; user JavaScript runs in the server-side Bun executor.
4
4
 
5
- ## 安装和启动
5
+ ## Installation and startup
6
6
 
7
- 需要 Bun 1.4.0 或更高版本:
7
+ Bun 1.4.0 or newer is required:
8
8
 
9
9
  ```bash
10
- bunx --bun flow-codeblock-rust-mcp@0.1.3
10
+ bunx --bun flow-codeblock-rust-mcp@0.1.4
11
11
  ```
12
12
 
13
- 配置环境变量:
13
+ Configure the environment:
14
14
 
15
15
  ```bash
16
16
  export FLOW_CODEBLOCK_BASE_URL=http://127.0.0.1:3003
17
17
  export FLOW_CODEBLOCK_TOKEN='<YOUR_INTERNAL_ACCESS_TOKEN>'
18
18
  ```
19
19
 
20
- `FLOW_CODEBLOCK_TOKEN` 是当前 Flow Codeblock 服务的内部访问令牌。生产部署应使用 HTTPS 地址,不要将真实 Token 写入仓库、npm 包、命令行历史或公开客户端配置。
20
+ `FLOW_CODEBLOCK_TOKEN` is the internal access token for the current Flow Codeblock service. Use HTTPS in production and never put a real token in the repository, npm package, shell history, or public client configuration.
21
21
 
22
- ## stdio 配置
22
+ ## Stdio configuration
23
23
 
24
24
  ```json
25
25
  {
26
26
  "mcpServers": {
27
27
  "flow-codeblock-rust": {
28
28
  "command": "bunx",
29
- "args": ["--bun", "flow-codeblock-rust-mcp@0.1.3"],
29
+ "args": ["--bun", "flow-codeblock-rust-mcp@0.1.4"],
30
30
  "env": {
31
31
  "FLOW_CODEBLOCK_BASE_URL": "https://flow.example.com",
32
32
  "FLOW_CODEBLOCK_TOKEN": "<YOUR_INTERNAL_ACCESS_TOKEN>"
@@ -36,28 +36,28 @@ export FLOW_CODEBLOCK_TOKEN='<YOUR_INTERNAL_ACCESS_TOKEN>'
36
36
  }
37
37
  ```
38
38
 
39
- ## 工具边界
39
+ ## Tool boundaries
40
40
 
41
- 代码契约使用当前 Rust+Bun 模块白名单:`crypto-js` 已移除,加密应使用 `node:crypto`。Excel 仅允许 `read-excel-file/node`、`read-excel-file/universal`、`write-excel-file/node`、`write-excel-file/universal` `write-excel-file/utility` 入口;这些模块由服务端共享重型执行池承载。
41
+ The code contract follows the current Rust+Bun module allowlist. `crypto-js` has been removed; use `node:crypto` for cryptography. Excel imports are limited to `read-excel-file/node`, `read-excel-file/universal`, `write-excel-file/node`, `write-excel-file/universal`, and `write-excel-file/utility`; these modules run in the server's shared heavy execution pool.
42
42
 
43
- 工具覆盖代码生成、未发布代码测试、脚本列表、版本读取、接口文档校验/预览/保存、脚本创建/更新、锁定/解锁和已发布脚本执行。创建或代码更新可提交完整接口文档或 RFC 6902 `interface_doc_patch`;预览会调用 `/flow/scripts/validate`,应用时会再次透传补丁并使用事务级 `expected_version` 检测并发冲突。所有脚本写操作需要预览后显式 `confirm: true`。
43
+ The tools cover code-contract generation, unpublished-code tests, script listing, version reads, documentation validation/preview/save, script creation/update, locking/unlocking, and published-script execution. Creates and code updates can submit a complete interface document or RFC 6902 `interface_doc_patch`; preview calls `/flow/scripts/validate`, and apply re-submits patches with transactional `expected_version` conflict detection. Every script write requires a preview and explicit `confirm: true`.
44
44
 
45
- 最终用户交付按模式区分:`non_script` 输出完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和完整 `execution_url`;`script` 默认不主动回显 JavaScript 或原始 `interface_doc`,只输出接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的完整 `script_url`。脚本代码与 `interface_doc` 仍由 MCP 内部用于预览、校验和发布,除非用户明确索要源码或原始文档。
45
+ Final delivery is mode-specific. `non_script` returns complete JavaScript, invocation instructions, request parameters and examples, execution logic, success/error examples, and a complete `execution_url`. `script` omits JavaScript and raw `interface_doc` by default and returns invocation instructions, request parameters and examples, execution logic, success/error examples, and the published `script_url`. Script code and `interface_doc` remain internal inputs to MCP preview, validation, and publication unless the user explicitly requests source or raw documentation.
46
46
 
47
- MCP 不提供脚本删除、紧急恢复解锁、Token 查询、执行统计、所有权转移或任意 HTTP 代理工具。当前版本只提供本地 stdio 连接,不提供远程 HTTPSSE Streamable HTTP 连接。
47
+ MCP does not provide script deletion, emergency recovery unlock, token lookup, execution statistics, ownership transfer, or arbitrary HTTP proxy tools. This release provides local stdio only; it does not expose remote HTTP, SSE, or Streamable HTTP transports.
48
48
 
49
- ## MCP 工具契约
49
+ ## MCP tool contract
50
50
 
51
- 服务器初始化时会通过 MCP `instructions` 下发完整的工具选择、脚本预览/确认流程、代码运行时约束和接口文档规则,因此不依赖额外 Skill 也可以直接调用工具。客户端应优先使用工具 description input schema 中的字段说明,不要通过试错猜测参数。
51
+ At initialization the server sends complete tool selection, preview/confirmation, runtime, and interface-documentation rules through MCP `instructions`. Clients should prefer tool descriptions and input-schema field descriptions instead of guessing parameters through trial and error.
52
52
 
53
- 接口文档必须包含 `schema_version`、`title`、`summary`、`endpoint`、`request`、`responses`、`logic_description`;`endpoint` 必须有 `methods` `description`,`request.query` `request.headers` 必须存在(没有参数时传 `[]`)。POST 还必须提供 `request.body`,其 `content_type`、`schema`、`example` 均必填;每个响应的 `status`、`description`、`content_type`、`schema`、`example` 均必填;查询参数和请求头的每个字段必须有 `name`、`type`、`required`、`description`、`example`。
53
+ Interface documents must include `schema_version`, `title`, `summary`, `endpoint`, `request`, `responses`, and `logic_description`. `endpoint` requires `methods` and `description`; `request.query` and `request.headers` must exist (use `[]` when empty). POST documents also require `request.body` with `content_type`, `schema`, and `example`. Every response requires `status`, `description`, `content_type`, `schema`, and `example`; every query/header parameter requires `name`, `type`, `required`, `description`, and `example`.
54
54
 
55
- 接口文档的 `endpoint.path` 使用相对路径:创建时省略,更新时使用 `/flow/codeblock/<实际脚本ID>`。对外展示完整请求地址时,将用户提供的服务域名与 `/flow/codeblock/{{脚本ID}}` 拼接;不要把真实令牌、密码、Cookie Authorization 值写入代码、文档、示例或 URL。
55
+ `endpoint.path` is relative: omit it when creating and use `/flow/codeblock/<actual-script-id>` when updating. Public request URLs combine the caller-provided service origin with `/flow/codeblock/{{script_id}}`. Never put real tokens, passwords, cookies, or Authorization values in code, documents, examples, or URLs.
56
56
 
57
- `interface_doc_patch` / `document_patch` 必须携带正整数 `expected_version`,最多 256 `add/remove/replace/move/copy/test` 操作。补丁预览仅返回操作数量、JSON Pointer 路径、警告和版本信息,不返回完整合并文档。
57
+ `interface_doc_patch` and `document_patch` require a positive integer `expected_version` and support at most 256 `add/remove/replace/move/copy/test` operations. Patch previews return operation counts, JSON Pointer paths, warnings, and version information, never the complete merged document.
58
58
 
59
- ## 安全行为
59
+ ## Security behavior
60
60
 
61
- - 管理请求使用 `Authorization: Bearer`,执行已发布脚本时不会把 MCP Token 转发到脚本输入。
62
- - 用户传入的 AuthorizationaccessTokenCookieCSRF、测试工具标识和 `Forwarded`/`X-Real-IP`/`X-Forwarded-*` 等代理来源头会被过滤。
63
- - 请求有 30 秒超时,预览有 10 分钟 TTL 256 条上限。
61
+ - Management requests use `Authorization: Bearer`; the MCP token is not forwarded into published-script input.
62
+ - User-supplied Authorization, accessToken, Cookie, CSRF, test-tool, MCP, `Forwarded`, `X-Real-IP`, and `X-Forwarded-*` headers are filtered.
63
+ - Requests have a 30-second timeout; previews have a 10-minute TTL and a 256-entry limit.
package/dist/index.js CHANGED
@@ -27901,7 +27901,7 @@ 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 文档的索引。");
27904
+ var patchPathSchema = exports_external.string().describe("RFC 6901 JSON Pointer path; array paths use indexes from the current canonical document.");
27905
27905
  var interfaceDocPatchOperationSchema = exports_external.union([
27906
27906
  exports_external.object({ op: exports_external.literal("add"), path: patchPathSchema, value: exports_external.unknown() }).strict(),
27907
27907
  exports_external.object({ op: exports_external.literal("remove"), path: patchPathSchema }).strict(),
@@ -27914,7 +27914,7 @@ var interfaceDocPatchOperationSchema = exports_external.union([
27914
27914
  context.addIssue({ code: "custom", path: ["value"], message: "value is required for this operation" });
27915
27915
  }
27916
27916
  });
27917
- var interfaceDocPatchSchema = exports_external.array(interfaceDocPatchOperationSchema).min(1).max(256).describe("RFC 6902 JSON Patch 操作数组;按顺序应用,不能与完整 interface_doc 同时提供。");
27917
+ var interfaceDocPatchSchema = exports_external.array(interfaceDocPatchOperationSchema).min(1).max(256).describe("RFC 6902 JSON Patch operation array; operations are applied in order and cannot be provided with a complete interface_doc.");
27918
27918
  var interfaceDocPatchJsonSchema = {
27919
27919
  $schema: "https://json-schema.org/draft/2020-12/schema",
27920
27920
  $id: "https://flow-codeblock.local/schemas/script-interface-doc.patch.v1.json",
@@ -27937,7 +27937,7 @@ var interfaceDocPatchJsonSchema = {
27937
27937
  function assertInterfaceDocPatch(patch) {
27938
27938
  const parsed = interfaceDocPatchSchema.safeParse(patch);
27939
27939
  if (!parsed.success)
27940
- throw new Error(`interface_doc_patch 格式无效: ${parsed.error.message}`);
27940
+ throw new Error(`Invalid interface_doc_patch format: ${parsed.error.message}`);
27941
27941
  }
27942
27942
  function isObject2(value) {
27943
27943
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -28177,7 +28177,7 @@ var interfaceDocSchema = {
28177
28177
  path: {
28178
28178
  type: "string",
28179
28179
  pattern: "^/flow/codeblock/",
28180
- description: "相对路径;创建时可省略,更新时必须为 /flow/codeblock/<实际脚本ID>。完整地址另行拼接调用方提供的域名。"
28180
+ description: "Relative path; omit it when creating a script, and use /flow/codeblock/<actual-script-id> when updating one. The complete URL is built separately from the caller-provided domain."
28181
28181
  },
28182
28182
  description: { type: "string", minLength: 1, maxLength: 4000 }
28183
28183
  }
@@ -28273,22 +28273,22 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
28273
28273
  result_bytes: 10 * 1024 * 1024
28274
28274
  },
28275
28275
  code_rules: [
28276
- "所有业务数据只从全局 input 读取,不从环境变量、持久化全局变量或其他外部状态读取;返回值必须可 JSON 序列化。",
28277
- "默认使用顶层 return;只有事件式/异步流程或用户明确要求时才使用 qf_output,且必须是裸的 qf_output = { ... } 对象字面量赋值,不能与顶层 return 混用,也不能遮蔽该标识符。",
28278
- "优先标准 JavaScript、服务端原生 fetch node:crypto;只有原生能力确实无法满足且用户明确要求时,才使用白名单 CommonJS 字面量 requirecrypto-js 已移除,不得生成该模块调用。",
28279
- "禁止 import/export、动态 require、浏览器 API、定时器、阻止标识符、阻止成员和黑名单 Node 模块,不得写入真实凭据。",
28280
- "业务逻辑和异步操作放在 try-catch 中;错误转换为字符串或普通对象后返回。",
28281
- "不得创建无界循环、未 settle Promise 或执行结束后仍运行的后台任务;所有请求必须 await return。",
28282
- "外部 URL、请求头、查询参数和请求体必须校验类型、长度和允许范围;HTTP 响应检查状态并按 JSON、文本、空响应分别处理。"
28276
+ "Read all business data from the global input only; do not read environment variables, persistent globals, or other external state. Return values must be JSON-serializable.",
28277
+ "Use top-level return by default. Use qf_output only for event-style/asynchronous flows or when explicitly requested, and assign it as a bare qf_output = { ... } object literal. Never mix it with top-level return or shadow the identifier.",
28278
+ "Prefer standard JavaScript, server-side fetch, and node:crypto. Use a whitelisted CommonJS literal require only when native capabilities cannot meet the requirement and the user explicitly requests it. crypto-js has been removed and must not be generated.",
28279
+ "Do not use import/export, dynamic require, browser APIs, timers, forbidden identifiers or members, or blacklisted Node modules. Never write real credentials.",
28280
+ "Put business logic and asynchronous operations in try-catch; return errors as strings or plain objects.",
28281
+ "Do not create unbounded loops, unsettled Promises, or background tasks that outlive execution; every request must be awaited or returned.",
28282
+ "Validate external URLs, headers, query parameters, and request bodies for type, length, and allowed ranges. Check HTTP status and handle JSON, text, and empty responses separately."
28283
28283
  ],
28284
28284
  async_lifecycle: [
28285
- "禁止 setTimeoutsetIntervalsetImmediate、轮询、延迟和后台重试。",
28286
- "请求必须在执行超时内完成,不能遗留未等待的 fetch"
28285
+ "Do not use setTimeout, setInterval, setImmediate, polling, delays, or background retries.",
28286
+ "Requests must finish within the execution timeout; do not leave fetch operations unawaited."
28287
28287
  ],
28288
28288
  require_policy: {
28289
- allowed_call_form: "仅允许单个字符串字面量 require('模块名'),不得间接调用、动态模块名或使用 import/export",
28290
- dayjs_exception: "日期处理优先原生 Date;复杂日期解析/格式化/时区才允许使用 dayjs",
28291
- other_modules: " dayjs 外,只有原生能力确实无法实现且用户明确要求时才允许白名单模块;Excel 仅允许 read-excel-file/noderead-excel-file/universalwrite-excel-file/nodewrite-excel-file/universal write-excel-file/utility"
28289
+ allowed_call_form: "Only a single string-literal require('module-name') call is allowed; indirect calls, dynamic module names, and import/export are forbidden.",
28290
+ dayjs_exception: "Prefer the native Date API for date handling; use dayjs only for complex date parsing, formatting, or time-zone work.",
28291
+ other_modules: "Except for dayjs, use a whitelisted module only when native capabilities cannot implement the requirement and the user explicitly requests it. Excel is limited to read-excel-file/node, read-excel-file/universal, write-excel-file/node, write-excel-file/universal, and write-excel-file/utility."
28292
28292
  },
28293
28293
  forbidden: {
28294
28294
  identifiers: [
@@ -28351,8 +28351,8 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
28351
28351
  ]
28352
28352
  },
28353
28353
  output_rules: [
28354
- "返回值只能是普通可序列化值或 Promise;禁止循环引用、BigInt、函数、Symbol、未处理的复杂类实例及无界数组/字符串。",
28355
- "平台会把即时接口返回值放入外层 HTTP 响应的 result 字段;脚本接口通常直接返回业务值。推荐 { success: true, data: value } { success: false, error: message }"
28354
+ "Return only plain serializable values or Promises; do not return circular references, BigInt, functions, Symbols, unhandled complex class instances, or unbounded arrays/strings.",
28355
+ "The platform places immediate-interface return values in the outer HTTP response's result field; script interfaces usually return the business value directly. Prefer { success: true, data: value } or { success: false, error: message }."
28356
28356
  ],
28357
28357
  allowed_modules: allowedModules
28358
28358
  };
@@ -28362,19 +28362,19 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
28362
28362
  input_contract: {
28363
28363
  method: "POST",
28364
28364
  path: "/flow/codeblock",
28365
- rule: "请求体中的 input 原样注入全局 input,缺省为 {};平台请求体可包含 codebase64inputqingcodeTimeout",
28365
+ rule: "The request body's input is injected unchanged as global input and defaults to {}; the platform body may contain codebase64, input, and qingcodeTimeout.",
28366
28366
  example: { codebase64: "<base64 JavaScript>", input: inputExample ?? {} }
28367
28367
  },
28368
28368
  generation_decisions: [
28369
- "用户未说明时生成即时执行的非脚本模式。",
28370
- "如果需求包含 HTTP 重定向,必须改用 script 模式 /flow/codeblock/{{script_id}}"
28369
+ "Generate immediate non_script mode when the user does not specify a mode.",
28370
+ "If the requirement includes an HTTP redirect, use script mode with /flow/codeblock/{{script_id}}."
28371
28371
  ],
28372
- deliverables: ["只含可执行 JavaScript javascript 代码块", "输入和输出契约"],
28372
+ deliverables: ["A javascript code block containing executable JavaScript only", "Input and output contracts"],
28373
28373
  test_tool: { name: "flow_execute_code", arguments: { code: "<JavaScript>", input: inputExample ?? {}, timeout_ms: 3000 } },
28374
- rule: "除非用户明确要求测试,否则不要调用 flow_execute_code",
28374
+ rule: "Do not call flow_execute_code unless the user explicitly requests a test.",
28375
28375
  response_format: [
28376
- "除非用户明确要求只返回代码,否则先说明模式和输出方式,再给 JavaScript 代码块,最后给请求/响应示例。",
28377
- "非脚本接口交付完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和 execution_url"
28376
+ "Unless the user explicitly requests code only, explain the mode and output first, then provide the JavaScript code block, followed by request/response examples.",
28377
+ "For non_script interfaces, deliver complete JavaScript, invocation instructions, request parameters and examples, execution logic, success/error output examples, and execution_url."
28378
28378
  ]
28379
28379
  };
28380
28380
  }
@@ -28387,25 +28387,25 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
28387
28387
  endpoint: "GET|POST /flow/codeblock/{{script_id}}",
28388
28388
  shape: { query: {}, header: {}, body: {}, cookies: {} },
28389
28389
  mapping: {
28390
- query: "input.query;单值为字符串,重复参数为字符串数组;不含 qingcodeToken/qingcodeTimeout",
28391
- headers: "input.header;服务端过滤 x-original-cookie,需要 Cookie 时使用 cookie。",
28392
- body: "input.bodyPOST JSON 请求体,空请求体为 {};业务数据直接发送,不包装为 input input.body",
28393
- cookies: "input.cookies;Cookie 键值对象,无 Cookie 时可能不存在。"
28390
+ query: "input.query; a single value is a string and repeated parameters are string arrays; do not include qingcodeToken or qingcodeTimeout.",
28391
+ headers: "input.header; the server filters x-original-cookie; use cookie when a Cookie value is needed.",
28392
+ body: "input.body; POST JSON request body, defaulting to {}; send business data directly without wrapping it as input or input.body.",
28393
+ cookies: "input.cookies; a cookie name/value object that may be absent when no cookies are supplied."
28394
28394
  },
28395
28395
  reserved_query: ["qingcodeToken", "qingcodeTimeout"]
28396
28396
  },
28397
28397
  endpoint_url_template: normalizedBaseUrl ? `${normalizedBaseUrl}${endpointPathTemplate}` : endpointPathTemplate,
28398
- endpoint_url_rule: "提供域名时,输出该域名 + /flow/codeblock/{{script_id}};URL 中不得包含凭据。",
28398
+ endpoint_url_rule: "When a domain is provided, output that domain plus /flow/codeblock/{{script_id}}; URLs must not contain credentials.",
28399
28399
  internal_artifacts: [
28400
- "只含可执行代码的 JavaScript 代码块(提交预览、校验和发布;默认不回显)",
28401
- "独立且完整的 script-interface-doc.v1 JSON 对象(提交预览、校验和发布;默认不回显)"
28400
+ "A JavaScript code block containing executable code only (submitted for preview, validation, and publication; not echoed by default)",
28401
+ "A standalone complete script-interface-doc.v1 JSON object (submitted for preview, validation, and publication; not echoed by default)"
28402
28402
  ],
28403
28403
  final_deliverables: [
28404
- "接口调用说明",
28405
- "请求参数及示例",
28406
- "执行逻辑",
28407
- "成功/错误输出示例",
28408
- "发布后的完整 script_url"
28404
+ "Invocation instructions",
28405
+ "Request parameters and examples",
28406
+ "Execution logic",
28407
+ "Success/error output examples",
28408
+ "The complete published script_url"
28409
28409
  ],
28410
28410
  interface_doc_contract: {
28411
28411
  strict_preview_gate: true,
@@ -28415,26 +28415,26 @@ function codeWriterContext(mode, requirement, inputExample, includeFullSchema, b
28415
28415
  full_json_schema: includeFullSchema ? interfaceDocSchema : undefined,
28416
28416
  patch_json_schema: includeFullSchema ? interfaceDocPatchJsonSchema : undefined,
28417
28417
  separation: [
28418
- "javascript 代码块只含可执行代码,不写接口文档注释。",
28419
- "json 代码块只含一个合法 script-interface-doc.v1 对象,不混入 Markdown、注释或尾随逗号。"
28418
+ "The javascript code block must contain executable code only and no interface-documentation comments.",
28419
+ "The json code block must contain exactly one valid script-interface-doc.v1 object, with no Markdown, comments, or trailing commas."
28420
28420
  ]
28421
28421
  },
28422
28422
  redirect_contract: {
28423
- rule: "只有脚本接口解析 flow_redirect_url/flow_redirect_code;即时接口把它们作为普通结果。",
28424
- url: "flow_redirect_url 必须是单斜杠相对路径或带主机的 http/https URL,不得含空白或控制字符。",
28425
- code: "flow_redirect_code 只能是 301302303307308 或对应数字字符串。"
28423
+ rule: "Only script interfaces interpret flow_redirect_url and flow_redirect_code; immediate interfaces return them as ordinary result fields.",
28424
+ url: "flow_redirect_url must be a single-slash relative path or an http/https URL with a host, without whitespace or control characters.",
28425
+ code: "flow_redirect_code must be 301, 302, 303, 307, or 308, as a number or numeric string."
28426
28426
  },
28427
28427
  workflow: [
28428
- "如果是更新,先调用 flow_get_script 读取当前版本;更新文档可先调用 flow_get_script_documentation",
28429
- "代码和完整 interface_doc 一起生成;创建或代码更新只调用一次 flow_preview_script_change",
28430
- "仅在用户明确确认后调用 flow_apply_script_change flow_apply_script_documentation,并传 confirm=true",
28431
- "只有用户要求测试已发布脚本时才调用 flow_execute_script;仅测试未发布代码时调用 flow_execute_code",
28432
- "版本冲突、预览过期或校验失败时停止并重新读取、重新预览,不重试旧 preview_id"
28428
+ "For updates, call flow_get_script first to read the current version; for documentation updates, flow_get_script_documentation may be called first.",
28429
+ "Generate code and a complete interface_doc together; call flow_preview_script_change once for a create or code update.",
28430
+ "Call flow_apply_script_change or flow_apply_script_documentation only after explicit user confirmation, with confirm=true.",
28431
+ "Call flow_execute_script only when the user requests a test of a published script; call flow_execute_code only to test unpublished code.",
28432
+ "On a version conflict, expired preview, or validation failure, stop and read/preview again; never retry an old preview_id."
28433
28433
  ],
28434
28434
  response_format: [
28435
- "脚本模式默认不回显 JavaScript 或原始 interface_doc;只展示接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的 script_url,除非用户明确索要源码或原始文档。",
28436
- "脚本代码与 interface_doc 仍必须在内部提交给预览、校验和发布工具。",
28437
- "说明请求参数、主要业务行为、响应和错误处理,并提供与模式匹配的 HTTP 方法、路径、Headers/Query/Body/Cookie 和响应示例。"
28435
+ "Script mode does not echo JavaScript or the raw interface_doc by default; show invocation instructions, request parameters and examples, execution logic, success/error output examples, and the published script_url unless the user explicitly asks for source or raw documentation.",
28436
+ "Script code and interface_doc must still be submitted internally to the preview, validation, and publication tools.",
28437
+ "Describe request parameters, primary business behavior, responses, and error handling, with HTTP method, path, Headers/Query/Body/Cookie, and response examples matching the selected mode."
28438
28438
  ]
28439
28439
  };
28440
28440
  }
@@ -28502,18 +28502,18 @@ var result = (value) => ({
28502
28502
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
28503
28503
  });
28504
28504
  var serverInstructions = [
28505
- "这是 Flow Codeblock Rust+Bun MCP Server。除 flow_write_code 外,工具直接调用服务端 REST APIflow_write_code 只返回生成契约。不要猜测 REST 路径,也不要把 MCP 内部令牌放入业务参数。",
28506
- "代码运行于服务端 Bun 异步函数上下文,支持现代 JavaScriptasync/await、Promise、箭头函数和顶层 return;默认最小超时 100ms、最大超时 15000ms,代码 65535 字节、输入 2MiB、结果 10MiB。",
28507
- "工具选择:flow_write_code 只生成代码与契约,不执行、不写库;flow_execute_code 只用于用户明确要求的未发布非脚本测试;flow_execute_script 只执行已发布脚本。",
28508
- "脚本读取、创建和更新流程:更新前先 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",
28509
- "预览 ID 是一次性且有时效的;版本冲突、预览过期或校验失败时停止,重新读取并预览,不要重试旧 preview_idflow_apply_* 永远需要 confirm=true",
28510
- "script-interface-doc.v1 必须包含 schema_versiontitlesummaryendpointrequestresponseslogic_descriptionendpoint 必须包含 methods descriptionrequest.queryrequest.headers 必须存在(没有参数用 []);POST 必须有 request.bodyGET-only 必须省略。增量文档使用最多 256 项的 add/remove/replace/move/copy/test JSON Patch,预览只回显操作数量和路径,不回显合并文档。",
28511
- "查询参数和请求头的每一项必须有 nametyperequireddescriptionexample。请求体和每个响应必须有 content_type=application/jsonschemaexample;每个响应还必须有 statusdescriptionJSON Schema 的每个节点必须声明 type,数组必须有 items,对象和 example 必须互相覆盖。",
28512
- "接口文档 endpoint.path 只写相对路径:创建时省略,更新时写 /flow/codeblock/<实际脚本ID>。对外展示的完整调用地址必须使用用户提供的域名拼接 /flow/codeblock/{{脚本ID}};不要把真实 Token、密码、Cookie Authorization 值写入代码、文档、示例或 URL。",
28513
- "脚本模式输入来自 input.queryinput.headerinput.bodyinput.cookies;即时非脚本模式 POST /flow/codeblock body.input 原样成为全局 input。代码默认使用顶层 return;只有事件式/异步流程或用户明确要求时才使用裸 qf_output 赋值,不能混用。",
28514
- "最终用户交付按模式区分:non_script 输出完整 JavaScript、接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和完整 execution_url;script 默认不主动回显 JavaScript 或原始 interface_doc,只输出接口调用说明、请求参数及示例、执行逻辑、成功/错误输出示例和发布后的完整 script_url,除非用户明确索要源码或原始文档。script 的代码与 interface_doc 仍必须内部提交给预览、校验和发布工具。",
28515
- "优先原生 JavaScriptURL/URLSearchParamsfetch node:cryptocrypto-js 已移除,禁止生成该模块调用。禁止浏览器 API、定时器、动态模块加载、黑名单 Node 模块和危险标识符。Excel 仅允许 read-excel-file/noderead-excel-file/universalwrite-excel-file/nodewrite-excel-file/universal write-excel-file/utilityHTTP 请求必须检查状态并处理 JSON/文本/空响应,所有异步任务必须显式 await return",
28516
- "执行脚本时 method 只能是 GET POSTMCP 认证、Cookie、CSRF、代理来源头和测试工具标识会被过滤。不要使用删除脚本、紧急恢复解锁或任意 HTTP 代理能力,本 MCP 不提供这些工具。"
28505
+ "This is the Flow Codeblock Rust+Bun MCP server. All tools except flow_write_code call the server-side REST API; flow_write_code returns an authoring contract only. Do not guess REST paths or put MCP credentials in business arguments.",
28506
+ "User code runs in a server-side Bun async function context with modern JavaScript, async/await, Promises, arrow functions, and top-level return. Default limits are 100 ms minimum timeout, 15,000 ms maximum timeout, 65,535 code bytes, 2 MiB input, and 10 MiB result.",
28507
+ "Tool routing: flow_write_code only generates code and its contract; flow_execute_code is for explicitly requested tests of unpublished non-script code; flow_execute_script runs only published scripts.",
28508
+ "Script workflow: read the current version with flow_get_script before updates; creates require a complete interface_doc, while code or document updates may use a complete interface_doc or an RFC 6902 interface_doc_patch (never both, and patches require expected_version). Preview with flow_preview_script_change, then call flow_apply_script_change(confirm=true) only after explicit user confirmation. Documentation-only changes use flow_preview_script_documentation -> flow_apply_script_documentation.",
28509
+ "Preview IDs are single-use and time-limited. On a version conflict, expired preview, or validation failure, stop, read again, and preview again; never retry an old preview_id. Every flow_apply_* call requires confirm=true.",
28510
+ "script-interface-doc.v1 requires schema_version, title, summary, endpoint, request, responses, and logic_description. endpoint requires methods and description; request.query and request.headers are required arrays (use [] when empty); POST requires request.body and GET-only documents must omit it. JSON Patch supports at most 256 add/remove/replace/move/copy/test operations; preview responses show operation counts and paths, not merged documents.",
28511
+ "Every query parameter and request header requires name, type, required, description, and example. Request bodies and responses require content_type=application/json, schema, and example; every response also requires status and description. Every JSON Schema node declares type, and object schemas and examples must cover each other.",
28512
+ "Keep endpoint.path relative: omit it on create and use /flow/codeblock/<actual-script-id> on update. Public call URLs use the caller-provided domain plus /flow/codeblock/{{script_id}}; never put real tokens, passwords, cookies, or Authorization values in code, documents, examples, or URLs.",
28513
+ "Script input comes from input.query, input.header, input.body, and input.cookies; for immediate non-script POST /flow/codeblock, body.input becomes global input unchanged. Use top-level return by default; use a bare qf_output assignment only for event-style/asynchronous flows or when explicitly requested, never both.",
28514
+ "Non-script delivery includes complete JavaScript, caller-facing invocation instructions, parameters/examples, logic, success/error examples, and execution_url. Script delivery omits JavaScript and raw interface_doc by default and includes invocation instructions, parameters/examples, logic, success/error examples, and the published script_url unless the user asks for source or raw documentation. Code and interface_doc remain internal preview/validation/publication inputs.",
28515
+ "Prefer native JavaScript, URL/URLSearchParams, fetch, and node:crypto; crypto-js has been removed. Do not generate browser APIs, timers, dynamic module loading, blacklisted Node modules, or dangerous identifiers. Excel imports are limited to read-excel-file/node, read-excel-file/universal, write-excel-file/node, write-excel-file/universal, and write-excel-file/utility. Check HTTP status and handle JSON, text, and empty responses; await or return every async task.",
28516
+ "Script execution accepts only GET or POST. MCP authentication, cookies, CSRF, proxy-source headers, and test-tool markers are filtered. There is no script deletion, emergency unlock, or arbitrary HTTP proxy tool; direct those requests to the web UI or controlled REST/operations flow."
28517
28517
  ].join(`
28518
28518
  `);
28519
28519
  function encodedScriptId(scriptId) {
@@ -28614,26 +28614,26 @@ function withApiErrors(handler) {
28614
28614
  };
28615
28615
  }
28616
28616
  var documentationFields = {
28617
- document: exports_external.unknown().optional().describe(`规范化的 script-interface-doc.v1 JSON 对象。与 raw_documentdocument_patch 三选一;保存或代码更新时必须完整。${interfaceDocInputDescription}`),
28618
- raw_document: exports_external.string().optional().describe("待服务端解析的 JSON/OpenAPI 文档文本。与 documentdocument_patch 三选一;format=json 时按 JSON 解析。"),
28619
- format: exports_external.literal("json").optional().describe("raw_document 的格式,目前只支持 json"),
28620
- document_patch: interfaceDocPatchSchema.optional().describe("仅已有脚本使用的 RFC 6902 增量补丁;与 documentraw_document 三选一。"),
28621
- expected_version: exports_external.number().int().positive().optional().describe("补丁的当前脚本版本;提交补丁时必填,必须来自刚读取的当前版本。")
28617
+ document: exports_external.unknown().optional().describe(`Normalized script-interface-doc.v1 JSON. Choose exactly one of document, raw_document, or document_patch; complete documents are required for saves and code updates. ${interfaceDocInputDescription}`),
28618
+ raw_document: exports_external.string().optional().describe("JSON/OpenAPI document text for server parsing. Choose exactly one of document, raw_document, or document_patch; format=json parses JSON."),
28619
+ format: exports_external.literal("json").optional().describe("Format of raw_document; only json is supported."),
28620
+ document_patch: interfaceDocPatchSchema.optional().describe("RFC 6902 patch for an existing script only. Choose exactly one of document, raw_document, or document_patch."),
28621
+ expected_version: exports_external.number().int().positive().optional().describe("Current script version for a patch; required with document_patch and must come from a fresh current-version read.")
28622
28622
  };
28623
28623
  var changeSchema = exports_external.object({
28624
- operation: exports_external.enum(["create", "update"]).describe("create 创建脚本;update 更新已有脚本。"),
28625
- script_id: exports_external.string().min(1).optional().describe("更新目标脚本 IDcreate 不得传入。"),
28626
- code: exports_external.string().optional().describe("UTF-8 JavaScript 源码,与 code_base64 二选一。创建或修改代码时必填;代码只包含可执行 JavaScript"),
28627
- code_base64: exports_external.string().optional().describe("JavaScript 源码的非空 Base64,与 code 二选一。"),
28628
- description: exports_external.string().optional().describe("脚本说明。可在不改代码时单独更新。"),
28629
- ip_whitelist: exports_external.array(exports_external.string()).nullable().optional().describe("来源 IP/CIDR 白名单。省略表示更新时保持原值;null [] 表示清除限制。"),
28624
+ operation: exports_external.enum(["create", "update"]).describe("create adds a script; update changes an existing script."),
28625
+ script_id: exports_external.string().min(1).optional().describe("Target script ID for update; forbidden for create."),
28626
+ code: exports_external.string().optional().describe("UTF-8 JavaScript source, mutually exclusive with code_base64. Required when creating or changing code; provide executable JavaScript only."),
28627
+ code_base64: exports_external.string().optional().describe("Non-empty Base64-encoded JavaScript, mutually exclusive with code."),
28628
+ description: exports_external.string().optional().describe("Script description. Can be updated without changing code."),
28629
+ ip_whitelist: exports_external.array(exports_external.string()).nullable().optional().describe("Source IP/CIDR allowlist. Omit on update to keep the current value; null or [] clears the restriction."),
28630
28630
  interface_doc: exports_external.unknown().optional().describe(interfaceDocInputDescription),
28631
- interface_doc_patch: interfaceDocPatchSchema.optional().describe(" update 使用的 RFC 6902 JSON Patch;与完整 interface_doc 互斥,create 禁止使用。"),
28632
- rollback_to_version: exports_external.number().int().positive().optional().describe("回滚到的历史版本号。只能与单独的 update 操作使用,不能和 codeinterface_doc interface_doc_patch 同时传入。"),
28633
- expected_version: exports_external.number().int().positive().optional().describe("更新时必填的当前版本号。必须来自刚读取的 flow_get_script,用于并发冲突保护;create 不得传入。")
28631
+ interface_doc_patch: interfaceDocPatchSchema.optional().describe("RFC 6902 patch for update only; mutually exclusive with interface_doc and forbidden for create."),
28632
+ rollback_to_version: exports_external.number().int().positive().optional().describe("Historical version to restore. Use only as a standalone update and never with code, interface_doc, or interface_doc_patch."),
28633
+ expected_version: exports_external.number().int().positive().optional().describe("Required for update and must be the current_version from flow_get_script for concurrency protection; forbidden for create.")
28634
28634
  });
28635
28635
  var documentationSchema = exports_external.object({
28636
- script_id: exports_external.string().min(1).describe("目标脚本 ID,不是完整 URL;校验或预览现有脚本的文档。"),
28636
+ script_id: exports_external.string().min(1).describe("Target script ID, not a full URL; validate or preview its documentation."),
28637
28637
  ...documentationFields
28638
28638
  }).superRefine((input, context) => {
28639
28639
  const supplied = [input.document, input.raw_document, input.document_patch].filter((value) => value !== undefined).length;
@@ -28747,14 +28747,15 @@ function assertPreview(record3, operation) {
28747
28747
  return record3;
28748
28748
  }
28749
28749
  function createMcpServer({ api: api2, previews = new PreviewStore }) {
28750
- const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.3" }, { instructions: serverInstructions });
28750
+ const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.4" }, { instructions: serverInstructions });
28751
28751
  server.registerTool("flow_write_code", {
28752
- 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。",
28752
+ title: "Get the Flow JavaScript authoring contract",
28753
+ description: "Call this before writing Flow Codeblock JavaScript. It returns the mode-specific authoring contract and never writes the database, publishes a script, or executes code. Use non_script for immediate POST /flow/codeblock code and return a complete execution_url; use script for persistent GET/POST /flow/codeblock/{{script_id}} code with a complete script-interface-doc.v1 for preview, validation, and publication. Script delivery includes invocation instructions, parameters/examples, logic, success/error examples, and script_url rather than source or raw interface_doc unless requested. Set base_url only when a caller-facing URL template is needed.",
28753
28754
  inputSchema: {
28754
- mode: exports_external.enum(["non_script", "script"]).describe("执行模式:non_script 为即时接口;script 为按脚本 ID 发布的 GET/POST 接口。未明确要求重定向时使用 non_script。"),
28755
- requirement: exports_external.string().min(1).max(20000).describe("用户的业务需求、输入字段、同步/异步要求和错误行为。只写与本次代码有关的需求。"),
28756
- input_example: exports_external.unknown().optional().describe("业务输入示例。脚本模式下用于生成 request.body/schema/example;非脚本模式下用于 flow_execute_code 测试参数。不要放真实凭据。"),
28757
- include_full_schema: exports_external.boolean().optional().describe("脚本模式是否在结果中附带完整 JSON Schema;默认 false。接口文档实例仍必须按必填字段生成。"),
28755
+ mode: exports_external.enum(["non_script", "script"]).describe("Generation mode. Use non_script for immediate, non-persistent execution; use script for a persistent GET/POST endpoint or HTTP redirects."),
28756
+ requirement: exports_external.string().min(1).max(20000).describe("Complete business requirements, input fields, expected output, external APIs, synchronization/async needs, and error behavior. Include only requirements relevant to this code."),
28757
+ input_example: exports_external.unknown().optional().describe("Business input example. In script mode it helps generate request.body/schema/example; in non_script mode it supplies flow_execute_code test input. Never include real credentials."),
28758
+ include_full_schema: exports_external.boolean().optional().describe("Whether to include the complete JSON Schema in the response; defaults to false. The generated interface document still contains all required fields."),
28758
28759
  base_url: exports_external.string().url().refine((value) => {
28759
28760
  try {
28760
28761
  const parsed = new URL(value);
@@ -28762,22 +28763,23 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28762
28763
  } catch {
28763
28764
  return false;
28764
28765
  }
28765
- }, "base_url must be an http(s) URL without credentials or control characters").optional().describe("可选的用户服务域名,例如 https://flow.example.com。仅用于输出完整调用地址,会拼接 /flow/codeblock/{{script_id}};不得包含用户名、密码或 Token。")
28766
+ }, "base_url must be an http(s) URL without credentials or control characters").optional().describe("Optional caller service origin such as https://flow.example.com. Used only to render /flow/codeblock/{{script_id}}; credentials and control characters are forbidden.")
28766
28767
  }
28767
28768
  }, async ({ mode, requirement, input_example, include_full_schema, base_url }) => {
28768
28769
  const context = codeWriterContext(mode, requirement, input_example, include_full_schema ?? false, base_url);
28769
28770
  return result(mode === "non_script" ? { ...context, execution_url: executionUrl(api2) } : context);
28770
28771
  });
28771
28772
  server.registerTool("flow_list_scripts", {
28772
- description: "只读分页查询脚本。默认使用 page/size 偏移分页;需要连续遍历时使用 pagination=cursor,首次不传 cursor,后续使用响应中的游标。不会创建、更新或执行脚本。",
28773
+ title: "List scripts",
28774
+ description: "Read-only paginated script listing. Use page/size offset pagination by default, or pagination=cursor for sequential traversal (omit cursor on the first call and use the returned cursor afterward). This tool does not create, update, or execute scripts.",
28773
28775
  inputSchema: {
28774
- page: exports_external.number().int().positive().optional().describe("偏移分页页码,从 1 开始;使用游标分页时省略。"),
28775
- size: exports_external.number().int().min(1).max(100).optional().describe("每页数量,1-100,默认由服务端决定。"),
28776
- keyword: exports_external.string().optional().describe("按脚本关键词筛选。"),
28777
- sort: exports_external.enum(["updated_at", "created_at", "code_length", "version"]).optional().describe("排序字段。游标分页只支持 updated_atcreated_atcode_length"),
28778
- order: exports_external.enum(["asc", "desc"]).optional().describe("排序方向,默认由服务端决定。"),
28779
- pagination: exports_external.literal("cursor").optional().describe(" cursor 启用游标分页;首次调用不要传 cursor"),
28780
- cursor: exports_external.string().optional().describe("上一页返回的游标,仅与 pagination=cursor 一起使用。")
28776
+ page: exports_external.number().int().positive().optional().describe("Offset page number starting at 1; omit when using cursor pagination."),
28777
+ size: exports_external.number().int().min(1).max(100).optional().describe("Items per page, 1-100; the server supplies the default."),
28778
+ keyword: exports_external.string().optional().describe("Optional keyword filter for scripts."),
28779
+ sort: exports_external.enum(["updated_at", "created_at", "code_length", "version"]).optional().describe("Sort field; cursor pagination supports updated_at, created_at, and code_length."),
28780
+ order: exports_external.enum(["asc", "desc"]).optional().describe("Sort direction; the server supplies the default."),
28781
+ pagination: exports_external.literal("cursor").optional().describe("Set to cursor to enable cursor pagination; omit cursor on the first call."),
28782
+ cursor: exports_external.string().optional().describe("Cursor returned by the previous page; use only with pagination=cursor.")
28781
28783
  }
28782
28784
  }, withApiErrors(async ({ page, size, keyword, sort, order, pagination, cursor }) => {
28783
28785
  const query = new URLSearchParams;
@@ -28798,27 +28800,30 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28798
28800
  return result(await api2.get(`/flow/scripts${query.size ? `?${query}` : ""}`));
28799
28801
  }));
28800
28802
  server.registerTool("flow_get_script", {
28801
- description: "只读读取脚本代码、元数据和版本信息。更新前必须先调用本工具并使用返回的 current_version 作为 flow_preview_script_change.expected_version。",
28803
+ title: "Get a script",
28804
+ description: "Read-only script code, metadata, and version information. Call this before updates and use the returned current_version as flow_preview_script_change.expected_version.",
28802
28805
  inputSchema: {
28803
- script_id: exports_external.string().min(1).describe("脚本 ID,不是完整 URL"),
28804
- version: exports_external.number().int().min(0).optional().describe("可选历史版本号;省略时读取当前版本。")
28806
+ script_id: exports_external.string().min(1).describe("Script ID, not a full URL."),
28807
+ version: exports_external.number().int().min(0).optional().describe("Optional historical version; omit to read the current version.")
28805
28808
  }
28806
28809
  }, withApiErrors(async ({ script_id, version: version2 }) => {
28807
28810
  const query = version2 === undefined ? "" : `?version=${encodeURIComponent(String(version2))}`;
28808
28811
  return result(await api2.get(`/flow/scripts/${encodedScriptId(script_id)}${query}`));
28809
28812
  }));
28810
28813
  server.registerTool("flow_get_script_documentation", {
28811
- description: "只读读取当前或指定历史版本的 script-interface-doc.v1 接口文档。修改文档前先读取当前版本并保留版本号。",
28814
+ title: "Get script interface documentation",
28815
+ description: "Read-only script-interface-doc.v1 documentation for the current or a specified historical version. Read the current version before changing documentation and keep its version information.",
28812
28816
  inputSchema: {
28813
- script_id: exports_external.string().min(1).describe("脚本 ID,不是完整 URL"),
28814
- version: exports_external.number().int().min(0).optional().describe("可选历史版本号;省略时读取当前文档。")
28817
+ script_id: exports_external.string().min(1).describe("Script ID, not a full URL."),
28818
+ version: exports_external.number().int().min(0).optional().describe("Optional historical version; omit to read the current document.")
28815
28819
  }
28816
28820
  }, withApiErrors(async ({ script_id, version: version2 }) => {
28817
28821
  const query = version2 === undefined ? "" : `?version=${encodeURIComponent(String(version2))}`;
28818
28822
  return result(await api2.get(`/flow/scripts/${encodedScriptId(script_id)}/documentation${query}`));
28819
28823
  }));
28820
28824
  server.registerTool("flow_validate_script_documentation", {
28821
- description: "只读校验并规范化指定脚本的接口文档,不写入数据库。完整 document、raw_document RFC 6902 document_patch 三选一;补丁必须带 expected_version,响应不会用于发布确认。",
28825
+ title: "Validate script interface documentation",
28826
+ description: "Read-only validation and normalization for a script-interface-doc.v1 document; this tool never writes to the database. Provide exactly one of document, raw_document, or an RFC 6902 document_patch. Patches require expected_version, and this response cannot be used as publication confirmation.",
28822
28827
  inputSchema: documentationSchema.shape
28823
28828
  }, withApiErrors(async (input) => {
28824
28829
  const parsed = documentationSchema.parse(input);
@@ -28839,7 +28844,8 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28839
28844
  return result(validation);
28840
28845
  }));
28841
28846
  server.registerTool("flow_preview_script_change", {
28842
- 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)。",
28847
+ title: "Preview script change",
28848
+ description: "Preview a script create or update without writing to the database. A create requires code or code_base64 plus a complete interface_doc and must not include script_id or expected_version. An update requires script_id and a freshly read expected_version; changing code also requires a complete interface_doc or interface_doc_patch. After a successful preview, call flow_apply_script_change(confirm=true) only after explicit user confirmation.",
28843
28849
  inputSchema: changeSchema.shape
28844
28850
  }, withApiErrors(async (input) => {
28845
28851
  const parsed = changeSchema.parse(input);
@@ -28885,10 +28891,11 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28885
28891
  });
28886
28892
  }));
28887
28893
  server.registerTool("flow_apply_script_change", {
28888
- description: "应用 flow_preview_script_change 返回的一次性 preview_id。必须传 confirm=true;工具会再次检查版本并在成功或失败后销毁预览。发布成功时返回由 FLOW_CODEBLOCK_BASE_URL 生成的完整 script_url。不支持删除脚本。版本冲突时重新读取并预览。",
28894
+ title: "Apply previewed script change",
28895
+ description: "Apply the single-use preview_id returned by flow_preview_script_change. confirm=true is required; the tool rechecks the current version and destroys the preview after success or failure. A successful publication returns a complete script_url built from FLOW_CODEBLOCK_BASE_URL. Script deletion is not supported. On a version conflict, read the script and preview again.",
28889
28896
  inputSchema: {
28890
- preview_id: exports_external.string().uuid().describe("最近一次脚本变更预览返回的 UUID;不能复用过期或已应用的 ID。"),
28891
- confirm: exports_external.literal(true).describe("必须为 true,表示用户已明确确认写入。")
28897
+ preview_id: exports_external.string().uuid().describe("UUID returned by the latest script-change preview; expired or already applied IDs cannot be reused."),
28898
+ confirm: exports_external.literal(true).describe("Must be true to confirm that the user explicitly approved the write.")
28892
28899
  }
28893
28900
  }, withApiErrors(async ({ preview_id }) => {
28894
28901
  try {
@@ -28916,7 +28923,8 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28916
28923
  }
28917
28924
  }));
28918
28925
  server.registerTool("flow_preview_script_documentation", {
28919
- description: "预览接口文档保存,不写数据库。先读取脚本当前版本;document、raw_document document_patch 三选一,补丁必须带 expected_version,完整文档必须包含所有强制字段。成功后只有 flow_apply_script_documentation(confirm=true) 才会写入。",
28926
+ title: "Preview documentation change",
28927
+ description: "Preview a script-interface-doc.v1 save without writing to the database. Read the script's current version first. Provide exactly one of document, raw_document, or document_patch; patches require expected_version and complete documents must include every required field. After a successful preview, only flow_apply_script_documentation(confirm=true) can write the change.",
28920
28928
  inputSchema: documentationSchema.shape
28921
28929
  }, withApiErrors(async (input) => {
28922
28930
  const parsed = documentationSchema.parse(input);
@@ -28950,10 +28958,11 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28950
28958
  });
28951
28959
  }));
28952
28960
  server.registerTool("flow_apply_script_documentation", {
28953
- description: "应用 flow_preview_script_documentation 返回的一次性预览。必须传 confirm=true;工具会再次检查脚本版本并在成功或失败后销毁预览。发布成功时返回完整 script_url。版本冲突时重新读取、预览。",
28961
+ title: "Apply previewed documentation change",
28962
+ description: "Apply the single-use preview returned by flow_preview_script_documentation. confirm=true is required; the tool rechecks the script version and destroys the preview after success or failure. A successful save returns a complete script_url. On a version conflict, read the script and preview again.",
28954
28963
  inputSchema: {
28955
- preview_id: exports_external.string().uuid().describe("最近一次接口文档预览返回的 UUID;不能复用过期或已应用的 ID。"),
28956
- confirm: exports_external.literal(true).describe("必须为 true,表示用户已明确确认写入。")
28964
+ preview_id: exports_external.string().uuid().describe("UUID returned by the latest documentation preview; expired or already applied IDs cannot be reused."),
28965
+ confirm: exports_external.literal(true).describe("Must be true to confirm that the user explicitly approved the write.")
28957
28966
  }
28958
28967
  }, withApiErrors(async ({ preview_id }) => {
28959
28968
  try {
@@ -28982,23 +28991,24 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
28982
28991
  }
28983
28992
  }));
28984
28993
  const lockSchema = {
28985
- script_id: exports_external.string().min(1).describe("要锁定或解锁的脚本 ID"),
28986
- owner_name: exports_external.string().min(1).describe("锁定时设置、解锁时核对的所有者名称。"),
28987
- lock_password: exports_external.string().min(6).describe("锁定口令;仅传给服务端,不会写入 MCP 预览或日志。"),
28988
- confirm: exports_external.literal(true).describe("必须为 true,表示用户明确确认锁定或解锁。")
28994
+ script_id: exports_external.string().min(1).describe("Script ID to lock or unlock."),
28995
+ owner_name: exports_external.string().min(1).describe("Owner name to set when locking and verify when unlocking."),
28996
+ lock_password: exports_external.string().min(6).describe("Lock password; sent only to the server and never stored in MCP previews or logs."),
28997
+ confirm: exports_external.literal(true).describe("Must be true to confirm that the user explicitly approved locking or unlocking.")
28989
28998
  };
28990
- server.registerTool("flow_lock_script", { description: "锁定脚本以阻止并发写入。必须显式传入 confirm=true;锁定口令不会被 MCP 保存。锁定后脚本变更和文档保存可能被服务端拒绝。", inputSchema: lockSchema }, withApiErrors(async ({ script_id, owner_name, lock_password }) => result(await api2.post(`/flow/scripts/${encodedScriptId(script_id)}/lock`, { owner_name, lock_password }))));
28991
- 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 }))));
28999
+ server.registerTool("flow_lock_script", { title: "Lock script", description: "Lock a script to prevent concurrent writes. confirm=true is required; the lock password is never stored by MCP. Script changes and documentation saves may be rejected while the script is locked.", inputSchema: lockSchema }, withApiErrors(async ({ script_id, owner_name, lock_password }) => result(await api2.post(`/flow/scripts/${encodedScriptId(script_id)}/lock`, { owner_name, lock_password }))));
29000
+ server.registerTool("flow_unlock_script", { title: "Unlock script", description: "Unlock a script using its owner name and password. confirm=true is required; the lock password is never stored by MCP. Emergency recovery unlock is not provided.", inputSchema: lockSchema }, withApiErrors(async ({ script_id, owner_name, lock_password }) => result(await api2.post(`/flow/scripts/${encodedScriptId(script_id)}/unlock`, { owner_name, lock_password }))));
28992
29001
  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()]))]);
28993
29002
  server.registerTool("flow_execute_script", {
28994
- description: "执行已发布脚本,仅用于用户明确要求测试或调用时。method 只能是 GET/POST;结果包含由 FLOW_CODEBLOCK_BASE_URL 和 script_id 生成的完整 script_url。query 数组会生成重复参数,POST 的 body 作为 JSON 发送。MCP 认证、Cookie、CSRF、代理来源头和测试工具标识会被过滤,qingcodeToken/qingcodeTimeout 不能作为业务参数传入。",
29003
+ title: "Execute published script",
29004
+ description: "Execute a published script only when the user explicitly requests a test or call. method must be GET or POST; the result includes a complete script_url built from FLOW_CODEBLOCK_BASE_URL and script_id. Array query values become repeated parameters, and a POST body is sent as JSON. MCP authentication, cookies, CSRF, proxy-source headers, and test-tool markers are filtered; qingcodeToken and qingcodeTimeout cannot be supplied as business parameters.",
28995
29005
  inputSchema: {
28996
- script_id: exports_external.string().min(1).describe("已发布脚本 ID;工具会调用 /flow/codeblock/{script_id}"),
28997
- method: exports_external.enum(["GET", "POST"]).default("POST").describe("脚本请求方法,只能是 GET POST;默认 POST"),
28998
- query: exports_external.record(exports_external.string(), queryValueSchema).optional().describe("业务查询参数。值可为 string/number/boolean 或其数组;数组生成重复 query 参数。不要传 qingcodeToken/qingcodeTimeout"),
28999
- headers: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("业务请求头。认证、Cookie、CSRFForwardedX-Real-IP 等保留头会被过滤。"),
29000
- body: exports_external.unknown().optional().describe("POST JSON 请求体;GET 不发送 body。不要把脚本模式业务 body 包装为 input input.body"),
29001
- timeout_ms: exports_external.number().int().positive().optional().describe("执行超时毫秒数;只能通过此字段配置,不能在 query 中传 qingcodeTimeout")
29006
+ script_id: exports_external.string().min(1).describe("Published script ID; the tool calls /flow/codeblock/{script_id}."),
29007
+ method: exports_external.enum(["GET", "POST"]).default("POST").describe("Script request method, either GET or POST; defaults to POST."),
29008
+ query: exports_external.record(exports_external.string(), queryValueSchema).optional().describe("Business query parameters. Values may be string/number/boolean or arrays of those types; arrays become repeated query parameters. Do not send qingcodeToken or qingcodeTimeout."),
29009
+ headers: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Business request headers. Authentication, cookies, CSRF, Forwarded, X-Real-IP, and other reserved headers are filtered."),
29010
+ body: exports_external.unknown().optional().describe("POST JSON request body; GET requests do not send a body. Do not wrap script-mode business data as input or input.body."),
29011
+ timeout_ms: exports_external.number().int().positive().optional().describe("Execution timeout in milliseconds; configure it only with this field, never with qingcodeTimeout in query.")
29002
29012
  }
29003
29013
  }, withApiErrors(async ({ script_id, method, query, headers, body, timeout_ms }) => {
29004
29014
  const url2 = new URL(`/flow/codeblock/${encodedScriptId(script_id)}`, api2.baseUrl);
@@ -29027,12 +29037,13 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
29027
29037
  return result({ script_url: scriptUrl(api2, script_id), method, response });
29028
29038
  }));
29029
29039
  server.registerTool("flow_execute_code", {
29030
- description: "执行未发布的非脚本 JavaScript,仅在用户明确要求测试时使用。结果包含完整 execution_url。请求固定为 POST /flow/codeblock,body.input 原样注入全局 input;代码和 code_base64 二选一。不会把 MCP 认证信息写入用户脚本输入,也不会创建或发布脚本。",
29040
+ title: "Execute unpublished code",
29041
+ description: "Execute unpublished non-script JavaScript only when the user explicitly requests a test. The result includes a complete execution_url. The request is always POST /flow/codeblock, and body.input is injected unchanged as global input; provide exactly one of code or code_base64. MCP authentication is never written into user input, and this tool does not create or publish scripts.",
29031
29042
  inputSchema: {
29032
- code: exports_external.string().min(1).optional().describe("UTF-8 JavaScript 源码,与 code_base64 二选一。"),
29033
- code_base64: exports_external.string().min(1).optional().describe("JavaScript 源码的非空 Base64,与 code 二选一。"),
29034
- input: exports_external.unknown().optional().describe("注入全局 input 的业务数据,默认 {}。不要放 Token、密码、Cookie Authorization 值。"),
29035
- timeout_ms: exports_external.number().int().positive().optional().describe("本次测试执行超时毫秒数;必须在服务端允许的最小/最大范围内。")
29043
+ code: exports_external.string().min(1).optional().describe("UTF-8 JavaScript source, mutually exclusive with code_base64."),
29044
+ code_base64: exports_external.string().min(1).optional().describe("Non-empty Base64-encoded JavaScript source, mutually exclusive with code."),
29045
+ input: exports_external.unknown().optional().describe("Business data injected into global input; defaults to {}. Do not include tokens, passwords, cookies, or Authorization values."),
29046
+ timeout_ms: exports_external.number().int().positive().optional().describe("Test execution timeout in milliseconds; it must be within the server's allowed range.")
29036
29047
  }
29037
29048
  }, withApiErrors(async ({ code, code_base64, input, timeout_ms }) => {
29038
29049
  const codeBase64 = encodeCode(code, code_base64);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-codeblock-rust-mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Flow Codeblock Rust+Bun stdio MCP Server for script management and execution.",
5
5
  "license": "MIT",
6
6
  "repository": {