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.
- package/README.md +22 -22
- package/dist/index.js +136 -125
- 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
|
|
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
|
-
|
|
7
|
+
Bun 1.4.0 or newer is required:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
bunx --bun flow-codeblock-rust-mcp@0.1.
|
|
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`
|
|
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
|
-
##
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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`
|
|
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
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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: "
|
|
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
|
-
"
|
|
28277
|
-
"
|
|
28278
|
-
"
|
|
28279
|
-
"
|
|
28280
|
-
"
|
|
28281
|
-
"
|
|
28282
|
-
"
|
|
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
|
-
"
|
|
28286
|
-
"
|
|
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: "
|
|
28290
|
-
dayjs_exception: "
|
|
28291
|
-
other_modules: "
|
|
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
|
-
"
|
|
28355
|
-
"
|
|
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: "
|
|
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
|
-
"
|
|
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: ["
|
|
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: "
|
|
28374
|
+
rule: "Do not call flow_execute_code unless the user explicitly requests a test.",
|
|
28375
28375
|
response_format: [
|
|
28376
|
-
"
|
|
28377
|
-
"
|
|
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
|
|
28391
|
-
headers: "input.header
|
|
28392
|
-
body: "input.body
|
|
28393
|
-
cookies: "input.cookies
|
|
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: "
|
|
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
|
-
"
|
|
28401
|
-
"
|
|
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
|
-
"
|
|
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
|
|
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: "
|
|
28424
|
-
url: "flow_redirect_url
|
|
28425
|
-
code: "flow_redirect_code
|
|
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
|
-
"
|
|
28429
|
-
"
|
|
28430
|
-
"
|
|
28431
|
-
"
|
|
28432
|
-
"
|
|
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
|
-
"
|
|
28436
|
-
"
|
|
28437
|
-
"
|
|
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
|
-
"
|
|
28506
|
-
"
|
|
28507
|
-
"
|
|
28508
|
-
"
|
|
28509
|
-
"
|
|
28510
|
-
"script-interface-doc.v1
|
|
28511
|
-
"
|
|
28512
|
-
"
|
|
28513
|
-
"
|
|
28514
|
-
"
|
|
28515
|
-
"
|
|
28516
|
-
"
|
|
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(
|
|
28618
|
-
raw_document: exports_external.string().optional().describe("
|
|
28619
|
-
format: exports_external.literal("json").optional().describe("raw_document
|
|
28620
|
-
document_patch: interfaceDocPatchSchema.optional().describe("
|
|
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
|
|
28625
|
-
script_id: exports_external.string().min(1).optional().describe("
|
|
28626
|
-
code: exports_external.string().optional().describe("UTF-8 JavaScript
|
|
28627
|
-
code_base64: exports_external.string().optional().describe("JavaScript
|
|
28628
|
-
description: exports_external.string().optional().describe("
|
|
28629
|
-
ip_whitelist: exports_external.array(exports_external.string()).nullable().optional().describe("
|
|
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("
|
|
28632
|
-
rollback_to_version: exports_external.number().int().positive().optional().describe("
|
|
28633
|
-
expected_version: exports_external.number().int().positive().optional().describe("
|
|
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("
|
|
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.
|
|
28750
|
+
const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.4" }, { instructions: serverInstructions });
|
|
28751
28751
|
server.registerTool("flow_write_code", {
|
|
28752
|
-
|
|
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("
|
|
28755
|
-
requirement: exports_external.string().min(1).max(20000).describe("
|
|
28756
|
-
input_example: exports_external.unknown().optional().describe("
|
|
28757
|
-
include_full_schema: exports_external.boolean().optional().describe("
|
|
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("
|
|
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
|
-
|
|
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("
|
|
28775
|
-
size: exports_external.number().int().min(1).max(100).optional().describe("
|
|
28776
|
-
keyword: exports_external.string().optional().describe("
|
|
28777
|
-
sort: exports_external.enum(["updated_at", "created_at", "code_length", "version"]).optional().describe("
|
|
28778
|
-
order: exports_external.enum(["asc", "desc"]).optional().describe("
|
|
28779
|
-
pagination: exports_external.literal("cursor").optional().describe("
|
|
28780
|
-
cursor: exports_external.string().optional().describe("
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
28891
|
-
confirm: exports_external.literal(true).describe("
|
|
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
|
-
|
|
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
|
-
|
|
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("
|
|
28956
|
-
confirm: exports_external.literal(true).describe("
|
|
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("
|
|
28986
|
-
owner_name: exports_external.string().min(1).describe("
|
|
28987
|
-
lock_password: exports_external.string().min(6).describe("
|
|
28988
|
-
confirm: exports_external.literal(true).describe("
|
|
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: "
|
|
28991
|
-
server.registerTool("flow_unlock_script", { description: "
|
|
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
|
-
|
|
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("
|
|
28997
|
-
method: exports_external.enum(["GET", "POST"]).default("POST").describe("
|
|
28998
|
-
query: exports_external.record(exports_external.string(), queryValueSchema).optional().describe("
|
|
28999
|
-
headers: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("
|
|
29000
|
-
body: exports_external.unknown().optional().describe("POST JSON
|
|
29001
|
-
timeout_ms: exports_external.number().int().positive().optional().describe("
|
|
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
|
-
|
|
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
|
|
29033
|
-
code_base64: exports_external.string().min(1).optional().describe("JavaScript
|
|
29034
|
-
input: exports_external.unknown().optional().describe("
|
|
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);
|