### Install Project Dependencies Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/README.md Installs all project dependencies using pnpm. Ensure Node.js and pnpm are installed first. ```bash pnpm install ``` -------------------------------- ### parametersExamples Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md An array of parameter examples, where each example demonstrates a valid configuration with a title, description, and parameters object. ```APIDOC ## parametersExamples ### Description Array of parameter examples. Each example demonstrates a valid configuration with a title, description, and parameters object. ### Type `ParametersExample[]` ### Interface Definition ```typescript interface ParametersExample { title: string; // Example name description: string; // What this example demonstrates parameters: Record; // Valid parameter values } ``` ### Requirements - Each example's parameters must pass validation. - Examples are validated when the plugin is registered. - Should demonstrate common use cases. - Should demonstrate all major features. ### Example ```typescript parametersExamples: [ { title: 'Route Active Items', description: 'Route items where status equals active to true port', parameters: { condition: { path: 'status', value: 'active', operator: 'equals' } } }, { title: 'Route Non-Premium Users', description: 'Route items where tier is not premium to false port', parameters: { condition: { path: 'tier', value: 'premium', operator: 'notEquals' } } } ] ``` ``` -------------------------------- ### Connection Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md An example of a Connection object, illustrating how to link the output of one node to the input of another. ```typescript const connection: Connection = { node: 'next-node', outputPort: 'main' }; ``` -------------------------------- ### Example Request for Node Resource Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md An example of how to request detailed information for a specific workflow node type, in this case, the 'builtIn.if' node. ```text Get resource: workflow-mng://nodes/builtIn.if ``` -------------------------------- ### If Node Example Configuration Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/node-plugins.md Example configuration for the If node. This node routes data items to different output ports ('true' or 'false') based on a specified condition. ```typescript { id: 'check-premium', title: 'Route by User Tier', type: 'builtIn.if', position: { x: 300, y: 0 }, parameters: { condition: { path: 'user.tier', value: 'premium', operator: 'equals' } }, connections: [ { node: 'premium-handler', outputPort: 'true' }, { node: 'standard-handler', outputPort: 'false' } ] } ``` -------------------------------- ### WorkflowNode Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md An example of a WorkflowNode, showing a node with its parameters and an outgoing connection to another node. ```typescript const node: WorkflowNode = { id: 'process-node', title: 'Process Data', type: 'builtIn.code', position: { x: 300, y: 0 }, parameters: { code: 'return item;', timeout: 5000 }, connections: [ { node: 'output-node', outputPort: 'main' } ] }; ``` -------------------------------- ### Start MCP Server Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Instructions for running the MCP server from the project root using pnpm or directly with tsx. ```bash # From project root pnpm mcp:run # Or with tsx directly tzx mcp/server.ts ``` -------------------------------- ### Example Output of list-available-nodes Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Illustrates the typical output format when listing available node plugins, showing their names, purposes, and use cases. ```text Currently available node plugins: 1. builtIn.noop — name: Noop | purpose: No-operation node that passes through input data unchanged. Useful as a placeholder or entry point for workflows. | use cases: Creating workflow entry points, Placeholder nodes during workflow design, Passing through data without modification 2. builtIn.set — name: Set | purpose: Add or overwrite fields in data items with static values. | use cases: Adding new fields to data items, Overwriting existing field values, Setting default values, Transforming data structure by adding fields 3. builtIn.marker — name: Marker | purpose: Marks data items with a field (default: "_matched") based on a condition evaluation. Does not route data - all items pass through with the specified field indicating whether the condition was met. | use cases: Marking data items with condition results, Adding metadata for downstream filtering, Condition evaluation without routing, Data validation and marking ... ``` -------------------------------- ### ParametersExample Interface Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Defines the structure for parameter examples, including a title, description, and the actual parameters object. These examples are used to demonstrate valid node configurations. ```typescript interface ParametersExample { title: string; description: string; parameters: Record; } ``` -------------------------------- ### Workflow Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md An example of a complete Workflow object, demonstrating the structure with multiple nodes and their connections. It includes an 'input' and a 'filter' node. ```typescript const workflow: Workflow = { id: 'user-processing', title: 'Process User Data', active: true, nodes: [ { id: 'input', title: 'Start', type: 'builtIn.noop', position: { x: 0, y: 0 }, parameters: {}, connections: [{ node: 'filter', outputPort: 'main' }] }, { id: 'filter', title: 'Filter Active', type: 'builtIn.filter', position: { x: 100, y: 0 }, parameters: { condition: { path: 'status', value: 'active', operator: 'equals' }, mode: 'pass' }, connections: [] } ] }; ``` -------------------------------- ### Set Node Example Configuration Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/node-plugins.md Example configuration for the Set node, which adds or overwrites fields in data items with static string values. It supports nested field paths using dot notation. ```typescript { id: 'set-status', title: 'Mark as Active', type: 'builtIn.set', position: { x: 100, y: 0 }, parameters: { values: [ { path: 'status', value: 'active' }, { path: 'user.tier', value: 'premium' }, { path: 'metadata.processed', value: 'true' } ] }, connections: [] } ``` -------------------------------- ### Execute Function Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md An example implementation of the execute function that processes input batches, transforms each item, and returns the results under the 'main' output port. This example is asynchronous. ```typescript async execute( node: WorkflowNode, input: TypedField[][] ): Promise> { const result: TypedField[][] = []; for (const batch of input) { const processed: TypedField[] = []; for (const item of batch) { // Transform item processed.push(transformedItem); } result.push(processed); } return { main: result }; } ``` -------------------------------- ### Example Node Name Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Provides examples of human-readable names for node types, used for display in UIs and documentation. ```typescript name: string ``` -------------------------------- ### Noop Node Example Configuration Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/node-plugins.md Example configuration for a no-operation node. This node passes input data through unchanged and is useful as a workflow entry point or placeholder. ```typescript { id: 'entry-node', title: 'Start', type: 'builtIn.noop', position: { x: 0, y: 0 }, parameters: {}, connections: [{ node: 'next-node', outputPort: 'main' }] } ``` -------------------------------- ### String Field Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Example of a required string field with a description. ```typescript // String field { type: 'string', required: true, description: 'User name' } ``` -------------------------------- ### Auto-complete Node Types Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Example command for auto-completing node types based on a partial input string. ```text Complete nodeType starting with "builtIn.i" ``` -------------------------------- ### NodeConfig Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md An example of a NodeConfig object representing a filter node. This demonstrates how to structure parameters for a specific node type. ```typescript const nodeConfig: NodeConfig = { id: 'filter-node', title: 'Filter Active Users', type: 'builtIn.filter', position: { x: 200, y: 100 }, parameters: { condition: { path: 'status', value: 'active', operator: 'equals' }, mode: 'pass' } }; ``` -------------------------------- ### Code Node Timeout Examples Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/configuration.md Examples of setting short and long timeouts for code node operations. ```typescript // Short timeout for quick operations { timeout: 1000 } ``` ```typescript // Long timeout for complex calculations { timeout: 30000 } ``` -------------------------------- ### Example Response for Workflow Node Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md A sample JSON response detailing a 'builtIn.if' node, including its type, name, purpose, output ports, parameter schema, and an example of parameter usage. ```json { "nodeType": "builtIn.if", "name": "If", "purpose": "Conditional routing node that routes data items to different output ports based on a condition...", "useCases": [ "Conditional workflow branching", "Routing data based on conditions", "Implementing business logic with conditional flows", "Data splitting and categorization" ], "outputPorts": ["true", "false"], "parameterSchema": { "type": "object", "fields": { "condition": { "type": "object", "required": true, "fields": { "path": { "type": "string", "required": true }, "value": { "type": "string", "required": true }, "operator": { "type": "enum", "required": true, "values": ["equals", "notEquals", "contains"] } } } } }, "parametersExamples": [ { "title": "Route Active vs Inactive", "description": "Route items where status equals 'active' to the 'true' port, others to 'false' port.", "parameters": { "condition": { "path": "status", "value": "active", "operator": "equals" } } } ] } ``` -------------------------------- ### ExecutionData Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md An example of ExecutionData, showing results for two nodes ('node-1' and 'node-2') with different output ports. ```typescript const data: ExecutionData = { 'node-1': { 'main': [ [{ value: 'item1', kind: 'primitive' }], [{ value: 'item2', kind: 'primitive' }] ] }, 'node-2': { 'true': [ [{ value: 'active-item', kind: 'primitive' }] ], 'false': [ [{ value: 'inactive-item', kind: 'primitive' }] ] } }; ``` -------------------------------- ### Start MCP Server Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/README.md Launches the local Model Context Protocol (MCP) server. This server exposes registered workflow nodes for introspection by MCP clients. ```bash pnpm mcp:run ``` -------------------------------- ### MCP Introspection Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Illustrates how to use the MCP server and inspector for node introspection, including querying parameter schemas. ```bash pnpm mcp:run # Then use MCP inspector to query: # - list-available-nodes (returns parameter schemas) # - workflow-node resource (includes full parameter schema) ``` -------------------------------- ### Array Field Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Example of a required array field where each item is a string. ```typescript // Array field { type: 'array', required: true, itemType: { type: 'string', required: true }, description: 'List of email addresses' } ``` -------------------------------- ### Marker Node Example Configuration Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/node-plugins.md Example configuration for the Marker node. This node marks data items with a field indicating whether they match a specified condition, adding a boolean result without routing. ```typescript { id: 'mark-active', title: 'Mark Active Items', type: 'builtIn.marker', position: { x: 200, y: 0 }, parameters: { condition: { path: 'status', value: 'active', operator: 'equals' }, field: 'isActive' }, connections: [] } ``` -------------------------------- ### Example Route by Priority Configuration Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/node-plugins.md Demonstrates a built-in switch node configuration for routing items based on a 'priority' field. It defines rules for 'high' and 'medium' priorities, with a default output for 'low'. ```typescript { id: 'route-by-priority', title: 'Route by Priority', type: 'builtIn.switch', position: { x: 600, y: 0 }, parameters: { rules: [ { condition: { path: 'priority', value: 'high', operator: 'equals' }, output: 'high' }, { condition: { path: 'priority', value: 'medium', operator: 'equals' }, output: 'medium' } ], defaultOutput: 'low' }, connections: [ { node: 'high-handler', outputPort: 'high' }, { node: 'medium-handler', outputPort: 'medium' }, { node: 'low-handler', outputPort: 'low' } ] } ``` -------------------------------- ### Example MCP Client Call for Listing Nodes Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Demonstrates how an MCP client, such as Claude, can query for available workflow nodes by asking a natural language question. ```typescript // Using Claude with MCP // In the MCP inspector or Claude interface: "What nodes are available for creating workflows?" // Returns the list-available-nodes result ``` -------------------------------- ### Execute Workflow Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md Demonstrates how to execute a workflow and handle its result. Check the 'finished' status to determine if the execution was successful and access 'data' or 'error' accordingly. ```typescript const result = await engine.executeWorkflow('my-workflow'); if (result.finished) { console.log('Success! Results:', result.data); } else { console.error('Failed:', result.error?.message); } ``` -------------------------------- ### FieldResolver Implementation Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md Provides an example implementation of a FieldResolver function. This resolver handles 'user' and 'product' entities, fetching data from mock databases and returning it as TypedField objects. ```typescript const resolver: FieldResolver = async (value, entityName) => { if (entityName === 'user') { // value is a user ID const user = await userDatabase.getById(value as string); return { id: { value: user.id, kind: 'primitive' }, name: { value: user.name, kind: 'primitive' }, email: { value: user.email, kind: 'primitive' }, profile: { value: { ...user.profile }, kind: 'primitive' } }; } if (entityName === 'product') { const product = await productDatabase.getById(value as string); return { id: { value: product.id, kind: 'primitive' }, name: { value: product.name, kind: 'primitive' }, price: { value: product.price, kind: 'primitive' } }; } throw new Error(`Unknown entity: ${entityName}`); }; ``` -------------------------------- ### NodeData and ParametersExample Interfaces Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Defines the structure for NodeData, which includes parameter examples, and the ParametersExample interface itself, detailing example titles, descriptions, and parameters. ```typescript interface NodeData extends NodeSummary { parametersExamples: ParametersExample[]; } interface ParametersExample { title: string; description: string; parameters: Record; } ``` -------------------------------- ### ParametersExamples Array Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md An array of ParametersExample objects, showcasing different configurations for routing items based on conditions. These examples are validated upon plugin registration. ```typescript parametersExamples: [ { title: 'Route Active Items', description: 'Route items where status equals active to true port', parameters: { condition: { path: 'status', value: 'active', operator: 'equals' } } }, { title: 'Route Non-Premium Users', description: 'Route items where tier is not premium to false port', parameters: { condition: { path: 'tier', value: 'premium', operator: 'notEquals' } } } ] ``` -------------------------------- ### Data Flow Example: Workflow Execution Steps Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Illustrates a step-by-step data flow through a sample workflow, showing input, processing, and output at each node. ```plaintext Workflow: Input → Filter → If(true/false) → Handler1 → Handler2 Execution: 1. Input phase: input: { 'input': { main: [[{id:1}, {id:2}, {id:3}]] } } 2. Filter node executes: • Receives: [[{id:1}, {id:2}, {id:3}]] • Outputs: { main: [[{id:1}, {id:3}]] } // {id:2} filtered out • Stored: data['filter-node'] = { main: [[{id:1}, {id:3}]] } 3. If node executes: • Receives: [[{id:1}, {id:3}]] • Evaluates condition on each item • Outputs: { true: [[{id:1}]], false: [[{id:3}]] } • Stored: data['if-node'] = { true: [[{id:1}]], false: [[{id:3}]] } 4. Handler1 receives from if-node's 'true' port: • Receives: [[{id:1}]] • Processes... 5. Handler2 receives from if-node's 'false' port: • Receives: [[{id:3}]] • Processes... ``` -------------------------------- ### Nested Object Field Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Example of an optional object field with nested properties. ```typescript // Nested object field { type: 'object', required: false, fields: { street: { type: 'string', required: true }, city: { type: 'string', required: true }, zip: { type: 'string', required: false } } } ``` -------------------------------- ### Example Use Cases for a Node Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md An array of strings detailing practical applications for a node, helping users identify relevant scenarios for its use. ```typescript useCases: string[] ``` -------------------------------- ### Example Output Ports Definition Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Demonstrates how to define static output port names for a node. These are the default ports when dynamic outputs are allowed, and the only valid ports when they are not. ```typescript outputPorts: string[] ``` -------------------------------- ### Enum Field with Default Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Example of an optional enum field with a default value and allowed values. ```typescript // Enum field with default { type: 'enum', required: false, default: 'light', values: ['light', 'dark'], description: 'Theme selection' } ``` -------------------------------- ### Example SerializableParameterSchema Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md Demonstrates the structure of a `SerializableParameterSchema` with nested fields, including string types, enums with defined values, and optional properties like default values and descriptions. ```typescript const schema: SerializableParameterSchema = { type: 'object', fields: { condition: { type: 'object', required: true, fields: { path: { type: 'string', required: true, description: 'Field path' }, value: { type: 'string', required: true, description: 'Comparison value' }, operator: { type: 'enum', required: true, values: ['equals', 'notEquals', 'contains'] } } }, mode: { type: 'enum', required: false, default: 'pass', values: ['pass', 'drop'] } } }; ``` -------------------------------- ### Example getParameterSchema Implementation Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Shows how to implement the getParameterSchema method, returning a Zod schema that defines the structure and validation rules for the node's parameters. ```typescript getParameterSchema: () => SerializableParameterSchema ``` ```typescript getParameterSchema: () => serializeParameterSchema( z.object({ condition: ConditionSchema, mode: z.enum(['pass', 'drop']).default('pass') }) ) ``` -------------------------------- ### PrimitiveTypedField Examples Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md Illustrates how to create PrimitiveTypedField objects for string and object values. Ensure the 'kind' property is set to 'primitive'. ```typescript const stringField: PrimitiveTypedField = { value: 'hello', kind: 'primitive' }; const objectField: PrimitiveTypedField = { value: { name: 'John', age: 30 }, kind: 'primitive' }; ``` -------------------------------- ### Serialized Schema Example Output Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/configuration.md The resulting JSON structure after serializing a Zod object schema. ```json { "type": "object", "fields": { "name": { "type": "string", "required": true }, "email": { "type": "string", "required": false }, "age": { "type": "number", "required": false, "default": 18 }, "role": { "type": "enum", "required": true, "values": ["admin", "user"] }, "tags": { "type": "array", "required": true, "itemType": { "type": "string", "required": true } }, "profile": { "type": "object", "required": true, "fields": { "bio": { "type": "string", "required": true }, "avatar": { "type": "string", "required": false } } } } } ``` -------------------------------- ### Test MCP Server with Inspector Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/README.md Connects the MCP Inspector to the running MCP server to list available node plugins. Ensure the inspector is installed or run via npx. ```bash npx @modelcontextprotocol/inspector -- pnpm --silent mcp:run ``` -------------------------------- ### Example Node Type Identifier Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Illustrates the recommended format for unique node type identifiers, typically 'domain.name'. This ensures clarity and avoids naming conflicts. ```typescript nodeType: string ``` -------------------------------- ### Serialize Zod Schema Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/configuration.md Demonstrates serializing a complex Zod object schema into a JSON representation. ```typescript const schema = z.object({ name: z.string(), email: z.string().optional(), age: z.number().default(18), role: z.enum(['admin', 'user']), tags: z.array(z.string()), profile: z.object({ bio: z.string(), avatar: z.string().optional() }) }); const serialized = serializeParameterSchema(schema); ``` -------------------------------- ### listWorkflows Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Returns all stored workflows. This is helpful for getting an overview of all available workflows in the system. ```APIDOC ## listWorkflows ### Description Returns all stored workflows. ### Method `listWorkflows(): Workflow[]` ### Returns - **Workflow[]** - Array of all Workflow definitions ### Example ```typescript const allWorkflows = engine.listWorkflows(); console.log(`Total workflows: ${allWorkflows.length}`); ``` ``` -------------------------------- ### Example Node Purpose Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Shows a concise description for a node's primary function, aiding in understanding its role within a workflow. ```typescript purpose: string ``` -------------------------------- ### LinkTypedField Examples Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/types.md Shows how to define LinkTypedField for user and product entities. The 'entity' field specifies the type of external resource to link to. ```typescript const userLink: LinkTypedField = { value: '12345', kind: 'link', entity: 'user' // Indicates this ID should be resolved using user repository }; const productLink: LinkTypedField = { value: 'SKU-789', kind: 'link', entity: 'product' }; ``` -------------------------------- ### CodeInvalidReturnFormatError Examples Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Illustrates incorrect and correct return formats for code execution. Ensure code returns a valid TypedField structure. ```typescript // Wrong - returns a plain string code: "return 'hello';" ``` ```typescript // Wrong - returns an object directly code: "return { name: 'John' };" ``` ```typescript // Correct - returns a TypedField code: "return toTypedField('hello');" ``` -------------------------------- ### Example Resolver Implementation Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Implement a custom resolver to fetch and structure data from external sources like a database. This is used during workflow execution to resolve linked entities. ```typescript const resolver: FieldResolver = async (value, entityName) => { if (entityName === 'user') { const userId = value as string; const user = await database.users.findById(userId); return { id: { value: user.id, kind: 'primitive' }, name: { value: user.name, kind: 'primitive' }, email: { value: user.email, kind: 'primitive' }, address: { value: user.address, kind: 'link', entity: 'address' // Can nest links } }; } if (entityName === 'address') { const addressId = value as string; const address = await database.addresses.findById(addressId); return { street: { value: address.street, kind: 'primitive' }, city: { value: address.city, kind: 'primitive' }, zipCode: { value: address.zipCode, kind: 'primitive' } }; } throw new Error(`Unknown entity: ${entityName}`); }; // Use with workflow execution const result = await engine.executeWorkflow( 'workflow-id', inputData, resolver // Pass resolver ); ``` -------------------------------- ### registerNode Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Registers a custom node plugin with the engine. The plugin's parameter examples are validated against its schema during registration. ```APIDOC ## registerNode ### Description Registers a custom node plugin with the engine. The plugin's parameter examples are validated against its schema during registration. ### Method Signature ```typescript registerNode(plugin: NodePlugin): void ``` ### Parameters #### Path Parameters - **plugin** (`NodePlugin`) - Required - The node plugin to register ### Throws - `NodeTypeAlreadyRegisteredError` — When a plugin with the same nodeType is already registered - `NodeValidationError` — When parameter examples fail validation ### Example ```typescript const myPlugin: NodePlugin = { nodeType: 'custom.myNode', name: 'My Node', purpose: 'A custom node for testing', useCases: ['Testing'], outputPorts: ['main'], dynamicOutputsAllowed: false, getParameterSchema: () => ({ type: 'object', fields: {} }), validate: () => {}, execute: async (node, input) => ({ main: input }), parametersExamples: [] }; engine.registerNode(myPlugin); ``` ``` -------------------------------- ### List All Stored Workflows Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Retrieves an array containing all workflows currently stored in the engine. Useful for getting an overview of available workflows. ```typescript const allWorkflows = engine.listWorkflows(); console.log(`Total workflows: ${allWorkflows.length}`); ``` -------------------------------- ### Empty Batch Handling Example Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Illustrates how empty batches are represented in the output and how downstream nodes receive them. This occurs when conditions in Filter or Switch nodes are not met. ```typescript // If Filter outputs no matching items: output = { main: [] } // Empty port // Downstream nodes still receive input: input = [[]] // One empty batch ``` -------------------------------- ### Example validate Method Implementation Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Illustrates the validate method, responsible for checking the node's configuration against its parameter schema and any custom validation rules. Throws an error if the configuration is invalid. ```typescript validate: (node: WorkflowNode) => void ``` ```typescript validate: (node: WorkflowNode) => { validateNodeParameters(node, FilterNodeParametersSchema); // Additional custom validations here } ``` -------------------------------- ### Example Error Handling Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Demonstrates how to check the `finished` status of an execution result and handle potential errors, including specific error types like `NodeExecutionError` and `FieldNotFoundError`. ```typescript const result = await engine.executeWorkflow('workflow-id'); if (result.finished) { // Success - process result.data console.log('Execution completed'); const nodeOutputs = result.data['some-node']; } else { // Failure - check error if (result.error instanceof NodeExecutionError) { console.error(`Node failed: ${result.error.nodeId}`); } else if (result.error instanceof FieldNotFoundError) { console.error(`Field missing: ${result.error.path}`); } // Partial data may still be available console.log('Partial results:', result.data); } ``` -------------------------------- ### Example Dynamic Outputs Allowed Flag Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md A boolean flag indicating whether a node can generate output ports dynamically based on its parameters. Set to false for nodes with fixed outputs. ```typescript dynamicOutputsAllowed: boolean ``` -------------------------------- ### Get Workflow Node Resource Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Retrieves complete information about a specific node type, including its parameter schema, examples, and use cases. The response contains the node data in JSON format. ```typescript { contents: [ { uri: 'workflow-mng://nodes/{nodeType}', mimeType: 'application/json', text: JSON.stringify(NodeData, null, 2) } ] } ``` -------------------------------- ### Get Registered Node Plugins Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Obtain an array of all currently registered node plugins. This can be useful for inspecting plugin details or finding specific plugins. ```typescript const plugins = engine.getRegisteredNodePlugins(); const noop = plugins.find(p => p.nodeType === 'builtIn.noop'); ``` -------------------------------- ### Initialize MCP Server Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Configure and instantiate the MCP server with a name, version, and initial instructions for the LLM client. ```typescript const server = new McpServer( { name: 'workflow-mng', version: '1.0.0', }, { instructions: 'Use list-available-nodes to inspect every workflow node that can be used right now.' } ); ``` -------------------------------- ### Run Development Tests Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/README.md Executes the project's test suite. Use this to verify code correctness during development. ```bash pnpm test ``` -------------------------------- ### Documenting Schemas using JSON.stringify Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Shows how to obtain and serialize a parameter schema for documentation or transmission purposes. ```typescript const engine = new WorkflowEngine(); const plugin = engine.getRegisteredNodePlugins()[0]; const schema = plugin.getParameterSchema(); // Use JSON.stringify to document or transmit const json = JSON.stringify(schema, null, 2); console.log('Parameter Schema:', json); ``` -------------------------------- ### Instantiate Workflow Engine Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/configuration.md Create a new instance of the WorkflowEngine. The constructor requires no arguments and automatically registers all built-in node types. ```typescript import { WorkflowEngine } from 'hands-on-configuration-tools-by-llm'; const engine = new WorkflowEngine(); ``` -------------------------------- ### LLM Interaction with MCP Server Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Illustrates how an LLM like Claude can interact with the MCP server by calling tools and resources to understand and generate workflows. ```text # In a session with this MCP server configured: "What workflow nodes are available? Show me the If node details." # Claude can call: # 1. list-available-nodes (tool) # 2. workflow-mng://nodes/builtIn.if (resource) ``` -------------------------------- ### Catch NodeExecutionError Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Example of how to catch a NodeExecutionError after executing a workflow. This snippet checks if the result finished and if an error occurred, then logs the nodeId and message. ```typescript const result = await engine.executeWorkflow('workflow-id'); if (!result.finished && result.error instanceof NodeExecutionError) { console.error(`Node execution failed:`, result.error.nodeId, result.error.message); } ``` -------------------------------- ### Import Workflow Engine Library Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/README.md Import the main WorkflowEngine class and core types from the library. Ensure these types are correctly imported for workflow definition and execution. ```typescript import { WorkflowEngine, type Workflow, type WorkflowNode, type ExecutionResult } from 'hands-on-configuration-tools-by-llm'; ``` -------------------------------- ### Workflow Node Resource Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Retrieves detailed information about a specific workflow node type, including its parameter schema, examples, and use cases. ```APIDOC ## Get Workflow Node Details ### Description Returns complete information about a specific node type including parameter schema, examples, and use cases. ### Method GET ### Endpoint `workflow-mng://nodes/{nodeType}` ### Parameters #### Path Parameters - **nodeType** (string) - Required - The node type identifier (e.g., `builtIn.if`) ### Response #### Success Response - **contents** (array) - An array containing the node information. - **uri** (string) - The URI of the node resource. - **mimeType** (string) - The MIME type of the content, typically 'application/json'. - **text** (string) - A JSON string representing the NodeData structure. **NodeData Structure** ```typescript interface NodeData extends NodeSummary { parametersExamples: ParametersExample[]; } interface ParametersExample { title: string; description: string; parameters: Record; } ``` ### Request Example ``` Get resource: workflow-mng://nodes/builtIn.if ``` ### Response Example ```json { "nodeType": "builtIn.if", "name": "If", "purpose": "Conditional routing node that routes data items to different output ports based on a condition...", "useCases": [ "Conditional workflow branching", "Routing data based on conditions", "Implementing business logic with conditional flows", "Data splitting and categorization" ], "outputPorts": ["true", "false"], "parameterSchema": { "type": "object", "fields": { "condition": { "type": "object", "required": true, "fields": { "path": { "type": "string", "required": true }, "value": { "type": "string", "required": true }, "operator": { "type": "enum", "required": true, "values": ["equals", "notEquals", "contains"] } } } } }, "parametersExamples": [ { "title": "Route Active vs Inactive", "description": "Route items where status equals 'active' to the 'true' port, others to 'false' port.", "parameters": { "condition": { "path": "status", "value": "active", "operator": "equals" } } } ] } ``` ``` -------------------------------- ### Get a Workflow by ID Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Retrieves a stored workflow definition using its unique identifier. Ensure the workflow ID exists to avoid errors. ```typescript const workflow = engine.getWorkflow('my-workflow'); console.log(workflow.title); ``` -------------------------------- ### WorkflowEngine Constructor Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Creates a new WorkflowEngine instance. It automatically registers all built-in node plugins. ```APIDOC ## WorkflowEngine Constructor ### Description Creates a new WorkflowEngine instance. Automatically registers all built-in node plugins (noop, set, marker, if, code, filter, switch). ### Example ```typescript import { WorkflowEngine } from 'hands-on-configuration-tools-by-llm'; const engine = new WorkflowEngine(); ``` ``` -------------------------------- ### Custom Node Implementation Pattern Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Illustrates the standard pattern for implementing a custom node's `execute` method. It shows how to process input batches and items, transform them, and return results for specified output ports. ```typescript async execute( node: WorkflowNode, input: TypedField[][], resolver?: FieldResolver ): Promise> { const result: TypedField[][] = []; // Process each batch for (const batch of input) { const outputBatch: TypedField[] = []; // Process each item in the batch for (const item of batch) { // Transform item const transformed = transformItem(item); outputBatch.push(transformed); } result.push(outputBatch); } // Return output ports return { main: result, // or multiple ports // 'error': errorBatch // optional additional ports }; } ``` -------------------------------- ### Create Workflow Engine Instance Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/README.md Instantiate the WorkflowEngine. The engine automatically registers 7 built-in node types upon creation, making them available for use in workflows. ```typescript const engine = new WorkflowEngine(); // Automatically has 7 built-in node types registered ``` -------------------------------- ### Creating Node Plugins with serializeParameterSchema Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/schema-serializer.md Demonstrates how to use `serializeParameterSchema` within a Node plugin's `getParameterSchema` method. ```typescript import { serializeParameterSchema } from 'hands-on-configuration-tools-by-llm'; export const myPlugin: NodePlugin = { // ... other properties getParameterSchema: () => serializeParameterSchema(MyNodeParametersSchema), // ... }; ``` -------------------------------- ### Format Code Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/README.md Automatically formats the codebase according to predefined style guidelines. This helps maintain a consistent code style across the project. ```bash pnpm format ``` -------------------------------- ### Get Registered Node Types Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Retrieve an array containing the identifiers of all node types currently registered with the engine. This includes both built-in and custom node types. ```typescript const types = engine.getRegisteredNodeTypes(); console.log(types); // ['builtIn.noop', 'builtIn.set', 'builtIn.marker', ...] ``` -------------------------------- ### Registering Plugins with Error Handling Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Demonstrates error handling when registering plugins (nodes) with the engine, covering validation errors and type registration conflicts. ```typescript try { engine.registerNode(plugin); } catch (error) { if (error instanceof NodeValidationError) { console.error('Plugin examples invalid:', error.message); } else if (error instanceof NodeTypeAlreadyRegisteredError) { console.error('Type already registered'); } else { throw error; } } ``` -------------------------------- ### Execute a Workflow (Simple) Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Executes a workflow with its default settings, without providing custom input data or a field resolver. Suitable for workflows that do not require external data or complex resolution logic. ```typescript // Simple execution with no input const result = await engine.executeWorkflow('my-workflow'); if (result.finished) { console.log('Workflow completed'); console.log(result.data); // Results per node } else { console.error('Workflow failed:', result.error); } ``` -------------------------------- ### execute Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/plugin.md Executes a workflow node with given input and returns output batches per port. This function can be synchronous or asynchronous. ```APIDOC ## execute ### Description Executes the node with the given input and returns output batches per port. This function can be asynchronous or synchronous. ### Method `execute` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **node** (`WorkflowNode`) - Required - The node being executed with its parameters. * **input** (`TypedField[][]`) - Required - Input batches, each batch is an array of TypedField items. * **resolver** (`FieldResolver` | undefined) - Optional - Function to resolve link fields. ### Request Example ```typescript async execute( node: WorkflowNode, input: TypedField[][] ): Promise> { const result: TypedField[][] = []; for (const batch of input) { const processed: TypedField[] = []; for (const item of batch) { // Transform item processed.push(transformedItem); } result.push(processed); } return { main: result }; } ``` ### Response #### Success Response (200) * **Record** - Keys are output port names, values are arrays of batches (arrays of TypedField arrays). Empty arrays are valid for ports with no output. #### Response Example ```json { "main": [ [ { "value": "transformedItem1", "kind": "primitive" }, { "value": "transformedItem2", "kind": "primitive" } ] ] } ``` ``` -------------------------------- ### Registering a Custom Tool with MCP Server Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Use `server.registerTool()` to add custom tools to the MCP server. This function takes a tool name, metadata, and a handler function that processes input and returns results. Ensure the handler correctly parses `extra` to access workflow data. ```typescript server.registerTool( 'validate-workflow', { title: 'Validate Workflow', description: 'Validates a workflow definition', }, (extra: unknown) => { const workflow = (extra as { workflow: Workflow }).workflow; try { engine.validateWorkflow(workflow); return { content: [{ type: 'text' as const, text: 'Workflow is valid' }] }; } catch (error) { return { content: [{ type: 'text' as const, text: `Invalid: ${error}` }] }; } } ); ``` -------------------------------- ### Executing Workflows and Handling Results Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Illustrates how to execute a workflow and handle both successful completion and execution errors, including specific `NodeExecutionError` types. ```typescript const result = await engine.executeWorkflow('workflow-id'); if (result.finished) { console.log('Success'); // Process result.data } else { if (result.error instanceof NodeExecutionError) { console.error(`Node ${result.error.nodeId} failed: ${result.error.message}`); } else { console.error('Execution failed:', result.error?.message); } } ``` -------------------------------- ### list-available-nodes Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Lists all currently registered workflow node plugins with summaries of their capabilities. This is useful for initial introspection to see what nodes are available for creating workflows. ```APIDOC ## list-available-nodes ### Description Lists all currently registered workflow node plugins with summaries of their capabilities. ### Parameters None ### Returns ```typescript { content: [ { type: 'text', text: 'Currently available node plugins:\n1. builtIn.noop — ...\n2. builtIn.set — ...\n...' } ], structuredContent: { nodes: NodeSummary[] } } ``` ### NodeSummary Structure ```typescript interface NodeSummary { nodeType: string; // e.g., 'builtIn.if' name: string; // e.g., 'If' purpose: string; // Purpose description useCases: string[]; // Array of use cases outputPorts: string[]; // Output port names parameterSchema: SerializableParameterSchema; // Parameter schema } ``` ### Example Output ``` Currently available node plugins: 1. builtIn.noop — name: Noop | purpose: No-operation node that passes through input data unchanged. Useful as a placeholder or entry point for workflows. | use cases: Creating workflow entry points, Placeholder nodes during workflow design, Passing through data without modification 2. builtIn.set — name: Set | purpose: Add or overwrite fields in data items with static values. | use cases: Adding new fields to data items, Overwriting existing field values, Setting default values, Transforming data structure by adding fields 3. builtIn.marker — name: Marker | purpose: Marks data items with a field (default: "_matched") based on a condition evaluation. Does not route data - all items pass through with the specified field indicating whether the condition was met. | use cases: Marking data items with condition results, Adding metadata for downstream filtering, Condition evaluation without routing, Data validation and marking ... ``` ### Use Case Initial introspection to see what nodes are available. ``` -------------------------------- ### List Available Workflow Nodes Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Command to list all registered workflow node URIs supported by the MCP server. ```text List workflow-node resources ``` -------------------------------- ### Providing a Resolver for Workflow Execution Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Demonstrates how to provide a resolver when executing a workflow to avoid `CodeResolverNotAvailableError`. This is necessary when code nodes use the `resolve()` function. ```typescript // Provide resolver when executing await engine.executeWorkflow('workflow-id', inputData, myResolver); ``` -------------------------------- ### Execute a Workflow with Input and Resolver Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/workflow-engine.md Executes a workflow providing specific input data and a custom field resolver function. This allows for dynamic data injection and external data lookups during execution. ```typescript // Execution with input data and resolver const inputData: ExecutionData = { 'start-node': { main: [[ { value: { id: { value: '123', kind: 'primitive' } }, kind: 'primitive' } ]] } }; const resolver: FieldResolver = async (value, entityName) => { if (entityName === 'user' && typeof value === 'string') { const user = await database.getUser(value); return { name: { value: user.name, kind: 'primitive' }, email: { value: user.email, kind: 'primitive' } }; } return value; }; const result = await engine.executeWorkflow('my-workflow', inputData, resolver); ``` -------------------------------- ### List Available Nodes Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/mcp-server.md Retrieves a list of all registered node URIs available on the MCP server. ```APIDOC ## List Workflow Nodes ### Description Returns a list of all registered node URIs. ### Method GET ### Endpoint `workflow-mng://nodes/` ### Response #### Success Response - **uris** (array of strings) - A list of available node URIs. ### Response Example ``` workflow-mng://nodes/builtIn.noop workflow-mng://nodes/builtIn.set workflow-mng://nodes/builtIn.marker workflow-mng://nodes/builtIn.if workflow-mng://nodes/builtIn.code workflow-mng://nodes/builtIn.filter workflow-mng://nodes/builtIn.switch ``` ``` -------------------------------- ### Batch Processing Data Structure Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/api-reference/execution-model.md Illustrates the structure for organizing data into batches for streaming and bulk operations. ```typescript TypedField[][] // Array of batches, each batch is array of items ``` -------------------------------- ### Validating Workflows with Error Handling Source: https://github.com/damir-manapov/hands-on-configuration-tools-by-llm/blob/main/_autodocs/errors.md Shows how to handle potential errors when adding a workflow to the engine, such as validation failures or ID conflicts. ```typescript try { engine.addWorkflow(workflow); } catch (error) { if (error instanceof WorkflowValidationError) { console.error('Validation failed:', error.message); } else if (error instanceof WorkflowAlreadyExistsError) { console.error('ID conflict:', error.message); } else { throw error; } } ```