flow-codeblock-rust-mcp 0.1.9 → 0.1.10
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 +4 -2
- package/dist/index.js +198 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Local stdio MCP server for Flow Codeblock Rust+Bun. It calls the server-side Rus
|
|
|
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.10
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Configure the environment:
|
|
@@ -26,7 +26,7 @@ export FLOW_CODEBLOCK_TOKEN='<YOUR_INTERNAL_ACCESS_TOKEN>'
|
|
|
26
26
|
"mcpServers": {
|
|
27
27
|
"flow-codeblock-rust": {
|
|
28
28
|
"command": "bunx",
|
|
29
|
-
"args": ["--bun", "flow-codeblock-rust-mcp@0.1.
|
|
29
|
+
"args": ["--bun", "flow-codeblock-rust-mcp@0.1.10"],
|
|
30
30
|
"env": {
|
|
31
31
|
"FLOW_CODEBLOCK_BASE_URL": "https://flow.example.com",
|
|
32
32
|
"FLOW_CODEBLOCK_TOKEN": "<YOUR_INTERNAL_ACCESS_TOKEN>"
|
|
@@ -56,6 +56,8 @@ At initialization the server sends complete tool selection, preview/confirmation
|
|
|
56
56
|
|
|
57
57
|
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`.
|
|
58
58
|
|
|
59
|
+
Every nested schema property, array item, and object-form `additionalProperties` node requires `type`, `description`, and `example`, with examples covering declared fields. MCP accepts one legacy JSON-text parse, fills examples only from matching parent examples, and uses a neutral description when one is omitted.
|
|
60
|
+
|
|
59
61
|
`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.
|
|
60
62
|
|
|
61
63
|
`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.
|
package/dist/index.js
CHANGED
|
@@ -27896,6 +27896,7 @@ var interfaceDocNestedRules = [
|
|
|
27896
27896
|
];
|
|
27897
27897
|
var interfaceDocInputDescription = [
|
|
27898
27898
|
"A complete script-interface-doc.v1 document is required when creating a script, changing code, or saving documentation.",
|
|
27899
|
+
"Submit interface_doc/document as a JSON object. Legacy JSON text is accepted and parsed once by MCP for compatibility. MCP fills nested examples only from matching parent examples, uses a neutral description when one is omitted, and never guesses a missing type.",
|
|
27899
27900
|
`Required structure: ${Object.entries(interfaceDocRequiredFields).map(([key, fields]) => `${key}=[${fields.join(", ")}]`).join("; ")}.`,
|
|
27900
27901
|
...interfaceDocNestedRules,
|
|
27901
27902
|
"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>.",
|
|
@@ -27934,6 +27935,73 @@ var interfaceDocPatchJsonSchema = {
|
|
|
27934
27935
|
]
|
|
27935
27936
|
}
|
|
27936
27937
|
};
|
|
27938
|
+
var schemaNodeInputSchema;
|
|
27939
|
+
schemaNodeInputSchema = exports_external.lazy(() => exports_external.looseObject({
|
|
27940
|
+
type: exports_external.string().min(1).describe("JSON Schema type such as object, array, string, integer, number, or boolean."),
|
|
27941
|
+
description: exports_external.string().min(1).describe("Description of this nested field or data structure."),
|
|
27942
|
+
example: exports_external.unknown().describe("A concrete value matching this nested schema node."),
|
|
27943
|
+
properties: exports_external.record(exports_external.string(), schemaNodeInputSchema).optional().describe("Map fixed object field names to child schema nodes."),
|
|
27944
|
+
items: schemaNodeInputSchema.optional().describe("Child schema node for each array item."),
|
|
27945
|
+
additionalProperties: exports_external.union([exports_external.boolean(), schemaNodeInputSchema]).optional().describe("Boolean or child schema for dynamic object keys."),
|
|
27946
|
+
required: exports_external.array(exports_external.string()).optional().describe("Runtime-required object field names.")
|
|
27947
|
+
}));
|
|
27948
|
+
var schemaRootInputSchema = exports_external.looseObject({
|
|
27949
|
+
type: exports_external.string().min(1).describe("JSON Schema type such as object, array, string, integer, number, or boolean."),
|
|
27950
|
+
description: exports_external.string().optional().describe("Description of the root data structure."),
|
|
27951
|
+
example: exports_external.unknown().optional().describe("Complete example matching this root schema."),
|
|
27952
|
+
properties: exports_external.record(exports_external.string(), schemaNodeInputSchema).optional().describe("Map fixed object field names to child schema nodes."),
|
|
27953
|
+
items: schemaNodeInputSchema.optional().describe("Child schema node for each array item."),
|
|
27954
|
+
additionalProperties: exports_external.union([exports_external.boolean(), schemaNodeInputSchema]).optional().describe("Boolean or child schema for dynamic object keys."),
|
|
27955
|
+
required: exports_external.array(exports_external.string()).optional().describe("Runtime-required object field names.")
|
|
27956
|
+
});
|
|
27957
|
+
var parameterInputSchema = exports_external.looseObject({
|
|
27958
|
+
name: exports_external.string().min(1).describe("Caller-facing query parameter or HTTP header name."),
|
|
27959
|
+
type: exports_external.enum(["string", "integer", "number", "boolean", "array", "object"]).describe("Parameter JSON type."),
|
|
27960
|
+
required: exports_external.boolean().describe("Whether the parameter is required at runtime."),
|
|
27961
|
+
description: exports_external.string().min(1).describe("Purpose and constraints of the parameter."),
|
|
27962
|
+
example: exports_external.unknown().describe("Concrete example value for the parameter."),
|
|
27963
|
+
default: exports_external.unknown().optional().describe("Optional default value."),
|
|
27964
|
+
format: exports_external.string().optional().describe("Optional format hint."),
|
|
27965
|
+
enum_values: exports_external.array(exports_external.unknown()).optional().describe("Optional allowed values.")
|
|
27966
|
+
});
|
|
27967
|
+
var interfaceDocToolInputObjectSchema = exports_external.looseObject({
|
|
27968
|
+
schema_version: exports_external.literal("script-interface-doc.v1").describe("Fixed document contract version."),
|
|
27969
|
+
title: exports_external.string().min(1).describe("Interface document title."),
|
|
27970
|
+
summary: exports_external.string().min(1).describe("One-sentence caller-facing summary."),
|
|
27971
|
+
endpoint: exports_external.looseObject({
|
|
27972
|
+
methods: exports_external.array(exports_external.enum(["GET", "POST"])).min(1).describe("HTTP methods supported by the endpoint."),
|
|
27973
|
+
path: exports_external.string().optional().describe("Actual /flow/codeblock/{script_id} path on update."),
|
|
27974
|
+
description: exports_external.string().min(1).describe("What the callable endpoint does.")
|
|
27975
|
+
}).describe("HTTP endpoint contract."),
|
|
27976
|
+
request: exports_external.looseObject({
|
|
27977
|
+
query: exports_external.array(parameterInputSchema).describe("Caller-facing URL query parameters; use [] when empty."),
|
|
27978
|
+
headers: exports_external.array(parameterInputSchema).describe("Caller-facing HTTP headers; use [] when empty."),
|
|
27979
|
+
body: exports_external.looseObject({
|
|
27980
|
+
content_type: exports_external.literal("application/json").describe("Must be application/json."),
|
|
27981
|
+
schema: schemaRootInputSchema.describe("Request body JSON Schema."),
|
|
27982
|
+
example: exports_external.unknown().describe("Complete request body example matching schema.")
|
|
27983
|
+
}).optional().describe("POST request body.")
|
|
27984
|
+
}).describe("Caller request contract."),
|
|
27985
|
+
responses: exports_external.array(exports_external.looseObject({
|
|
27986
|
+
status: exports_external.number().int().min(100).max(599).describe("HTTP status code from 100 through 599."),
|
|
27987
|
+
description: exports_external.string().min(1).describe("Business meaning of this response branch."),
|
|
27988
|
+
content_type: exports_external.literal("application/json").describe("Must be application/json."),
|
|
27989
|
+
schema: schemaRootInputSchema.describe("Response body JSON Schema."),
|
|
27990
|
+
example: exports_external.unknown().describe("Complete response example matching schema.")
|
|
27991
|
+
})).min(1).describe("Complete response branches at the document root."),
|
|
27992
|
+
logic_description: exports_external.string().min(20).describe("Endpoint processing logic; at least 20 characters."),
|
|
27993
|
+
usage_refs: exports_external.array(exports_external.unknown()).optional().describe("Real application references only.")
|
|
27994
|
+
});
|
|
27995
|
+
function parseLegacyJsonDocument(value) {
|
|
27996
|
+
if (typeof value !== "string")
|
|
27997
|
+
return value;
|
|
27998
|
+
try {
|
|
27999
|
+
return JSON.parse(value);
|
|
28000
|
+
} catch {
|
|
28001
|
+
return value;
|
|
28002
|
+
}
|
|
28003
|
+
}
|
|
28004
|
+
var interfaceDocToolInputSchema = exports_external.preprocess(parseLegacyJsonDocument, interfaceDocToolInputObjectSchema).describe(interfaceDocInputDescription);
|
|
27937
28005
|
function assertInterfaceDocPatch(patch) {
|
|
27938
28006
|
const parsed = interfaceDocPatchSchema.safeParse(patch);
|
|
27939
28007
|
if (!parsed.success)
|
|
@@ -27945,18 +28013,82 @@ function isObject2(value) {
|
|
|
27945
28013
|
function hasOwn(object4, key) {
|
|
27946
28014
|
return Object.prototype.hasOwnProperty.call(object4, key);
|
|
27947
28015
|
}
|
|
28016
|
+
function normalizeSchemaNode(schema, parentExample, fieldName, root = false) {
|
|
28017
|
+
if (!root) {
|
|
28018
|
+
if (typeof schema.description !== "string" || !schema.description.trim()) {
|
|
28019
|
+
schema.description = `Value for field "${fieldName}".`;
|
|
28020
|
+
}
|
|
28021
|
+
if (!hasOwn(schema, "example") && parentExample !== undefined) {
|
|
28022
|
+
schema.example = structuredClone(parentExample);
|
|
28023
|
+
}
|
|
28024
|
+
}
|
|
28025
|
+
const example = hasOwn(schema, "example") ? schema.example : parentExample;
|
|
28026
|
+
if (schema.type === "array") {
|
|
28027
|
+
if (isObject2(schema.items)) {
|
|
28028
|
+
const itemExample = Array.isArray(example) && example.length > 0 ? example[0] : undefined;
|
|
28029
|
+
normalizeSchemaNode(schema.items, itemExample, `${fieldName} item`);
|
|
28030
|
+
}
|
|
28031
|
+
return;
|
|
28032
|
+
}
|
|
28033
|
+
if (schema.type !== "object")
|
|
28034
|
+
return;
|
|
28035
|
+
const properties = isObject2(schema.properties) ? schema.properties : undefined;
|
|
28036
|
+
if (properties) {
|
|
28037
|
+
for (const [key, propertySchema] of Object.entries(properties)) {
|
|
28038
|
+
if (!isObject2(propertySchema))
|
|
28039
|
+
continue;
|
|
28040
|
+
const childExample = isObject2(example) && hasOwn(example, key) ? example[key] : undefined;
|
|
28041
|
+
normalizeSchemaNode(propertySchema, childExample, key);
|
|
28042
|
+
}
|
|
28043
|
+
}
|
|
28044
|
+
if (isObject2(schema.additionalProperties)) {
|
|
28045
|
+
const knownKeys = new Set(properties ? Object.keys(properties) : []);
|
|
28046
|
+
const dynamicExample = isObject2(example) ? Object.entries(example).find(([key]) => !knownKeys.has(key))?.[1] : undefined;
|
|
28047
|
+
normalizeSchemaNode(schema.additionalProperties, dynamicExample, `${fieldName} value`);
|
|
28048
|
+
}
|
|
28049
|
+
}
|
|
28050
|
+
function normalizeInterfaceDocument(document) {
|
|
28051
|
+
if (!isObject2(document))
|
|
28052
|
+
return document;
|
|
28053
|
+
const normalized = structuredClone(document);
|
|
28054
|
+
const containers = [];
|
|
28055
|
+
if (isObject2(normalized.request) && isObject2(normalized.request.body)) {
|
|
28056
|
+
containers.push(normalized.request.body);
|
|
28057
|
+
}
|
|
28058
|
+
if (Array.isArray(normalized.responses)) {
|
|
28059
|
+
containers.push(...normalized.responses.filter(isObject2));
|
|
28060
|
+
}
|
|
28061
|
+
for (const container of containers) {
|
|
28062
|
+
const schema = isObject2(container.schema) ? container.schema : undefined;
|
|
28063
|
+
if (!schema)
|
|
28064
|
+
continue;
|
|
28065
|
+
if (!hasOwn(container, "example") && hasOwn(schema, "example")) {
|
|
28066
|
+
container.example = structuredClone(schema.example);
|
|
28067
|
+
}
|
|
28068
|
+
normalizeSchemaNode(schema, container.example, "root", true);
|
|
28069
|
+
}
|
|
28070
|
+
return normalized;
|
|
28071
|
+
}
|
|
27948
28072
|
function requireText(object4, key, path, issues, minLength = 1) {
|
|
27949
28073
|
const value = object4[key];
|
|
27950
28074
|
if (typeof value !== "string" || value.trim().length < minLength) {
|
|
27951
28075
|
issues.push(`${path}.${key} must be a non-empty string with at least ${minLength} characters`);
|
|
27952
28076
|
}
|
|
27953
28077
|
}
|
|
27954
|
-
function validateSchemaExampleCoverage(schema, example, schemaPath, examplePath, issues) {
|
|
28078
|
+
function validateSchemaExampleCoverage(schema, example, schemaPath, examplePath, issues, requireMetadata = false) {
|
|
27955
28079
|
if (typeof schema.type !== "string") {
|
|
27956
28080
|
issues.push(`${schemaPath}.type is required`);
|
|
27957
|
-
|
|
28081
|
+
}
|
|
28082
|
+
if (requireMetadata) {
|
|
28083
|
+
requireText(schema, "description", schemaPath, issues);
|
|
28084
|
+
if (!hasOwn(schema, "example")) {
|
|
28085
|
+
issues.push(`${schemaPath}.example is required`);
|
|
28086
|
+
}
|
|
27958
28087
|
}
|
|
27959
28088
|
if (schema.type === "array") {
|
|
28089
|
+
if (!isObject2(schema.items)) {
|
|
28090
|
+
issues.push(`${schemaPath}.items is required for array schemas`);
|
|
28091
|
+
}
|
|
27960
28092
|
if (!Array.isArray(example)) {
|
|
27961
28093
|
issues.push(`${examplePath} must be an array`);
|
|
27962
28094
|
return;
|
|
@@ -27965,14 +28097,15 @@ function validateSchemaExampleCoverage(schema, example, schemaPath, examplePath,
|
|
|
27965
28097
|
issues.push(`${schemaPath}.items must fully describe array elements`);
|
|
27966
28098
|
return;
|
|
27967
28099
|
}
|
|
27968
|
-
example.forEach((item, index) => validateSchemaExampleCoverage(schema.items, item, `${schemaPath}.items`, `${examplePath}[${index}]`, issues));
|
|
28100
|
+
example.forEach((item, index) => validateSchemaExampleCoverage(schema.items, item, `${schemaPath}.items`, `${examplePath}[${index}]`, issues, true));
|
|
27969
28101
|
return;
|
|
27970
28102
|
}
|
|
27971
28103
|
if (schema.type !== "object")
|
|
27972
28104
|
return;
|
|
27973
28105
|
const properties = isObject2(schema.properties) ? schema.properties : undefined;
|
|
27974
28106
|
const additionalProperties = isObject2(schema.additionalProperties) ? schema.additionalProperties : undefined;
|
|
27975
|
-
|
|
28107
|
+
const allowsAdditionalProperties = additionalProperties !== undefined || schema.additionalProperties === true;
|
|
28108
|
+
if (!properties && !allowsAdditionalProperties) {
|
|
27976
28109
|
issues.push(`${schemaPath} must define properties or an additionalProperties schema`);
|
|
27977
28110
|
return;
|
|
27978
28111
|
}
|
|
@@ -27985,7 +28118,7 @@ function validateSchemaExampleCoverage(schema, example, schemaPath, examplePath,
|
|
|
27985
28118
|
if (!hasOwn(example, key)) {
|
|
27986
28119
|
issues.push(`${examplePath} is missing ${key}`);
|
|
27987
28120
|
} else if (isObject2(propertySchema)) {
|
|
27988
|
-
validateSchemaExampleCoverage(propertySchema, example[key], `${schemaPath}.properties.${key}`, `${examplePath}.${key}`, issues);
|
|
28121
|
+
validateSchemaExampleCoverage(propertySchema, example[key], `${schemaPath}.properties.${key}`, `${examplePath}.${key}`, issues, true);
|
|
27989
28122
|
} else {
|
|
27990
28123
|
issues.push(`${schemaPath}.properties.${key} must be a JSON Schema object`);
|
|
27991
28124
|
}
|
|
@@ -27995,8 +28128,8 @@ function validateSchemaExampleCoverage(schema, example, schemaPath, examplePath,
|
|
|
27995
28128
|
if (properties && hasOwn(properties, key))
|
|
27996
28129
|
continue;
|
|
27997
28130
|
if (additionalProperties) {
|
|
27998
|
-
validateSchemaExampleCoverage(additionalProperties, value, `${schemaPath}.additionalProperties`, `${examplePath}.${key}`, issues);
|
|
27999
|
-
} else {
|
|
28131
|
+
validateSchemaExampleCoverage(additionalProperties, value, `${schemaPath}.additionalProperties`, `${examplePath}.${key}`, issues, true);
|
|
28132
|
+
} else if (schema.additionalProperties !== true) {
|
|
28000
28133
|
issues.push(`${schemaPath}.properties does not define example field ${key}`);
|
|
28001
28134
|
}
|
|
28002
28135
|
}
|
|
@@ -28128,7 +28261,7 @@ function interfaceDocCompletenessIssues(document, operation) {
|
|
|
28128
28261
|
validateSchemaAndExample(response, path, issues);
|
|
28129
28262
|
});
|
|
28130
28263
|
}
|
|
28131
|
-
return issues;
|
|
28264
|
+
return [...new Set(issues)];
|
|
28132
28265
|
}
|
|
28133
28266
|
function assertCompleteInterfaceDoc(document, operation) {
|
|
28134
28267
|
const issues = interfaceDocCompletenessIssues(document, operation);
|
|
@@ -28222,7 +28355,7 @@ var interfaceDocSchema = {
|
|
|
28222
28355
|
additionalProperties: false,
|
|
28223
28356
|
properties: {
|
|
28224
28357
|
content_type: { const: "application/json" },
|
|
28225
|
-
schema: {},
|
|
28358
|
+
schema: { $ref: "#/$defs/schema_root" },
|
|
28226
28359
|
example: {}
|
|
28227
28360
|
}
|
|
28228
28361
|
},
|
|
@@ -28234,30 +28367,68 @@ var interfaceDocSchema = {
|
|
|
28234
28367
|
status: { type: "integer", minimum: 100, maximum: 599 },
|
|
28235
28368
|
description: { type: "string", minLength: 1, maxLength: 4000 },
|
|
28236
28369
|
content_type: { const: "application/json" },
|
|
28237
|
-
schema: {},
|
|
28370
|
+
schema: { $ref: "#/$defs/schema_root" },
|
|
28238
28371
|
example: {}
|
|
28239
28372
|
}
|
|
28373
|
+
},
|
|
28374
|
+
schema_root: {
|
|
28375
|
+
type: "object",
|
|
28376
|
+
required: ["type"],
|
|
28377
|
+
additionalProperties: true,
|
|
28378
|
+
properties: {
|
|
28379
|
+
type: { type: "string", minLength: 1 },
|
|
28380
|
+
description: { type: "string", minLength: 1 },
|
|
28381
|
+
example: {},
|
|
28382
|
+
properties: { type: "object", additionalProperties: { $ref: "#/$defs/schema_node" } },
|
|
28383
|
+
items: { $ref: "#/$defs/schema_node" },
|
|
28384
|
+
additionalProperties: { anyOf: [{ $ref: "#/$defs/schema_node" }, { type: "boolean" }] },
|
|
28385
|
+
required: { type: "array", items: { type: "string" } }
|
|
28386
|
+
}
|
|
28387
|
+
},
|
|
28388
|
+
schema_node: {
|
|
28389
|
+
type: "object",
|
|
28390
|
+
required: ["type", "description", "example"],
|
|
28391
|
+
additionalProperties: true,
|
|
28392
|
+
properties: {
|
|
28393
|
+
type: { type: "string", minLength: 1 },
|
|
28394
|
+
description: { type: "string", minLength: 1 },
|
|
28395
|
+
example: {},
|
|
28396
|
+
properties: { type: "object", additionalProperties: { $ref: "#/$defs/schema_node" } },
|
|
28397
|
+
items: { $ref: "#/$defs/schema_node" },
|
|
28398
|
+
additionalProperties: { anyOf: [{ $ref: "#/$defs/schema_node" }, { type: "boolean" }] },
|
|
28399
|
+
required: { type: "array", items: { type: "string" } }
|
|
28400
|
+
}
|
|
28240
28401
|
}
|
|
28241
28402
|
}
|
|
28242
28403
|
};
|
|
28243
|
-
function schemaFromExample(value) {
|
|
28404
|
+
function schemaFromExample(value, fieldName = "value") {
|
|
28405
|
+
const metadata = { description: `Value for ${fieldName}.`, example: structuredClone(value) };
|
|
28244
28406
|
if (Array.isArray(value)) {
|
|
28245
|
-
return {
|
|
28407
|
+
return {
|
|
28408
|
+
type: "array",
|
|
28409
|
+
...metadata,
|
|
28410
|
+
items: value.length > 0 ? schemaFromExample(value[0], `${fieldName} item`) : {
|
|
28411
|
+
type: "string",
|
|
28412
|
+
description: `Value for ${fieldName} item.`,
|
|
28413
|
+
example: ""
|
|
28414
|
+
}
|
|
28415
|
+
};
|
|
28246
28416
|
}
|
|
28247
28417
|
if (value !== null && typeof value === "object") {
|
|
28248
28418
|
const entries = Object.entries(value);
|
|
28249
28419
|
return {
|
|
28250
28420
|
type: "object",
|
|
28251
|
-
|
|
28421
|
+
...metadata,
|
|
28422
|
+
properties: Object.fromEntries(entries.map(([key, item]) => [key, schemaFromExample(item, key)])),
|
|
28252
28423
|
required: entries.map(([key]) => key),
|
|
28253
28424
|
additionalProperties: false
|
|
28254
28425
|
};
|
|
28255
28426
|
}
|
|
28256
28427
|
if (value === null)
|
|
28257
|
-
return { type: "null" };
|
|
28428
|
+
return { type: "null", ...metadata };
|
|
28258
28429
|
if (typeof value === "number")
|
|
28259
|
-
return { type: Number.isInteger(value) ? "integer" : "number" };
|
|
28260
|
-
return { type: typeof value };
|
|
28430
|
+
return { type: Number.isInteger(value) ? "integer" : "number", ...metadata };
|
|
28431
|
+
return { type: typeof value, ...metadata };
|
|
28261
28432
|
}
|
|
28262
28433
|
function codeWriterContext(mode, requirement, inputExample, includeFullSchema, baseUrl) {
|
|
28263
28434
|
const common = {
|
|
@@ -28535,8 +28706,9 @@ var serverInstructions = [
|
|
|
28535
28706
|
"Tool routing: flow_write_code only generates code and its contract; flow_execute_code tests unpublished generated code; flow_execute_script runs published scripts. When the generated code and available safe input are sufficient for a meaningful runtime test, execute it immediately without waiting for user confirmation. If required input or credentials are missing, report that runtime verification was not performed instead of inventing them.",
|
|
28536
28707
|
"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.",
|
|
28537
28708
|
"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.",
|
|
28709
|
+
"Interface-document validation reports every discovered nested schema issue in one response; fix the complete list before making another preview call.",
|
|
28538
28710
|
"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.",
|
|
28539
|
-
"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
|
|
28711
|
+
"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 root JSON Schema node declares type; every nested property, array item, and object-form additionalProperties node declares type, description, and example. Arrays must define items, fixed object properties must be covered by the complete example, and additionalProperties=true is reserved for opaque upstream JSON.",
|
|
28540
28712
|
"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.",
|
|
28541
28713
|
"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. Treat input as a reserved, read-only runtime binding: never declare, redeclare, rebind, or destructure a local binding named input in any scope, including function parameters and nested callbacks. Use an alias such as const payload = input when a local name is needed. Use top-level return by default; use a bare qf_output assignment only for event-style/asynchronous flows or when explicitly requested, never both.",
|
|
28542
28714
|
"For every initial generation and every later revision in non-script mode, final delivery always includes the complete latest generated JavaScript, even after runtime verification; never return only a patch, diff, or partial snippet. Also include 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.",
|
|
@@ -28642,7 +28814,7 @@ function withApiErrors(handler) {
|
|
|
28642
28814
|
};
|
|
28643
28815
|
}
|
|
28644
28816
|
var documentationFields = {
|
|
28645
|
-
document:
|
|
28817
|
+
document: interfaceDocToolInputSchema.optional().describe(`Normalized script-interface-doc.v1 JSON object. Choose exactly one of document, raw_document, or document_patch; complete documents are required for saves and code updates. ${interfaceDocInputDescription}`),
|
|
28646
28818
|
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."),
|
|
28647
28819
|
format: exports_external.literal("json").optional().describe("Format of raw_document; only json is supported."),
|
|
28648
28820
|
document_patch: interfaceDocPatchSchema.optional().describe("RFC 6902 patch for an existing script only. Choose exactly one of document, raw_document, or document_patch."),
|
|
@@ -28655,7 +28827,7 @@ var changeSchema = exports_external.object({
|
|
|
28655
28827
|
code_base64: exports_external.string().optional().describe("Non-empty Base64-encoded JavaScript, mutually exclusive with code."),
|
|
28656
28828
|
description: exports_external.string().optional().describe("Script description. Can be updated without changing code."),
|
|
28657
28829
|
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."),
|
|
28658
|
-
interface_doc:
|
|
28830
|
+
interface_doc: interfaceDocToolInputSchema.optional().describe(interfaceDocInputDescription),
|
|
28659
28831
|
interface_doc_patch: interfaceDocPatchSchema.optional().describe("RFC 6902 patch for update only; mutually exclusive with interface_doc and forbidden for create."),
|
|
28660
28832
|
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."),
|
|
28661
28833
|
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.")
|
|
@@ -28722,6 +28894,7 @@ function assertScriptChangeInput(input) {
|
|
|
28722
28894
|
throw new Error("rollback_to_version cannot be combined with code, interface_doc, or interface_doc_patch");
|
|
28723
28895
|
}
|
|
28724
28896
|
if (input.interface_doc !== undefined) {
|
|
28897
|
+
input.interface_doc = normalizeInterfaceDocument(input.interface_doc);
|
|
28725
28898
|
assertCompleteInterfaceDoc(input.interface_doc, input.operation);
|
|
28726
28899
|
}
|
|
28727
28900
|
if (input.interface_doc_patch !== undefined)
|
|
@@ -28775,7 +28948,7 @@ function assertPreview(record3, operation) {
|
|
|
28775
28948
|
return record3;
|
|
28776
28949
|
}
|
|
28777
28950
|
function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
28778
|
-
const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.
|
|
28951
|
+
const server = new McpServer({ name: "flow-codeblock-rust", version: "0.1.10" }, { instructions: serverInstructions });
|
|
28779
28952
|
server.registerTool("flow_write_code", {
|
|
28780
28953
|
title: "Get the Flow JavaScript authoring contract",
|
|
28781
28954
|
description: "Call this before writing or revising Flow Codeblock JavaScript. It returns the mode-specific authoring contract, including forbidden-identifier and reserved-input replacement rules, and never writes the database, publishes a script, or executes code. For every non_script generation or revision, always deliver the complete latest generated JavaScript plus execution_url, never only a patch or partial snippet; 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.",
|
|
@@ -28783,7 +28956,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28783
28956
|
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."),
|
|
28784
28957
|
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."),
|
|
28785
28958
|
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."),
|
|
28786
|
-
include_full_schema: exports_external.boolean().optional().describe("Whether to include the complete JSON Schema in the response; defaults to
|
|
28959
|
+
include_full_schema: exports_external.boolean().optional().describe("Whether to include the complete recursive JSON Schema in the response; defaults to true for script mode to avoid a follow-up schema call. Set false only when the caller already has the schema."),
|
|
28787
28960
|
base_url: exports_external.string().url().refine((value) => {
|
|
28788
28961
|
try {
|
|
28789
28962
|
const parsed = new URL(value);
|
|
@@ -28794,7 +28967,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28794
28967
|
}, "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.")
|
|
28795
28968
|
}
|
|
28796
28969
|
}, async ({ mode, requirement, input_example, include_full_schema, base_url }) => {
|
|
28797
|
-
const context = codeWriterContext(mode, requirement, input_example, include_full_schema ??
|
|
28970
|
+
const context = codeWriterContext(mode, requirement, input_example, include_full_schema ?? mode === "script", base_url);
|
|
28798
28971
|
return result(mode === "non_script" ? { ...context, execution_url: executionUrl(api2) } : context);
|
|
28799
28972
|
});
|
|
28800
28973
|
server.registerTool("flow_list_scripts", {
|
|
@@ -28856,6 +29029,7 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28856
29029
|
}, withApiErrors(async (input) => {
|
|
28857
29030
|
const parsed = documentationSchema.parse(input);
|
|
28858
29031
|
if (parsed.document !== undefined) {
|
|
29032
|
+
parsed.document = normalizeInterfaceDocument(parsed.document);
|
|
28859
29033
|
assertCompleteInterfaceDoc(parsed.document, "update");
|
|
28860
29034
|
}
|
|
28861
29035
|
if (parsed.document_patch !== undefined)
|
|
@@ -28956,6 +29130,8 @@ function createMcpServer({ api: api2, previews = new PreviewStore }) {
|
|
|
28956
29130
|
inputSchema: documentationSchema.shape
|
|
28957
29131
|
}, withApiErrors(async (input) => {
|
|
28958
29132
|
const parsed = documentationSchema.parse(input);
|
|
29133
|
+
if (parsed.document !== undefined)
|
|
29134
|
+
parsed.document = normalizeInterfaceDocument(parsed.document);
|
|
28959
29135
|
const expectedVersion = await fetchCurrentVersion(api2, parsed.script_id);
|
|
28960
29136
|
if (parsed.document_patch !== undefined && parsed.expected_version !== expectedVersion) {
|
|
28961
29137
|
throw new Error(`Script version changed from ${parsed.expected_version} to ${expectedVersion}; read and preview again`);
|