Skip to main content
Glama
Svel26

Sigmatek LASAL MCP Server

by Svel26

Sigmatek LASAL MCP Server

CI npm version License: MIT PRs Welcome

A Model Context Protocol (MCP) server for automating the Sigmatek LASAL software suite. It gives AI coding assistants (Claude, Gemini, Cursor, etc.) the ability to compile, deploy to hardware, control PLCs, read/write live values, run HMI simulations, and validate project GUIDs — while the agent edits project files directly.

Warning: This is NOT an official Sigmatek product. This project is in active development — bugs and unpredictable behavior are likely. Do not use on production projects without backups or version control.

Design Philosophy

The MCP only exposes tools for operations that require an external engine or hardware — compiling, deploying, PLC control, LARS soft-runtime simulations — plus the class/manifest operations whose generated formats and caches make raw file edits error-prone (creating a class, registering project files, latin1-safe class source access, resolving GUID collisions). For everything else (reading/editing .lcp, .lcn, .lss, .lvp, dashboard JSON), the AI agent works with the files directly using its native file tools. This keeps the tool set small, reliable, and focused.

Related MCP server: tiacommander-mcp

Features

  • Build & Deploy: Compile CLASS 2 projects, download to PLC, full deploy pipelines (build_project, deploy_all), bootdisk/update-stick creation (plain or Update-Tool flavor with Autoexec, LasalOS image, VISU publish folder; create_class2_bootdisk).

  • Multi-Station Deploy: MachineManager .lutc orchestration — CLASS 2, LASAL SCREEN and VISUDesigner downloads, OS updates, file transfer, run/boot, channel writes, CLI commands (deploy_solution), with the per-run MachineManager log returned for diagnosis.

  • Background Jobs: build_project, deploy_all, deploy_solution and lse_project accept async: true and return a jobId — poll with check_job_status (useful for clients with request timeouts).

  • Headless Hardening: modal engine dialogs (error boxes, crash reporters, WerFault) are auto-dismissed while script runs execute — their text is captured into the tool result instead of hanging the run until someone clicks OK (LASAL_MCP_DIALOG_WATCHER=0 disables).

  • PLC Control: Start/stop PLC runtime, read/write live channel values, query state (control_plc, plc_values).

  • Local Simulation (LARS): Run one LASAL program per LARS instance — one workspace per station (PLC + HMI) so both run simultaneously on separate ports (the MCP probes the port each instance actually serves). Point stations at the local runtime with a single call, compile/download/start/read values exactly like a real PLC, and browse the HMI via DataService. LARS also renders LASAL SCREEN projects locally, with window screenshots for visual verification. No hardware needed (lars_runtime).

  • CLASS 2 Batch Engine: Create/delete networks, add/remove objects, manage connections, configure tasks — operations that require the CLASS 2 scripting engine (apply_project_changes, run_class2_script).

  • GUID & CRC-32 Validation: Auto-resolve duplicate GUID collisions across classes/MaeExp.txt and compute exact IEEE 802.3 CRC-32 hashes for @CT_ tables (validate_guids).

  • VISUDesigner Engine: Sync datapoints, manage text lists/schemes/media, publish, download to HMI (visu_project).

  • LASAL SCREEN (LSE) Engine: Drive classic panel HMI .lpr projects via the LASALScreen COM automation — inventory, compile, download, merge/fuse, text-list translation edits, variable import from CLASS 2, bulk theming, settings (lse_project).

  • HMI Simulation: Local web runtime via LasalVISUDataService returning accessible HTTP URLs for browser inspection or external Playwright MCP testing (hmi_runtime).

  • PLC Diagnostics: Tracing, file transfer, static code analysis (plc_diagnostics).

  • MCP Resources: Built-in resources for file documentation (lasal://guide), live project status (lasal://project/status), active stations (lasal://stations), and class sources (lasal://classes/{className}).

  • Autocompletions: Context-aware MCP completions for class names and station names.

Prerequisites

  • Windows OS (Sigmatek LASAL suite runs exclusively on Windows).

  • Node.js v18 or higher.

  • Sigmatek LASAL Suite:

    • LASAL CLASS 2 (PLC engineering).

    • VISUDesigner (web HMI design).

    • LASAL SCREEN (LSE, classic panel HMI design — required for lse_project).

    • MachineManager (optional — required for deploy_solution).

Quick Start (with npx)

No repository clone or build required — configure your favorite MCP client to run directly via npx:

Claude Desktop

Add to %APPDATA%\Claude\claude_desktop_config.json:

{
  "mcpServers": {
    "lasal-mcp": {
      "command": "npx",
      "args": ["-y", "lasal-mcp"]
    }
  }
}

Cursor

Add to your project's .cursor/mcp.json (or global Cursor MCP settings):

{
  "mcpServers": {
    "lasal-mcp": {
      "command": "npx",
      "args": ["-y", "lasal-mcp"]
    }
  }
}

Claude Code

Run:

claude mcp add lasal-mcp npx -y lasal-mcp

Local Installation & Setup (for Developers)

git clone https://github.com/Svel26/Lasal-MCP.git
cd Lasal-MCP
npm install
npm run build

When running from a local clone, point your MCP client to:

{
  "mcpServers": {
    "lasal-mcp": {
      "command": "node",
      "args": ["C:/path/to/Lasal-MCP/dist/server.js"]
    }
  }
}

Configuration

Environment Variables

Variable

Default

Purpose

LASAL_CLASS2_EXE

C:\Program Files (x86)\Sigmatek\Lasal\Class2\Bin\Lasal2.exe

CLASS 2 IDE path

LASAL_VISUDESIGNER_EXE

C:\Program Files\Sigmatek\Lasal\VISUDesigner\VISUDesigner.exe

VISUDesigner path

LASAL_SCREEN_EXE

C:\Program Files (x86)\Sigmatek\Lasal\Screen\LSE_modeless.exe

LASAL SCREEN (LSE) editor / COM automation server path

LASAL_MACHINEMANAGER_EXE

C:\Program Files (x86)\Sigmatek\Lasal\MachineManager\Bin\MachineManager.exe

MachineManager path

LASAL_DATASERVICE_EXE

auto-discovered (latest version)

DataService path

LASAL_MCP_TIMEOUT_COMPILE

600000

Compile timeout (ms)

LASAL_MCP_TIMEOUT_DOWNLOAD

600000

Download timeout (ms)

LASAL_MCP_TIMEOUT_VISU

300000

Visu operation timeout (ms)

LASAL_MCP_TIMEOUT_SCRIPT

120000

Script execution timeout (ms)

LASAL_MCP_TIMEOUT_LSE

300000

LASAL SCREEN operation timeout (ms)

LASAL_MCP_TIMEOUT_MM

900000

MachineManager update timeout (ms)

LASAL_MCP_DIALOG_WATCHER

1

Auto-dismiss modal engine dialogs during script runs and report their text. Set to 0 to disable.

LASAL_LARS_EXE

C:\Program Files (x86)\Sigmatek\Lars\Lars.exe

LARS runtime path

LASAL_LARS_CONFIG

%APPDATA%\lasalos2.xml

LARS workspace config file

LASAL_MCP_HMI_DIR

C:\lslvisu

Local HMI runtime directory

LASAL_MCP_SCRATCH_MAX_AGE_H

24

Hours before temp files are cleaned

LASAL_MCP_STATE_FILE

<repo>/lasal-state.json

Override the MCP state file (unit tests use it to stay off live state)

Available Tools

Engine & Hardware Tools (MCP)

Tool

Description

select_project

Set the active project root directory.

lasal_status

Check project, stations, engines, processes, HMI health.

check_job_status

Poll background jobs started with async: true (or list recent jobs).

inspect_project

Read-only class/network/object inventory (channels, tasks) from the manifest + class sources.

validate_guids

Scan a station project for duplicate GUID collisions and uninitialized TO_UDINT(0) placeholders; auto-resolves GUID collisions and populates exact CRC-32 @CT_ hashes.

read_class_source

Read or write a class .st (and optional .h) by class name; latin1-validated.

set_target_ip

Update a station's target IP/port/SSL in its .lss, preserving other settings.

manage_class2

Open or close the CLASS 2 IDE.

manage_visudesigner

Open or close VISUDesigner.

manage_lasalscreen

Open or close the LASAL SCREEN (LSE) editor.

build_project

Compile or download to PLC (supports async: true).

create_class2_bootdisk

Create a CLASS 2 bootdisk / update stick (plain or Update-Tool flavor with Autoexec, OS image, VISU publish folder).

control_plc

Start, stop, or query PLC runtime state.

plc_values

Read/write live channel values on a running PLC.

lars_runtime

Local LARS simulation: list/setup workspaces per station (wires CLASS 2 + LASAL SCREEN projects), start/stop, simulate (one-call loop: ARM→PC switch, compile, start, download), screenshot of the rendered screen, point stations at the probed effective port (set_station_target), revert (restore), switch ARM projects to the PC target (target_pc).

apply_project_changes

Batch engine operations (networks, objects, connections, tasks, compiler version, compile/download) and file-level class operations: create_class, add_project_file, clean_project (incl. deep artifact purge).

run_class2_script

Escape hatch: run arbitrary Python 2.7 batch statements through Lasal2.exe for API calls not exposed as operations.

visu_project

VISUDesigner engine operations (text lists, schemes, media, publish, download).

lse_project

LASAL SCREEN engine operations via COM automation: info, compile, download, merge/fuse, XML text export/import, CLASS 2 variable import, text-list translations, bulk button/softkey theming, settings, images.

hmi_runtime

Start/stop local HMI web simulation (DataService) and return accessible URL.

plc_diagnostics

Tracing (DataAnalyzer), file transfer on the control, code analysis (project or single file), OS download, RAM-image clear, project-on-PLC backup, connection-file download.

deploy_all

Full pipeline: compile → download → start PLC → compile LASAL SCREEN → optional SCREEN download → sync visu → start HMI.

deploy_solution

Multi-station MachineManager deploy via generated .lutc: CLASS 2 / LASAL SCREEN / VISUDesigner downloads, OS, files, run/boot, writes, CLI.

MCP Resources

URI

Description

lasal://guide

Comprehensive guide on LASAL file formats, ST structure, and runtime JS API.

lasal://project/status

Dynamic JSON resource reporting selected project, discovered stations, HMI runtime status, and LARS instances.

lasal://stations

Live list of stations in the active solution and their target connections.

lasal://classes/{className}

Direct read access to Structured Text (.st) sources by class name with autocompletion.

Direct File Editing (no MCP needed)

The agent edits these files directly with its native file tools:

File

Format

Encoding

What it contains

.lsm

XML

latin1

Solution — lists all stations

.lss

XML

latin1

Station settings — target IP, project references

.lcp

XML

latin1

CLASS 2 project manifest — class and network file paths

.st

Generated declaration + ST

latin1

Class source — //{{LSL_DECLARATION metadata, class body, @CT_ table, methods; prefer read_class_source

.lcn

XML

latin1

Network definitions — objects, connections, init values

.lvp

Mixed

utf-8

VISUDesigner project manifest

.lpr

Binary

mixed

LASAL SCREEN project — never edit directly; drive via lse_project

LSEOnlineConfig.xml

XML

latin1

LASAL SCREEN online/download target (updated by set_target_ip)

Dashboard JSON

JSON

utf-8

HMI dashboards, windows, controls, property bindings

See the built-in lasal://guide resource for detailed file format documentation.

Development

npm run dev          # Watch mode
npm test             # Run unit tests (Vitest)
npm run test:lab     # Integration tests against the local LASAL installation (creates fresh projects)
npm run test:watch   # Tests in watch mode
npm run lint         # ESLint
npm run format       # Prettier
npm run inspector    # MCP Inspector for interactive debugging

Simulating without hardware (LARS)

LARS (LASAL Runtime System) runs LASAL programs on a normal PC. Since each LARS instance runs one program, the MCP creates one workspace per station:

  1. lars_runtime setup — creates workspaces for every station in the selected solution.

  2. lars_runtime start <station> — launches the LARS window for that station and reports the effective online port it probed.

  3. lars_runtime set_station_target <station> — points the station's .lss at that effective port (refuses to target a port that is not answering).

  4. Now build_project, control_plc, and plc_values work unchanged against the local runtime.

  5. lars_runtime restore <station> — reverts the .lss to the real hardware target.

Shortcut: lars_runtime simulate does the whole loop in one call — creates the workspace if needed (CLASS 2 + LASAL SCREEN), switches ARM targets to PC, compiles, starts the LARS instance (probing its effective online port) and downloads to it.

How the online port is resolved

Workspaces get distinct port blocks in lasalos2.xml (1954, 1964, 1974, …), but LARS builds differ in which port they actually serve: older builds bind the workspace's ONLINE port, while the field-tested 01.03.216 build serves the default port 1954 for a single instance (and a second parallel instance on that build exposes no online port at all). The MCP therefore probes what actually answers (workspace ONLINE port first, then 1954) and never assigns a port another running instance already owns — PLC and HMI end up on distinct ports whenever the LARS build provides them, and a workspace that answers nowhere fails loudly instead of pointing a station at a dead port. lars_runtime list and lasal_status report the resolved port as effectiveOnlinePort.

Notes:

  • Projects compiled for Processor="ARM" (most machine PLCs) need lars_runtime target_pc first — LARS is an x86 runtime and rejects ARM images.

  • HMI panel / Local stations are already PC-targeted and work directly.

  • Downloads to LARS automatically include the PC loader (addLoaderAnyway).

  • %APPDATA%\lasalos2.xml is edited losslessly — the MCP updates only the fields it owns and preserves everything else, so the file stays interchangeable with Sigmatek's LARSConfigTool (Desc attributes, DATASERVICETCPPORT, comments, extra drive mappings).

  • hmi_runtime remaps published stations.json entries to running LARS instances, so the web HMI talks to the local simulation.

  • Stations with a LASAL SCREEN project get their .lpr wired into the LARS workspace (SCREEN_PRJ_PATH), so LARS renders the panel screens locally; lars_runtime screenshot returns a PNG of the window for visual verification.

Contributing

Contributions are welcome! Please check out CONTRIBUTING.md for guidelines on code standards, adding tools, and submitting pull requests.

Releasing & CI/CD

Automated releases and publishing to npm are powered by GitHub Actions. Releases can be triggered manually via workflow dispatch with automated version bumping or by pushing version tags (v*.*.*).

License

This project is licensed under the MIT License.

Available Tools

23 tools
apply_project_changesA
Destructive

Run CLASS 2 batch engine operations that cannot be done by editing files directly: create/delete/rename networks, add/remove/rename objects, create/delete connections, set init values, configure tasks, compile, download. Kills CLASS 2 IDE before running.

NameRequiredDescriptionDefault
dry_runNoValidate operations without applying them.
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.
operationsYesOrdered list of operations. Batch engine types: create_network, delete_network, rename_network, duplicate_network, add_object, remove_object, rename_object, change_object_class, create_connection, delete_connection, set_init_value, delete_class, compile, download, set_task_order, set_task_time, set_task_cpu_core, set_multi_cpu_core, set_visualized_flag, set_comment_network, set_comment_object, set_network_options, reset_network_options, move_network_to_folder, set_parameter_value, set_compiler_version, copy_class, copy_network, replace_object, add_library, import_lcz, update_referenced, calculate_resources, mm_change_connection, mm_update_server_list, set_project_revision. File-level types (applied before the batch engine, no CLASS 2 API): create_class, add_project_file, clean_project.

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, so the safety profile is partly covered. The description adds a genuinely non-obvious behavioral trait beyond the annotations: it kills the CLASS 2 IDE before running, which an agent must warn the user about. It stops short of describing failure/rollback behavior or whether the IDE is restarted afterward.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Only two sentences, but the long middle enumeration of operation types is redundant with the schema's own list. More importantly, the critical safety note ('Kills CLASS 2 IDE before running') is buried at the very end rather than front-loaded, which is poor structure for a destructive tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and only a single destructive annotation, so the description carries substantial burden for a 40+ operation batch tool. It omits ordering/failure semantics (schema notes 'Ordered list' but the description does not address partial-failure behavior) and never says what a successful run returns. Adequate but with clear gaps given the complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents every parameter and every operation variant. The description's operation enumeration largely restates what the operations schema already lists. Baseline 3 is appropriate; no additional syntax or format meaning is conveyed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Run CLASS 2 batch engine operations') and enumerates the resources it touches (networks, objects, connections, tasks, compile, download). It also frames itself against file editing ('cannot be done by editing files directly'), giving a boundary. However, it never names sibling tools like manage_class2 or run_class2_script to disambiguate the batch-engine path from the scripting path.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is an implied usage boundary – operations that cannot be done by editing files directly – which helps an agent decide. But there are no explicit when-not conditions, no named alternatives for the operations that CAN be done via file edits, and no prerequisites (e.g. target connection state) stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

build_projectA

Compile the CLASS 2 project or download it to the PLC. Compilation kills CLASS 2 IDE. Download pings the PLC first. Supports async: true — the call then returns immediately with a jobId and you MUST poll check_job_status until it reports status completed/failed (the result is delivered there).

NameRequiredDescriptionDefault
asyncNoRun in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.
actionYes'compile' builds the project; 'download' transfers it to the PLC.
optionsNoCompile mode (compile only). RebuildAll is safest; BuildChanges is faster for incremental work.RebuildAll
lcp_pathNoAbsolute path to the .lcp file. Omit to use the selected project.
timeout_sNoTimeout in seconds for compile or download. Omit for default (600s).
connectionNoConnection string (e.g. 'TCPIP:192.168.1.100') or address-book name (download only). Omit to use the connection saved in the .lss file.
add_loader_anywayNoForce loader download even if the target OS already has a compatible loader (download only). Default: auto — the loader is sent for local LARS/loopback targets, skipped otherwise. Set false to disable, true to force.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Only openWorldHint is annotated, so the description carries the burden and does so well: it discloses the side effect that compilation kills the CLASS 2 IDE, that download pings the PLC first, and that async returns a jobId whose result must be retrieved via check_job_status. This is exactly the destructive/lifecycle context annotations do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb/resource, then builds outward to side effects and async workflow. Every sentence carries distinct, non-redundant information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter build/deploy tool with no output schema, it covers the critical gaps: side effects, the PLC ping, and the async job/poll workflow. It stops short of describing the sync return value or result shape, a minor omission given the otherwise strong behavioral coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents action, options, async, timeout, connection, lcp_path, and add_loader_anyway in detail. The description reinforces the async parameter's return contract but adds little meaning beyond what the structured fields already contain, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (compile/download) and resource (CLASS 2 project), and explicitly names the sibling it hands off to (check_job_status) when async is used. An agent can tell it apart from deploy_all/deploy_solution without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context: compile vs download distinction is present, async usage is spelled out with the mandatory polling loop. It does not, however, contrast this tool against the other deployment siblings (deploy_all, deploy_solution), so the alternative-choice guidance is incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_job_statusA
Read-onlyIdempotent

Poll the status of a background job started with async: true (build_project, deploy_all, deploy_solution, lse_project). Omit jobId to list recent jobs.

NameRequiredDescriptionDefault
jobIdNoJob id returned by an async tool call (status 'pending'). Omit to list recent jobs.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered; the description adds the genuinely useful behavior that an omitted jobId turns this into a recent-jobs listing. It still says nothing about returned status values, terminal states, or whether polling is throttled.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, and the primary use case is front-loaded before the optional list mode. Every clause carries information the agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description could say more about the shape of a status response (e.g., pending/running/done fields), but for a single-optional-parameter polling tool with annotations covering safety, what is present is close to sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the description restates the jobId semantics almost verbatim from the schema ('omitted to list recent jobs'). The only added nuance is that the id came from an async call with status 'pending', which is marginal beyond structured data.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (poll) plus resource (status of a background job), with the exact originating tools named (build_project, deploy_all, deploy_solution, lse_project). An agent can distinguish this from unrelated siblings like control_plc or plc_values without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear trigger condition — only jobs started with async: true — and states that omitting jobId switches the tool into list-recent-jobs mode. It does not spell out a when-not case or name a competing status tool, so it falls just short of a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

control_plcB
Destructive

Start, stop, or query PLC runtime state. Pings the target PLC before start/stop.

NameRequiredDescriptionDefault
actionYes'start' runs the PLC project; 'stop' halts it; 'get_state' queries its current state.
lcp_pathNoAbsolute path to the .lcp file. Omit to use the selected project.
connectionNoConnection string or address-book name. Omit to use the project's saved connection.

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare openWorldHint=true and destructiveHint=true, so the agent knows the tool reaches out and can cause destructive effects. The description adds a genuine behavioral detail beyond that — a preflight ping of the target PLC before start/stop — but says nothing about the consequences or reversibility of halting a running PLC, which is the most decision-relevant side effect.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the action set front-loaded and the preflight ping follow-up. Nothing is padded and no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description should say more about what get_state returns and what the ping/start/stop operations produce on failure. It covers purpose and one side effect adequately, and annotations carry the safety profile, but a destructive multi-action control tool warrants more detail than is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so action, lcp_path, and connection are fully documented in the schema including the enum semantics and the 'omit to use default' behavior. The description adds no syntax, format, or interaction detail beyond what the schema already provides, making baseline 3 correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb set (start, stop, query) and the exact resource (PLC runtime state), so the agent knows this is the control tool rather than a read-only one. It does not, however, distinguish itself from siblings like lasal_status or lars_runtime, which may also surface runtime state, leaving some ambiguity in a crowded toolset.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to prefer this over lasal_status, plc_diagnostics, or lars_runtime, nor any exclusion or prerequisite guidance. The only guidance is the implicit mapping of the three actions, which the schema already conveys.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_class2_bootdiskA
Destructive

Create a CLASS 2 bootdisk (update stick): plain bootdisk or the full Update-Tool flavor with update script, Autoexec.lsl, LasalOS image, VISUDesigner publish folder and MultiMaster Stations.txt. Platform AUTO/ALL/ARM/X86.

NameRequiredDescriptionDefault
modeNoBootdisk flavor. Default: update_stick when any of os_file/visu_publish_folder/autoexec_file/add_autoexec/update_script is used, otherwise simple.
os_fileNoLasalOS image (.lbi) to include (update-stick mode).
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.
platformNoTarget architecture: AUTO (project target), ALL, ARM or X86. Default AUTO.AUTO
overwriteNoOverwrite existing bootdisk content. Default true.
timeout_sNoTimeout in seconds. Default 300.
lvd_runtimeNoWhen a VISUDesigner publish folder is set: also use its Runtime directory. Default true.
output_pathYesDirectory to write the bootdisk into (e.g. a prepared USB stick root).
add_autoexecNoPlace an autoexec.lsl into the destination directory that starts the update script (update-stick mode).
autoexec_fileNoPath of a regular Autoexec.lsl to place on the PLC (update-stick mode).
update_scriptNoUpdate-tool script flavor (update-stick mode): none, all (runs every update) or menu. Default none.none
all_lobs_in_oneNoWrite all .lob files into a single file.
visu_publish_folderNoVISUDesigner 'Publish' folder to bundle into the update (update-stick mode).
add_multimaster_stationsNoCopy the MultiMaster Stations.txt into the destination (update-stick mode). Default true.
use_active_connection_filesNoUse the project's active connection files (update-stick mode). Default true.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint annotation already signals that this operation can destroy/overwrite data. The description adds useful context about what a bootdisk contains and that platform selection is supported, but it does not mention overwrite behavior, output location requirements, permissions, or other operational constraints beyond what the annotation and schema provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action, uses two tight sentences, and avoids unnecessary repetition. The flavor details are packed efficiently without burying the main purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 15 parameters, a destructive hint, and no output schema, the description is adequate at the purpose level but incomplete for usage context. It relies heavily on the schema for parameter details and does not explain prerequisites such as how the selected project or omitted lcp_path affects the operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 15 parameters thoroughly. The description adds only a high-level mention of platform values and update-stick contents, which is marginal beyond the detailed enum and parameter descriptions already present.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb 'Create' and resource 'CLASS 2 bootdisk', and distinguishes the two output flavors (plain bootdisk vs. full Update-Tool). This lets an agent identify the tool as the bootdisk-creation operation among siblings like manage_class2 and deploy_all.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains what can be produced, but gives no explicit when-to-use guidance, prerequisites, or alternatives. It does not tell the agent when to choose this tool over related deployment or management tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

deploy_allA

Full deploy pipeline: compile → download PLC → start PLC → verify state → compile LASAL SCREEN (.lpr, when present) → optional SCREEN download → update Visu stations → download Visu → start HMI runtime. Each step is optional via flags. Supports async: true — the call then returns immediately with a jobId and you MUST poll check_job_status until it reports status completed/failed (the result is delivered there).

NameRequiredDescriptionDefault
asyncNoRun in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.
compileNoCompile the CLASS 2 project. Default true.
lse_runNoStart the screen runtime on the target after download (Download & Run). Default true.
lcp_pathNoAbsolute path to the .lcp file. Omit to use the selected project.
lse_pathNoAbsolute path to the .lpr (LASAL SCREEN) project. Omit to auto-detect from the selected project.
lvp_pathNoAbsolute path to the .lvp file. Omit to auto-detect from the selected project.
start_plcNoStart the PLC runtime after a successful download. Default true.
timeout_sNoTimeout override in seconds for compile and download steps.
compile_lseNoCompile the LASAL SCREEN project (writes the Runtime output folder). Skipped when there is no .lpr. Default true.
download_lseNoDownload the LASAL SCREEN project to its station (requires lse_connection or a station target in the solution). Default false.
download_plcNoDownload the compiled CLASS 2 project to the PLC. Default true.
download_visuNoDownload the VISUDesigner project to the HMI after updating stations. Requires visu_connection. Default false.
add_plc_loaderNoForce loader download to PLC even if the target already has a compatible loader. Default: auto — sent for local LARS/loopback targets, skipped otherwise. Set false to disable, true to force.
lse_connectionNoSCREEN download target, e.g. 'TCPIP:192.168.1.50'. Omit to resolve from the station that owns the .lpr.
plc_connectionNoPLC connection string (e.g. 'TCPIP:192.168.1.100'). Omit to use the connection saved in the project's .lss file.
compile_optionsNoCompile mode. RebuildAll is safest; BuildChanges is faster for incremental work.RebuildAll
visu_connectionNoHMI connection string (e.g. 'TCPIP:192.168.1.100'). Required when download_visu is true.
add_visu_runtimeNoForce runtime download to HMI even if the version already matches.
start_hmi_runtimeNoStart the local HMI runtime (DataService) and copy HMI files after a successful compilation/update. Default false.
visu_download_flagsNoVISUDesigner download mode: 0=normal (default), 1=changes only, 2=publish+download changes.
update_visu_stationsNoRun update_all_stations on the VISUDesigner project to sync datapoints after CLASS 2 changes. Default true.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations provide only `openWorldHint: true`, so the description carries most of the burden — and it does disclose the key non-obvious behavior: asynchronous execution returns immediately with a jobId and the real result is delivered via check_job_status, not in this response. It also reveals that steps are skipped conditionally (LSE compile skipped when no .lpr; loader auto-sent only for local loopback targets). It does not disclose partial-failure semantics, whether a failed mid-pipeline deploy leaves the PLC/HMI in an inconsistent state, or permission/auth requirements for a tool that physically writes to and starts hardware.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the pipeline order and then the async contract — no filler or restated title. The pipeline enumeration is dense but every stage listed corresponds to a real flag, so it earns its space. A short structural break between the pipeline description and the async/mode guidance would improve scanability for a 21-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity, zero-required-parameter tool with no output schema, the description correctly compensates by explaining where the result actually appears (the job record polled via check_job_status) and what the pipeline does end-to-end. Given `openWorldHint: true` and hardware-mutating side effects, it still omits failure/recovery behavior and the deploy_solution relationship, leaving modest gaps for a tool this consequential.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; the description earns a point by supplying cross-parameter meaning the schema does not — namely the execution ordering of the flags and the fact that any stage can be individually disabled. The async contract is stated in prose as well as in the schema, reinforcing which parameter drives the job/poll flow. It adds nothing, though, about interactions between flags (e.g. start_plc with compile=false).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the tool's specific action and enumerates the exact pipeline stages in execution order (compile → download PLC → start PLC → verify → LSE compile → SCREEN download → update/download Visu → start HMI), which is far more informative than a generic 'deploy' label. However, it never distinguishes itself from the sibling tool `deploy_solution`, which appears to be a near-overlapping deploy entry point, so an agent cannot tell the two apart from the text alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear operational directive for one mode: with `async: true` the call returns a jobId and the caller 'MUST poll check_job_status until it reports status completed/failed', naming the sibling tool to use. It also states each pipeline step is individually optional via flags, implying the whole-pipeline usage. What is missing is when NOT to use this tool versus `deploy_solution` or the granular per-stage tools like build_project/hmi_runtime.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

deploy_solutionA
Destructive

Multi-station deploy via MachineManager: generates a .lutc update file from the solution (class2/screen/visu downloads, OS updates, file transfers, run/boot, channel writes, CLI commands) and executes it with MachineManager.exe /update. This is the official flow for pushing LASAL SCREEN projects together with CLASS 2 to the same panel. Use dry_run to review the generated .lutc first. The newest MachineManager per-run log is returned with the result. Supports async: true — the call then returns immediately with a jobId and you MUST poll check_job_status until it reports status completed/failed (the result is delivered there).

NameRequiredDescriptionDefault
asyncNoRun in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.
dry_runNoGenerate and return the .lutc without executing MachineManager (plan review).
lsm_pathNoPath to the .lsm solution. Omit to use the selected project.
stationsYesOrdered per-station deploy steps. Instructions are emitted per station in field order: class2 → screen → visu → run → write → cli → packages → os → boot → files.
utc_pathNoWhere to write the generated .lutc update file (default: MCP scratch directory).
timeout_sNoTimeout override for the whole update run.
machine_nrNoMachine number used in the update log, e.g. "042". Default "000".

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and openWorldHint=true, so the safety profile is covered; the description adds material behavior beyond that — it generates a .lutc plan file, shells out to an external executable, returns the newest per-run log, and imposes a strict polling contract for async runs. It does not describe what state is overwritten on target stations or whether a run can be aborted/rolled back, which is the remaining gap for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded in the first sentence, and the following sentences each carry distinct information (dry_run review, log return, async contract). The parenthetical enumeration of step types makes the first sentence heavy, but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes on return-value disclosure and does it well: it names the log returned, the dry_run preview artifact, and the jobId/status shape for async runs, plus the required polling loop. It omits prerequisites (target reachability, permissions) and the blast radius of the deploy, which would round out a destructive multi-station operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description only elaborates on dry_run and async; the semantics of lsm_path, utc_path, timeout_s, machine_nr and the entire nested stations schema are left to the schema. It adds no formatting or constraint detail beyond what is already documented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb (multi-station deploy), the exact mechanism (MachineManager.exe /update) and the artifact produced (.lutc), and it scopes the tool to the LASAL SCREEN + CLASS 2 combination. It stops short of differentiating from the sibling deploy_all, which an agent could plausibly confuse it with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives actionable guidance ("Use dry_run to review the generated .lutc first") and states the mandatory async workflow (set async:true, then MUST poll check_job_status until completed/failed), naming the sibling to poll. It never states when not to use this tool or how it relates to deploy_all.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

hmi_runtimeA

Start, stop, or check the local HMI web simulation (LasalVISUDataService). Publishes the project, copies webroot, and spawns the DataService. Returns the accessible HTTP URL (e.g. for testing via Playwright MCP or opening in a browser).

NameRequiredDescriptionDefault
actionYesAction to perform on the HMI runtime DataService.
lvp_pathNoAbsolute path to the .lvp file. Omit to use the currently selected project.
debugPublishNoUse debug publish (requires TypeScript project support). Fallback to standard publish on failure. Default true.
publishFirstNoPublish the project before starting the DataService. Default true.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply openWorldHint=true, so the description carries most of the behavioral burden and does so well: it discloses the concrete side effects of start (publishes the project, copies webroot, spawns the DataService) and what comes back (an HTTP URL). It stops short of stating whether stop tears down the spawned process, how port conflicts are handled, or what status reports, so it is not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with zero waste: the action scope leads, the side effects follow, and the return value closes. Nothing is repeated from the schema and nothing extraneous is included.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description covers the return value (an accessible HTTP URL) and the side effects of the mutating actions, which is the main thing an agent needs for a four-parameter runtime-control tool. Thin annotations (openWorldHint only) leave room for more on failure modes and stop semantics, keeping it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with an enum on action and defaults documented for debugPublish and publishFirst, so the schema does the heavy lifting and the baseline is 3. The description adds process context (that start triggers publish and webroot copy) but no parameter-level syntax or default behavior beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states specific verbs (start, stop, check) against a specific resource (the local HMI web simulation, named internally as LasalVISUDataService), and the word 'HMI web simulation' distinguishes it from the sibling lars_runtime. An agent can tell what it does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It hints at the use case ('for testing via Playwright MCP or opening in a browser'), which implies the intended context, but it never states when to choose this over deploy_all, lars_runtime, or the other runtime/deploy siblings, and gives no prerequisites or exclusion conditions. Usage is implied rather than guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

inspect_projectA
Read-onlyIdempotent

Read-only inventory of the CLASS 2 project: classes (name, channels, tasks), networks and objects, from the .lcp manifest and class sources. Use it to plan changes before apply_project_changes.

NameRequiredDescriptionDefault
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.
class_namesNoReturn full channel details only for these class names. Omit to get a summary of all classes (name + channel counts). Use this to drill into specific classes after the initial summary.
include_networksNoInclude network objects in the output. Default false to keep output small.
include_connectionsNoInclude network connections in the output (requires include_networks). Default false.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered; the description adds genuine extra context by naming the underlying data sources (.lcp manifest and class sources) that determine what the inventory reflects. It stops short of describing behavior on a missing/invalid lcp_path or the summary-vs-detail output tradeoff, which would have pushed it higher.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both earning their place: the first defines scope and payload, the second routes the agent to the follow-up tool. Front-loaded with the read-only inventory statement and no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does outline the returned entities (classes, channels, tasks, networks, objects) and points at the manifest as the source, which is adequate for a four-parameter read tool. Minor gaps remain around failure behavior for an invalid lcp_path and the exact summary-vs-full output distinction.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the four parameters are already fully documented in the schema, including the drill-down semantics of class_names and the include_networks/include_connections dependency. The description only echoes the return shape ('classes (name, channels, tasks)') and adds no format or defaulting detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read-only inventory of the CLASS 2 project') and enumerates exactly what is returned (classes with name/channels/tasks, networks and objects). It also names its data sources (.lcp manifest and class sources), which makes it clearly distinguishable from mutation siblings like apply_project_changes and manage_class2.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the use case: 'Use it to plan changes before apply_project_changes,' which gives the agent a clear trigger. It does not, however, distinguish this tool from other read siblings such as read_class_source or lse_project/visu_project, so the agent gets context but no exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lars_runtimeA

Manage local LARS (LASAL Runtime System) simulation instances. LARS runs one program per instance — use one workspace per station (PLC + HMI) so both run simultaneously on separate ports. Actions: list (auto-cleans stale workspaces), setup (create workspaces for all stations), start (auto-creates the workspace if the station is known but unconfigured), stop, remove, gc (lazy cleanup of unreferenced workspaces), set_station_target (point a station's .lss at its LARS instance), restore (revert .lss to the real target. After set_station_target, build_project/control_plc/plc_values/deploy_all operate on the LARS instance automatically.

NameRequiredDescriptionDefault
nameNoLARS workspace name (e.g. 'VisuPalletizer_PLC'). Required for start/stop/remove/set_station_target/restore when station is omitted.
actionYes'list' shows all configured LARS workspaces and their state (auto-cleans stale ones, but never the selected project's). 'setup' creates/updates LARS workspaces for the selected project's stations (or one station/lcp), wiring both the CLASS 2 project and the LASAL SCREEN (.lpr) project so LARS renders the screen locally. 'start' launches a LARS instance (auto-creates the workspace first if the station is known but unconfigured); reports the effective online port it probed (LARS builds differ in which port they serve). 'stop' terminates it, 'remove' deletes its workspace config. 'gc' runs lazy garbage collection: deletes auto-created workspaces that are not running and no longer referenced by any station .lss or published DataService stations.json, while always keeping workspaces of the selected project. 'set_station_target' points a station's .lss at the online port its LARS instance actually services (probed; never a port another running instance owns); 'restore' reverts to the saved real target. 'target_pc' switches an ARM-compiled .lcp to the PC (x86) compile target LARS requires (restore via 'restore'). 'simulate' runs the full no-hardware loop in one call: ensure workspace (auto-creates), switch ARM targets to PC, compile, start the local LARS instance (probing its effective online port), then download to it. 'screenshot' captures the LARS window of a running workspace (returns the PNG) — use it to visually verify LASAL SCREEN projects running locally.
dry_runNoWith action 'gc': report what would be removed without deleting anything. Default false.
stationNoStation name from the selected project's solution (e.g. 'PLC', 'HMI', 'Local'). Resolution is scoped to the selected project; a station that only exists in another project's workspace is refused, and multiple matches report an ambiguity error and list the candidates. Pass name= to disambiguate. Mutually exclusive with name.
lcp_pathNoAbsolute path to a .lcp to create a workspace for (setup only, when no station name is usable).
min_age_hNoWith action 'gc': only delete workspaces unreferenced for at least this many hours (overrides LASAL_MCP_LARS_GC_MIN_AGE_H; 0 = immediately.
project_dirNoSolution directory to auto-detect stations from and to scope station resolution (setup/list/start/stop/set_station_target/restore/target_pc/simulate. Defaults to the selected project.
compile_modeNoWith action 'simulate': CLASS 2 compile mode. Default RebuildAll (safest).RebuildAll
skip_compileNoWith action 'simulate': skip the CLASS 2 compile step (reuse the existing build). Default false.
skip_downloadNoWith action 'simulate': skip the download step (only compile + start). Default false.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only carry openWorldHint=true, so the description does the heavy lifting — and it does: list auto-cleans stale workspaces (never the selected project's), start auto-creates an unconfigured workspace and probes the effective online port, gc is lazy and preserves referenced/selected-project workspaces, set_station_target never claims a port another instance owns, and station resolution is refused for cross-project names and errors on ambiguity. Mutation semantics (remove deletes workspace config, restore reverts .lss) are also explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose sentence, then the workspace-per-station rule, then an action inventory in one dense block. It is long but proportional to 11 actions; the only waste is partial overlap between the action list in the description and the enum descriptions in the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly notes what is returned for the two outlier actions (start reports the probed port, screenshot returns the PNG) and covers scoping, auto-creation, and cleanup policies. What it does not cover is failure behavior for the mutating actions in general and any timing/latency expectations for launching an instance.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3; the description adds genuine value on top, noting that name is required for start/stop/remove/set_station_target/restore when station is omitted, that name and station are mutually exclusive, and how station resolution is scoped to the selected project.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Manage local LARS (LASAL Runtime System) simulation instances') and enumerates every action with a one-line gloss so an agent can select among them without opening the schema. It also explicitly distinguishes itself from siblings by naming build_project/control_plc/plc_values/deploy_all as the tools that consume the LARS state it sets up.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operating advice ('use one workspace per station (PLC + HMI) so both run simultaneously') and per-action usage context (simulate runs the full no-hardware loop in one call; screenshot is for visually verifying LASAL SCREEN projects). It does not explicitly compare itself to close siblings such as hmi_runtime or when *not* to use LARS, so it falls short of a full when/when-not/alternative statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lasal_statusA
Read-onlyIdempotent

Check project selection, station discovery, PLC/HMI reachability, engine paths, running processes, and HMI runtime health. Call to orient or diagnose connection issues.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description usefully signals that this is a broad multi-check aggregator rather than a single probe, but adds nothing about latency, cost, or what a degraded result looks like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler. The scope list is front-loaded and the actionable guidance ("orient or diagnose connection issues") closes it, so an agent gets both content and trigger immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of conveying what comes back, and its enumeration of six check areas largely does that. It is complete enough for a zero-param read tool, missing only how results are shaped or whether a healthy/unhealthy verdict is returned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The enumerated check list effectively describes the scope of the call instead.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ("Check") and enumerates exactly what is checked: project selection, station discovery, PLC/HMI reachability, engine paths, running processes, HMI runtime health. This makes it distinguishable from narrower siblings like check_job_status or plc_diagnostics, though it never names them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Call to orient or diagnose connection issues" gives a clear triggering context. It stops short of stating when NOT to use it or pointing to deeper alternatives (e.g., plc_diagnostics for PLC detail), so it is clear context without exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lse_projectA
Destructive

Run LASAL SCREEN (LSE) engine operations on a .lpr screen project via the LASALScreen COM automation: info (screens/windows/servers/text lists/languages/settings inventory), create (fresh project), compile (Runtime output folder), download to a panel (Download & Run), and apply_changes with granular operations: merge/fuse projects, export_xml/import_xml text round-trips, import_variables (CLASS 2 references), textlist_* translations, server_get_property/server_set_property (limits, unit, menu, state schema, hostname, …), bulk update_buttons/update_softkeys theming, settings_set (resolution/compiler/online), image_insert. The .lpr itself is binary — never edit it directly; use this tool or the editor. Supports async: true — the call then returns immediately with a jobId and you MUST poll check_job_status until it reports status completed/failed (the result is delivered there).

NameRequiredDescriptionDefault
runNoWith action 'download': start the screen runtime on the target after the transfer (Download & Run).
saveNoWith action 'apply_changes': save the project after the operations (set false for read-only exports).
asyncNoRun in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.
actionYes'info' inventories the project (screens, windows, servers, text lists, languages, settings) read-only. 'compile' rebuilds the Runtime output folder. 'download' pushes the project to the panel (F6-equivalent) via the project's online settings. 'apply_changes' loads the project, runs the operations list, saves, and closes. 'create' generates a NEW empty .lpr project at lpr_path (screens can then be laid out in the editor; text lists/data can be prepared via operations).
lpr_pathNoFull path to the .lpr project file. Omit to auto-detect from the selected project.
timeout_sNoTimeout override in seconds.
connectionNoDownload target, e.g. 'TCPIP:192.168.1.50'. Omit to use the station that owns the .lpr in the solution (its .lss target).
operationsNoOrdered operations for action 'apply_changes'. Each has a 'type' field: compile | merge | fuse | export_xml | import_xml | export | import_variables | import_scl | textlist_import_file | textlist_import | textlist_create | textlist_add_text | textlist_set_text | textlist_get_texts | add_language | clear_languages | set_actual_language | update_buttons | update_softkeys | settings_set | image_insert | server_get_property | server_set_property

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare openWorldHint=true and destructiveHint=true, so the description does not need to establish that this is a mutating tool. It adds useful behavioral context by warning that the .lpr file is binary, stating that apply_changes loads/saves/closes the project, and explaining the async=true jobId polling flow via check_job_status. It does not detail permissions, reversibility, or operation-specific side effects, but it covers the most important hidden behaviors.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then covers the main actions, binary handling, and async polling. It is dense and packs many operation names into the first sentence, but the length is justified by the tool's breadth and the information is relevant. It could be more readable with slight restructuring, but it avoids redundant explanation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex tool with many operations, the description provides the essential context: what the tool operates on, the main action modes, the binary .lpr constraint, and the critical async polling requirement. Since the input schema is fully described and annotations cover the mutation/open-world safety profile, the remaining gap is mainly operation-level return behavior. That is a minor completeness gap rather than a blocking omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters and operation variants in detail. The description adds some semantic grouping for the operations array (merge/fuse, XML round-trips, textlist translations, server properties, theming, settings, images), but it does not add meaningfully more than the schema for individual parameters. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: run LASAL SCREEN engine operations on a .lpr screen project via COM automation. It enumerates the main action categories (info, create, compile, download, apply_changes), making the tool's scope unmistakable. It stops short of naming sibling tools or explicitly differentiating itself from manage_lasalscreen or apply_project_changes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when the tool is used by listing its actions and operations, and it warns that the .lpr is binary and should not be edited directly. However, it does not explicitly say when to choose this tool over sibling tools such as manage_lasalscreen, apply_project_changes, or build_project. Usage is therefore inferable but not fully guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manage_class2A
Destructive

Open or close the LASAL CLASS 2 IDE GUI. Close before running batch operations.

NameRequiredDescriptionDefault
actionYes'open' launches LASAL CLASS 2; 'close' kills it.
lcp_pathNoFull path to the .lcp station file to open (open only). Omit to auto-detect from the selected project.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint=true annotation already signals that closing is destructive; the description adds a workflow constraint (close before batch operations) that annotations do not convey. It does not, however, say what closing destroys (unsaved state, running jobs) or what happens if the IDE is already open/closed, which the schema only hints at with "kills it".

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the core action stated first and the operational caveat second. Nothing could be removed without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter, no-output-schema toggle tool with a destructiveHint annotation, the description covers purpose and one important operational rule. It could be slightly stronger by noting the effect of an unexpected close (e.g. terminating an in-progress session), but nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the action enum is self-documenting, so the schema carries the parameter burden. The description adds no syntax, format, or conditional detail about lcp_path or the action values, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (open/close) against a precisely named resource (the LASAL CLASS 2 IDE GUI), which separates it from sibling GUI-management tools like manage_visudesigner and manage_lasalscreen. An agent can identify the tool's job without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Close before running batch operations" gives a concrete sequencing prerequisite for the close action, which is real when-to-use context. However, it names no alternatives and gives no guidance for when to open or when not to touch the IDE, so it stops short of a full when/when-not treatment.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manage_lasalscreenA
Destructive

Open or close the LASAL SCREEN (LSE) editor for .lpr screen projects. Close before running lse_project automation (releases .lpr file locks).

NameRequiredDescriptionDefault
actionYes'open' launches the LASAL SCREEN (LSE) editor; 'close' kills it (releases .lpr file locks).
lpr_pathNoFull path to the .lpr screen project to open (open only). Omit to auto-detect from the selected project.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint annotation already signals that close is destructive, and the description adds meaningful context by saying close releases .lpr file locks and should precede lse_project automation. It does not elaborate further on editor state or failure behavior, but it adds useful operational context beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences, with the core purpose stated first and the important close-before-automation caveat immediately after. There is no wasted wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-action editor-control tool with full schema coverage, a destructiveHint annotation, and no output schema, the description supplies the essential purpose, one key workflow constraint, and the file-lock consequence. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the action enum and lpr_path semantics are already fully documented in the schema. The description reinforces the .lpr context but does not add parameter-level meaning beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb pair, open/close, and a specific resource, the LASAL SCREEN (LSE) editor for .lpr screen projects. It also differentiates the close action from lse_project automation by explaining the file-lock relationship.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit and useful condition for using close: do it before running lse_project automation because it releases .lpr file locks. The open case is implied by the tool purpose but not given the same explicit when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manage_visudesignerA
Destructive

Open or close the VISUDesigner GUI. Close before running automated visu operations.

NameRequiredDescriptionDefault
actionYes'open' launches VISUDesigner; 'close' kills it.
lvp_pathNoFull path to the .lvp station file to open (open only). Omit to auto-detect from the selected project.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint=true annotation already signals that this tool can destroy state, and the description adds a genuine behavioral note about sequencing (close before automated visu operations). It does not explain what is lost on close (unsaved state?) or whether the kill is graceful, so it only partially compensates for the gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the primary action stated first and the operational warning second. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter GUI toggle with no output schema and full schema coverage, the description is nearly sufficient: it covers the action, the target, and the key precondition. It stops short of describing failure modes or what 'kill' means for in-flight work, which is the only meaningful gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are fully documented in the schema, including the enum meanings and the auto-detect behavior of lvp_path. The description adds nothing beyond that, which is the expected baseline when the schema does the work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (open/close) and the resource (VISUDesigner GUI), so an agent knows exactly what the tool manipulates. It does not explicitly differentiate itself from siblings like visu_project or hmi_runtime, but the purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The sentence 'Close before running automated visu operations' gives a real ordering precondition for the close action, which is useful guidance. However, there is no guidance on when to open versus when the GUI is unnecessary, and no alternatives are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

plc_diagnosticsC

Run PLC diagnostics: trace recording, file upload/download/delete on PLC, or static code analysis.

NameRequiredDescriptionDefault
actionYesPLC diagnostics/maintenance action: trace (DataAnalyzer run), file_upload/file_download/file_delete (files on the control), code_analysis (static analysis on the project or one source file), download_os (install a LasalOS .lbi — control reboots), clear_ram_image, save_project_on_plc (backup the running project on the control), download_connection_file (.lcf).
os_pathNoLasalOS update file (.lbi) to install (download_os action only).
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.
plc_pathNoFile path on the PLC (for file upload/download/delete).
timeout_sNoTimeout override in seconds. Defaults: 120s, or 600s for download_os.
connectionNoPLC connection string. Omit to use connection from project's .lss file.
local_pathNoLocal file path on the host (for file upload/download).
config_pathNoAbsolute path to the DataAnalyzer config file (trace action only).
duration_msNoDuration in milliseconds to run the trace (trace action only). Default 5000.
output_pathNoDestination path for the trace output or code analysis result.
source_fileNoAnalyze a single source file instead of the whole project (code_analysis action only).
connection_fileNoOptional .lcf connection file path (download_connection_file action only; omit to use the project's active connection file).

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Only openWorldHint is annotated, so the description carries the behavioral burden and largely fails it: it does not disclose that file_delete is destructive, that clear_ram_image wipes the controller's RAM, that save_project_on_plc overwrites a backup, or that download_os reboots the control. Those risk notes exist only partially in the schema's action text, and no permission, auth, or timeout behavior is described in the description itself.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; the core purpose and action families come first. It is tight, though it is arguably too terse for nine heterogeneous actions with very different risk profiles.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter, 9-action tool with no output schema and only openWorldHint annotated, the description omits critical context: which actions mutate or reboot the PLC, default timeouts, and what each action returns. The action enum in the schema compensates somewhat, but the description alone is not sufficient for safe invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 12 parameters including per-action applicability (e.g., os_path for download_os only, duration_ms for trace only). The description adds only the coarse grouping of actions and no additional parameter semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Run) and resource (PLC diagnostics) and enumerates representative sub-actions (trace, file ops, code analysis), so the agent can distinguish it from control_plc and plc_values. However, the enumeration is incomplete — download_os, clear_ram_image, save_project_on_plc, and download_connection_file appear only in the schema's action enum, not the description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance and no alternatives are named, despite siblings like control_plc, plc_values, and lse_project that plausibly overlap. The reader must infer which of the nine actions to pick and when this tool is preferred over the control/runtime tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

plc_valuesB

Read or write live channel values on a running PLC. Channels use 'ObjectName.ChannelName' format. Auto-coerces types based on ST declarations.

NameRequiredDescriptionDefault
actionYes'read' fetches live channel values; 'write' pushes new values.
valuesNoChannel/value pairs to write (write only).
channelsNoChannel paths to read, each in 'ObjectName.ChannelName' format (read only).
lcp_pathNoAbsolute path to the .lcp file. Omit to use the selected project.
connectionNoConnection string or address-book name. Omit to use the project's saved connection.

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only carry openWorldHint=true, so the description bears most of the behavioral burden. It usefully discloses automatic type coercion based on ST declarations, but says nothing about write failures, permissions, or reversibility of the write path, which is a notable gap for a mutation-capable tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short, front-loaded sentences with no filler; the capability and the channel-format constraint come first. Tight and readable, though it could be even more economical.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a five-parameter dual read/write tool with full schema coverage and no output schema, the description covers the essentials of invocation. It is missing behavioral detail around write semantics and error handling, so it is adequate but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters are already documented, including the 'ObjectName.ChannelName' format and per-action applicability. The description only restates the channel format and adds the type-coercion note, so it earns the baseline rather than adding new parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb pair (read/write) and resource (live channel values on a running PLC), so the agent immediately knows the capability. It does not, however, differentiate itself from siblings like control_plc or plc_diagnostics, leaving overlap ambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'on a running PLC' implies a precondition and the read/write framing hints at when each action applies, but there is no explicit when-to-use/when-not or routing to alternatives such as control_plc. Usage is only inferable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_class_sourceA

Read or write a CLASS 2 class source (.st) by class name, with optional .h access. Writes are latin1-validated and require the CLASS 2 IDE to be closed.

NameRequiredDescriptionDefault
actionYes'read' returns the source; 'write' overwrites it.
sourceNoFull content to write to the .st file — must be latin1-compatible (write only).
lcp_pathNoAbsolute path to the .lcp file. Omit to use the selected project.
class_nameYesName of the CLASS 2 class (e.g. 'Palletizer').
header_sourceNoContent to write to the .h file. Omit to leave it unchanged (write only).
include_headerNoAlso return the .h file contents (read only). Default false.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false, so the description carries most of the behavioral load and does so usefully: it discloses that writes overwrite the file, are latin1-validated, and require the IDE to be closed. This exceeds what the annotations provide. It stops short of describing failure behavior when validation fails or how the write interacts with the .h file when header_source is omitted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence with the class/resource up front and the write precondition trailing. No filler. Slightly compressed given the dual read/write mode and the .st/.h duality, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a six-parameter tool with no output schema and no nested objects, the description covers the operation, the write preconditions, and the optional header access. The remaining gap is that read-side return behavior is only implied ('read returns the source' lives in the schema), and error/rollback behavior is unspecified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all six parameters, including the read/write enum and the .h handling. The description's only added meaning is the latin1 validation constraint and that .h access is optional; the baseline of 3 applies when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: read or write a CLASS 2 class source (.st) by class name, with optional .h access. It is clear and concrete, though it does not distinguish itself from the sibling manage_class2, so an agent cannot tell which to prefer without checking both. The tool name ('read_class_source') understates the write capability, but the description corrects that.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives one real usage constraint — writes are latin1-validated and require the CLASS 2 IDE to be closed — which is actionable guidance about preconditions. However, it offers no when-to-use-vs-alternatives routing against manage_class2 or run_class2_script, so the selection decision is left partly to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_class2_scriptA
Destructive

Escape hatch: run arbitrary Python 2.7 batch statements through Lasal2.exe (module batch, project prj in scope). Use for batch API calls not covered by apply_project_changes; the project is NOT saved automatically.

NameRequiredDescriptionDefault
argsNoOptional arguments exposed to the script as sys.argv[1:]. Default [].
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.
script_bodyYesPython 2.7 statements executed inside the CLASS 2 batch context. `batch` (sigmatek.lasal.batch) and the loaded project `prj` are in scope; the project is closed afterwards (call batch.Save(prj) yourself if the change must persist). Example: batch.Compile(prj, batch.CompileOptions.BuildChanges)

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply destructiveHint=true, so the description carries real weight here and delivers: it discloses the escape-hatch nature (arbitrary code), the project-closed-afterwards lifecycle, and that persistence requires an explicit batch.Save call. It stops short of describing error behavior or what the call returns, which is a minor remaining gap rather than a contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero padding, and the most decision-relevant fact ('Escape hatch') is front-loaded before the routing and persistence details. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an arbitrary-code execution tool with no output schema, the description covers purpose, scope, alternative, and persistence semantics well. It could say a bit more about what the caller gets back (stdout, exceptions) or failure modes, but nothing essential for invoking it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so `script_body`, `args`, and `lcp_path` are already documented in the schema, and the description's mention of `batch`/`prj` scope largely echoes that. Baseline 3 is appropriate when the schema does the heavy lifting and the prose adds only reinforcement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: run arbitrary Python 2.7 batch statements through Lasal2.exe, naming the module (`batch`) and in-scope project (`prj`). It explicitly distinguishes itself from the sibling apply_project_changes, so an agent can route correctly without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use condition ('batch API calls not covered by apply_project_changes') and names the alternative, which is exactly the routing information an agent needs. It also flags the persistence caveat ('the project is NOT saved automatically'), which is a usage-relevant warning rather than pure prose.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

select_projectA
Idempotent

Set the active LASAL project by directory path. Call first — all other tools default to this project.

NameRequiredDescriptionDefault
pathYesFull path to the LASAL solution folder (must contain a .lsm file).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations declare idempotentHint=true and openWorldHint=false, but not the statefulness of the operation. The description supplies that missing behavior: setting a session/project default that all other tools then inherit, which is decision-relevant context. It stops short of detailing failure behavior on a malformed path, though the schema's '.lsm file' requirement covers part of that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with zero filler; the primary action is front-loaded and the ordering constraint follows immediately. Nothing is redundant with the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter priming tool with no output schema, the description covers the essentials: what it selects, how, and its ordering relationship to the rest of the toolset. Minor omissions remain (invalid-path handling, whether the selection persists across sessions), but nothing critical for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single 'path' parameter is fully documented in the schema, including the '.lsm file' containment requirement. The description only restates 'by directory path', adding no format, resolution, or error semantics beyond what the schema already provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Set the active LASAL project') plus the mechanism ('by directory path'), which is enough for an agent to distinguish it from operational siblings like inspect_project or build_project. The 'Call first' clause reinforces that this is the selecting/priming tool rather than one that acts on an already-selected project.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete ordering rule — 'Call first — all other tools default to this project' — which tells the agent exactly when this tool is required and what its side effect enables. It lacks an explicit when-not or a named alternative (e.g., what to do for multiple simultaneous projects), keeping it just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_target_ipA
Idempotent

Update the target IP/port/SSL of a station in its .lss (surgical edit, other settings preserved). Use when a station moved networks; connection strings can also be passed per call.

NameRequiredDescriptionDefault
ipNoNew IP address (e.g. '192.168.1.100').
portNoNew port (default '1954'). Only change if non-standard.
ssltlsNoEnable SSL/TLS for the connection. Omit to leave unchanged.
stationNoStation name to update (e.g. 'PLC', 'HMI'). Omit if the project has only one station.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply idempotentHint=true, so the description carries most of the burden and does add real value: it discloses the persistence target (.lss) and the preservation semantics ('surgical edit, other settings preserved'). It does not say whether the change takes effect immediately, requires a redeploy/restart, or needs any permission, which are meaningful gaps for a config mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences, front-loaded with the action and its scope, then the trigger condition and alternative. Every clause earns its place; nothing is restated from the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-optional-parameter mutation with no output schema, the description covers what changes, what is preserved, and when to use it. What is missing is the activation story — whether the edited .lss requires a deploy or PLC reconnect for the new target to take effect — which matters given siblings like deploy_solution and control_plc.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so each parameter (ip, port, ssltls, station) is already documented including the port default and the 'omit to leave unchanged' behavior for ssltls. The description adds only the alternative of per-call connection strings, which is contextual rather than parameter-level, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource: 'Update the target IP/port/SSL of a station in its .lss', with the scope narrowed by '(surgical edit, other settings preserved)'. It is clear what changes and what does not. It never names a sibling tool, so differentiation from tools like apply_project_changes or deploy_solution is only implied.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use when a station moved networks' gives an explicit trigger condition, and 'connection strings can also be passed per call' points at an alternative approach. There is no explicit when-not guidance or named alternative tool, so it stops short of full routing clarity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_guidsB
Destructive

Scan a LASAL station project for duplicate GUID collisions and uninitialized TO_UDINT(0) placeholders in classes. Auto-resolves duplicate GUID collisions (generating fresh GUIDs and updating MaeExp.txt/xml) and populates exact LASAL CRC32 @CT_ hashes. Also cleans dangling network metadata.

NameRequiredDescriptionDefault
auto_fixNoAutomatically resolve duplicate GUID collisions and update @CT_ hashes. Default true.
lcp_pathNoAbsolute path to the .lcp file. Omit to use the currently selected project.

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only give destructiveHint=true, so the description carries real weight and delivers: it discloses that the tool generates fresh GUIDs, rewrites MaeExp.txt/xml files, populates CRC32 @CT_ hashes, and cleans dangling network metadata. This tells the agent what on-disk artifacts get mutated. It stops short of addressing reversibility, backups, or permission needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The scan purpose is front-loaded, followed by the auto-fix actions in a well-ordered sequence. Three sentences, each contributing information with no filler. Slightly dense but not wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive-by-default mutation tool with no output schema, the description explains what changes but omits whether findings are reported back, whether fixes are reversible, and what the agent should verify before running with auto_fix=true. Adequate but with a notable gap around the default destructive path.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both auto_fix and lcp_path, including the 'omit to use currently selected project' fallback. The description reinforces the auto-fix behavior but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs and resources: scanning a LASAL station project for duplicate GUID collisions and TO_UDINT(0) placeholders, plus auto-resolution. This is far more specific than a tautology and clearly separates it from generic siblings like inspect_project. It does not explicitly contrast with any named sibling, keeping it at 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit statement of when to use this tool versus alternatives, nor any prerequisites (e.g., when to call before/after build_project or deploy). Usage is only implied by the purpose text. There is no when-not guidance despite a destructive default behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

visu_projectB
Destructive

Run VISUDesigner engine operations: update stations, publish, manage text lists/schemes/media/code modules, set datapoint properties, or download to HMI. These need the VISUDesigner engine — for direct dashboard JSON editing, edit the files in the project directly.

NameRequiredDescriptionDefault
flagsNoDownload mode: 0=normal (default), 1=changes only, 2=publish+download changes (download only).
actionYes'apply_changes' loads the project, runs operations, saves, and closes. 'download' pushes the project to an HMI without saving content changes.
lvp_pathNoFull path to the .lvp project file. Omit to auto-detect from the selected project.
connectionNoHMI connection string, e.g. 'TCPIP:192.168.1.100' (download only).
operationsNoOrdered list of VISUDesigner operations (apply_changes only). Each has a 'type' field. Available types: update_all_stations | update_station | publish | add_text_lists | remove_text_lists | add_texts | remove_texts | change_texts | change_component_texts | set_text_list_revisions | set_component_text_list_revisions | csv_export_text_lists | csv_import_text_lists | csv_export_component_text_lists | csv_import_component_text_lists | set_datapoint_properties | set_datatype_properties | add_schemes | remove_schemes | add_scheme_entries | remove_scheme_entries | move_scheme_entries | set_scheme_inputs | set_scheme_properties | set_scheme_entry_properties | add_media_items | remove_media_items | add_code_modules | remove_code_modules | update_property_values | update_runtime | delete_station | station_details | import_project | add_languages | remove_languages | set_language_properties | add_alarms | remove_alarms | set_alarm_properties | set_alarm_servers_or_groups | set_alarm_revisions | download
add_runtimeNoForce runtime download even if version already matches (download only).

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations supply only destructiveHint=true, so the description carries most of the burden. It adds real context by stating the engine dependency (a runtime prerequisite), but does not disclose what gets destroyed, that apply_changes saves and closes the project, that operations are executed in order, or any error/rollback behavior. Useful but incomplete for a destructive multi-op tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the operation catalog and followed by the engine requirement and the fallback alternative. The enumeration is long but earns its place by signalling breadth. Minor waste only.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 6 params and 40+ operation types, no output schema, and a destructive annotation, the description is a thin overview. It omits the critical apply_changes/download mode split and any destructive-operation warning, though the exhaustive schema compensates substantially for those gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and every parameter and operation variant is documented inline, so the baseline is 3. The description's enumeration of operation families loosely maps to the 'operations' param but adds no syntax, ordering, or constraint detail beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Run VISUDesigner engine operations') and enumerates the covered categories: stations, publish, text lists, schemes, media, code modules, datapoint properties, and HMI download. It is far from a tautology. However, it never distinguishes itself from the closely-named sibling manage_visudesigner, so an agent cannot fully route between them from the description alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives one genuine exclusion — 'for direct dashboard JSON editing, edit the files in the project directly' — which tells the agent when NOT to use this tool. But it offers no guidance on apply_changes vs download, no prerequisites beyond 'needs the VISUDesigner engine', and no comparison to the manage_visudesigner sibling, leaving the primary routing decision to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 17 tool updatesv0.3.2
    • Changedapply_project_changes2 fields changed
      • changedInput schema / properties / operations / description
        Previous value: -"Ordered list of CLASS 2 batch engine operations. Available types: create_network, delete_network, rename_network, duplicate_network, add_object, remove_object, rename_object, change_object_class, create_connection, delete_connection, set_init_value, delete_class, compile, download, set_task_order, set_task_time, set_task_cpu_core, set_multi_cpu_core, set_visualized_flag, set_comment_network, set_comment_object, set_network_options, reset_network_options, move_network_to_folder, set_parameter_value"New value: +"Ordered list of operations. Batch engine types: create_network, delete_network, rename_network, duplicate_network, add_object, remove_object, rename_object, change_object_class, create_connection, delete_connection, set_init_value, delete_class, compile, download, set_task_order, set_task_time, set_task_cpu_core, set_multi_cpu_core, set_visualized_flag, set_comment_network, set_comment_object, set_network_options, reset_network_options, move_network_to_folder, set_parameter_value, set_compiler_version, copy_class, copy_network, replace_object, add_library, import_lcz, update_referenced, calculate_resources, mm_change_connection, mm_update_server_list, set_project_revision. File-level types (applied before the batch engine, no CLASS 2 API): create_class, add_project_file, clean_project."
      • changedInput schema / properties / operations / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "name": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "create_network",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "deleteConnections": {
        -        "default": true,
        -        "type": "boolean"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "delete_network",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "newName": {
        -        "type": "string"
        -      },
        -      "oldName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "rename_network",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "oldName",
        -      "newName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "name": {
        -        "type": "string"
        -      },
        -      "newName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "duplicate_network",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name",
        -      "newName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "className": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "add_object",
        -        "type": "string"
        -      },
        -      "visualized": {
        -        "default": true,
        -        "type": "boolean"
        -      },
        -      "x": {
        -        "default": 300,
        -        "type": "number"
        -      },
        -      "y": {
        -        "default": 300,
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "className",
        -      "objectName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "deleteConnections": {
        -        "default": true,
        -        "type": "boolean"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "remove_object",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "newName": {
        -        "type": "string"
        -      },
        -      "oldName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "rename_object",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "oldName",
        -      "newName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "className": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "change_object_class",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "className"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "fromClient": {
        -        "type": "string"
        -      },
        -      "fromObject": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "toObject": {
        -        "type": "string"
        -      },
        -      "toServer": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "create_connection",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "fromObject",
        -      "fromClient",
        -      "toObject",
        -      "toServer"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "clientName": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "delete_connection",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "objectName",
        -      "clientName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "channelName": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_init_value",
        -        "type": "string"
        -      },
        -      "value": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "objectName",
        -      "channelName",
        -      "value"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "className": {
        -        "type": "string"
        -      },
        -      "force": {
        -        "default": false,
        -        "type": "boolean"
        -      },
        -      "type": {
        -        "const": "delete_class",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "className"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "options": {
        -        "default": "RebuildAll",
        -        "enum": [
        -          "RebuildAll",
        -          "BuildChanges",
        -          "UserClassesOnly",
        -          "NoDebugInfo"
        -        ],
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "compile",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "add_loader_anyway": {
        -        "default": false,
        -        "type": "boolean"
        -      },
        -      "connection": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "download",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "position": {
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "task": {
        -        "enum": [
        -          "realtime",
        -          "cyclicwork",
        -          "background"
        -        ],
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_task_order",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "task",
        -      "position"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "task": {
        -        "enum": [
        -          "realtime",
        -          "cyclicwork",
        -          "background"
        -        ],
        -        "type": "string"
        -      },
        -      "time": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_task_time",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "task",
        -      "time"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "core": {
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "task": {
        -        "enum": [
        -          "realtime",
        -          "cyclicwork"
        -        ],
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_task_cpu_core",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "task",
        -      "core"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "multiCore": {
        -        "type": "boolean"
        -      },
        -      "type": {
        -        "const": "set_multi_cpu_core",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "multiCore"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "isVisualized": {
        -        "type": "boolean"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_visualized_flag",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "isVisualized"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "comment": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_comment_network",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "comment"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "comment": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_comment_object",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "comment"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "optionNames": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "resetAllOthers": {
        -        "default": false,
        -        "type": "boolean"
        -      },
        -      "type": {
        -        "const": "set_network_options",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "optionNames"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "optionNames": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "reset_network_options",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "optionNames"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "folder": {
        -        "type": "string"
        -      },
        -      "network": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "move_network_to_folder",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "folder"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "network": {
        -        "type": "string"
        -      },
        -      "objectName": {
        -        "type": "string"
        -      },
        -      "parameterName": {
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_parameter_value",
        -        "type": "string"
        -      },
        -      "value": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "network",
        -      "objectName",
        -      "parameterName",
        -      "value"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "create_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "deleteConnections": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "delete_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "newName": {
        +        "type": "string"
        +      },
        +      "oldName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "rename_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "oldName",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "newName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "duplicate_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "add_object",
        +        "type": "string"
        +      },
        +      "visualized": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "x": {
        +        "default": 300,
        +        "type": "number"
        +      },
        +      "y": {
        +        "default": 300,
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "className",
        +      "objectName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "deleteConnections": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "remove_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "newName": {
        +        "type": "string"
        +      },
        +      "oldName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "rename_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "oldName",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "change_object_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "className"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "fromClient": {
        +        "type": "string"
        +      },
        +      "fromObject": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "toObject": {
        +        "type": "string"
        +      },
        +      "toServer": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "create_connection",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "fromObject",
        +      "fromClient",
        +      "toObject",
        +      "toServer"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "clientName": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "delete_connection",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "objectName",
        +      "clientName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "channelName": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_init_value",
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "objectName",
        +      "channelName",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "force": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "delete_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "className"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "options": {
        +        "default": "RebuildAll",
        +        "enum": [
        +          "RebuildAll",
        +          "BuildChanges",
        +          "UserClassesOnly",
        +          "NoDebugInfo"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "compile",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "add_loader_anyway": {
        +        "type": "boolean"
        +      },
        +      "connection": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "download",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "position": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork",
        +          "background"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_order",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "position"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork",
        +          "background"
        +        ],
        +        "type": "string"
        +      },
        +      "time": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_time",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "time"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "core": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_cpu_core",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "core"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "multiCore": {
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "set_multi_cpu_core",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "multiCore"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "isVisualized": {
        +        "type": "boolean"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_visualized_flag",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "isVisualized"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "comment": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_comment_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "comment"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "comment": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_comment_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "comment"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "optionNames": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "resetAllOthers": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "set_network_options",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "optionNames"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "optionNames": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "reset_network_options",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "optionNames"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "folder": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "move_network_to_folder",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "folder"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "parameterName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_parameter_value",
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "parameterName",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "set_compiler_version",
        +        "type": "string"
        +      },
        +      "version": {
        +        "description": "Compiler version string accepted by batch.SetCompilerVersion (e.g. 'C75').",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "version"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "description": "Class name to copy.",
        +        "type": "string"
        +      },
        +      "overwrite": {
        +        "default": true,
        +        "description": "Overwrite an existing class with the same name.",
        +        "type": "boolean"
        +      },
        +      "sourceProject": {
        +        "description": "Path to the SOURCE .lcp that contains the class.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "copy_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "sourceProject",
        +      "className"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "description": "Network name to copy.",
        +        "type": "string"
        +      },
        +      "overwrite": {
        +        "default": true,
        +        "description": "Overwrite an existing network with the same name.",
        +        "type": "boolean"
        +      },
        +      "sourceProject": {
        +        "description": "Path to the SOURCE .lcp that contains the network.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "copy_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "sourceProject",
        +      "network"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "checkObjectName": {
        +        "default": true,
        +        "description": "Verify the object name matches.",
        +        "type": "boolean"
        +      },
        +      "network": {
        +        "description": "Target network in this project.",
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "description": "Object in the target network to replace.",
        +        "type": "string"
        +      },
        +      "sourceNetwork": {
        +        "description": "Network in the source project that contains the replacement object.",
        +        "type": "string"
        +      },
        +      "sourceObject": {
        +        "description": "Replacement object name in the source project.",
        +        "type": "string"
        +      },
        +      "sourceProject": {
        +        "description": "Path to the SOURCE .lcp that contains the replacement object's network.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "replace_object",
        +        "type": "string"
        +      },
        +      "useSourceConnections": {
        +        "default": false,
        +        "description": "Adopt the source object's connections.",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "sourceProject",
        +      "network",
        +      "objectName",
        +      "sourceNetwork",
        +      "sourceObject"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "library": {
        +        "description": "Library to add: path to a library .lcp or a registered library name.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "add_library",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "library"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "file": {
        +        "description": "Path to a .lcz class/network import bundle.",
        +        "type": "string"
        +      },
        +      "keepExistingLinked": {
        +        "default": false,
        +        "description": "Keep existing classes linked instead of replacing.",
        +        "type": "boolean"
        +      },
        +      "overwrite": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "import_lcz",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "file"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "scope": {
        +        "default": "classes",
        +        "description": "Refresh linked library classes or networks.",
        +        "enum": [
        +          "classes",
        +          "networks"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "update_referenced",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "outputPath": {
        +        "description": "Optional path for the resource export file.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "calculate_resources",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "newConnection": {
        +        "description": "New connection configuration name (address book).",
        +        "type": "string"
        +      },
        +      "station": {
        +        "description": "MultiMaster station name.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "mm_change_connection",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "station",
        +      "newConnection"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "file": {
        +        "description": "Optional path of a server list file to use.",
        +        "type": "string"
        +      },
        +      "station": {
        +        "description": "MultiMaster station name.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "mm_update_server_list",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "station"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "revision": {
        +        "description": "Project revision string (e.g. \"1.2\").",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_project_revision",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "revision"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "author": {
        +        "default": "lasal-mcp",
        +        "type": "string"
        +      },
        +      "backgroundTask": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "comment": {
        +        "type": "string"
        +      },
        +      "company": {
        +        "default": "Votech",
        +        "type": "string"
        +      },
        +      "cyclicTask": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "defBackgroundTime": {
        +        "default": "100 ms",
        +        "description": "Background task time, e.g. \"100 ms\".",
        +        "type": "string"
        +      },
        +      "defCyclicTime": {
        +        "default": "1 ms",
        +        "description": "Cyclic task time, e.g. \"1 ms\" (legacy project constants like cCyTb are not available on current compiler versions).",
        +        "type": "string"
        +      },
        +      "files": {
        +        "default": [],
        +        "description": "Class dependency files (.h/.cpp), optionally created.",
        +        "items": {
        +          "properties": {
        +            "content": {
        +              "description": "Optional latin1 content to write to the file.",
        +              "type": "string"
        +            },
        +            "global": {
        +              "description": "Header: set Global=\"true\" in <HeaderFiles>.",
        +              "type": "boolean"
        +            },
        +            "include": {
        +              "description": "Header: emit an #include in the class .st (default true for *.h).",
        +              "type": "boolean"
        +            },
        +            "path": {
        +              "description": "Path relative to the project (e.g. .\\Class\\PbLib\\C_PbLib.cpp) or absolute.",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "path"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "folder": {
        +        "default": "IQ",
        +        "description": "Class browser folder under <ClassFolders>.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Class name ([A-Za-z_][A-Za-z0-9_]*).",
        +        "type": "string"
        +      },
        +      "realtimeTask": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "revision": {
        +        "default": "0.1",
        +        "type": "string"
        +      },
        +      "servers": {
        +        "default": [],
        +        "description": "Extra server channels (ClassSvr is always added).",
        +        "items": {
        +          "properties": {
        +            "initialize": {
        +              "default": false,
        +              "type": "boolean"
        +            },
        +            "name": {
        +              "description": "Server (channel) name.",
        +              "type": "string"
        +            },
        +            "retentive": {
        +              "default": false,
        +              "type": "boolean"
        +            },
        +            "type": {
        +              "default": "SvrCh_DINT",
        +              "description": "ST channel type (SvrCh_*, default SvrCh_DINT).",
        +              "type": "string"
        +            },
        +            "visualized": {
        +              "default": true,
        +              "type": "boolean"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "create_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "global": {
        +        "default": false,
        +        "description": "Header: set Global=\"true\".",
        +        "type": "boolean"
        +      },
        +      "header": {
        +        "description": "Force registration in <HeaderFiles> even when the name does not end in .h.",
        +        "type": "boolean"
        +      },
        +      "path": {
        +        "description": "Existing file to register (relative to the project or absolute).",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "add_project_file",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "caches": {
        +        "default": true,
        +        "description": "Delete ProjectInternal/BrowserInfo.bin and LobInfo.bin.",
        +        "type": "boolean"
        +      },
        +      "deep": {
        +        "default": false,
        +        "description": "Also delete the generated .lcb and Network/ConfigObjects .lob/.lba (forces a full relink). Use to recover after a class was removed by deleting its folder instead of the batch delete_class operation.",
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "clean_project",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedbuild_project3 fields changed
      • removedInput schema / properties / add_loader_anyway / default
        Removed value: -false
      • changedInput schema / properties / add_loader_anyway / description
        Previous value: -"Force loader download even if the target OS already has a compatible loader (download only)."New value: +"Force loader download even if the target OS already has a compatible loader (download only). Default: auto — the loader is sent for local LARS/loopback targets, skipped otherwise. Set false to disable, true to force."
      • addedInput schema / properties / async
        Added value: +{
        +  "default": false,
        +  "description": "Run in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.",
        +  "type": "boolean"
        +}
    • Addedcheck_job_status
    • Addedcreate_class2_bootdisk
    • Changeddeploy_all8 fields changed
      • removedInput schema / properties / add_plc_loader / default
        Removed value: -false
      • changedInput schema / properties / add_plc_loader / description
        Previous value: -"Force loader download to PLC even if the target already has a compatible loader."New value: +"Force loader download to PLC even if the target already has a compatible loader. Default: auto — sent for local LARS/loopback targets, skipped otherwise. Set false to disable, true to force."
      • addedInput schema / properties / async
        Added value: +{
        +  "default": false,
        +  "description": "Run in the background: returns { status: 'pending', jobId } — poll with check_job_status. Default false.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / compile_lse
        Added value: +{
        +  "default": true,
        +  "description": "Compile the LASAL SCREEN project (writes the Runtime output folder). Skipped when there is no .lpr. Default true.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / download_lse
        Added value: +{
        +  "default": false,
        +  "description": "Download the LASAL SCREEN project to its station (requires lse_connection or a station target in the solution). Default false.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / lse_connection
        Added value: +{
        +  "description": "SCREEN download target, e.g. 'TCPIP:192.168.1.50'. Omit to resolve from the station that owns the .lpr.",
        +  "type": "string"
        +}
      • addedInput schema / properties / lse_path
        Added value: +{
        +  "description": "Absolute path to the .lpr (LASAL SCREEN) project. Omit to auto-detect from the selected project.",
        +  "type": "string"
        +}
      • addedInput schema / properties / lse_run
        Added value: +{
        +  "default": true,
        +  "description": "Start the screen runtime on the target after download (Download & Run). Default true.",
        +  "type": "boolean"
        +}
    • Addeddeploy_solution
    • Removedhmi_browser
    • Addedinspect_project
    • Changedlars_runtime7 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"'list' shows all configured LARS workspaces and their state (auto-cleans stale ones). 'setup' creates/updates LARS workspaces for the selected project's stations (or one station/lcp. 'start' launches a LARS instance (auto-creates the workspace first if the station is known but unconfigured), 'stop' terminates it, 'remove' deletes its workspace config. 'gc' runs lazy garbage collection: deletes auto-created workspaces that are not running and no longer referenced by any station .lss or published DataService stations.json. 'set_station_target' points a station's .lss at its LARS instance (127.0.0.1:<port>); 'restore' reverts to the saved real target. 'target_pc' switches an ARM-compiled .lcp to the PC (x86) compile target LARS requires (restore via 'restore')."New value: +"'list' shows all configured LARS workspaces and their state (auto-cleans stale ones, but never the selected project's). 'setup' creates/updates LARS workspaces for the selected project's stations (or one station/lcp), wiring both the CLASS 2 project and the LASAL SCREEN (.lpr) project so LARS renders the screen locally. 'start' launches a LARS instance (auto-creates the workspace first if the station is known but unconfigured); reports the effective online port it probed (LARS builds differ in which port they serve). 'stop' terminates it, 'remove' deletes its workspace config. 'gc' runs lazy garbage collection: deletes auto-created workspaces that are not running and no longer referenced by any station .lss or published DataService stations.json, while always keeping workspaces of the selected project. 'set_station_target' points a station's .lss at the online port its LARS instance actually services (probed; never a port another running instance owns); 'restore' reverts to the saved real target. 'target_pc' switches an ARM-compiled .lcp to the PC (x86) compile target LARS requires (restore via 'restore'). 'simulate' runs the full no-hardware loop in one call: ensure workspace (auto-creates), switch ARM targets to PC, compile, start the local LARS instance (probing its effective online port), then download to it. 'screenshot' captures the LARS window of a running workspace (returns the PNG) — use it to visually verify LASAL SCREEN projects running locally."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "list",
        -  "setup",
        -  "start",
        -  "stop",
        -  "remove",
        -  "set_station_target",
        -  "restore",
        -  "target_pc",
        -  "gc"
        -]New value: +[
        +  "list",
        +  "setup",
        +  "start",
        +  "stop",
        +  "remove",
        +  "set_station_target",
        +  "restore",
        +  "target_pc",
        +  "gc",
        +  "screenshot",
        +  "simulate"
        +]
      • addedInput schema / properties / compile_mode
        Added value: +{
        +  "default": "RebuildAll",
        +  "description": "With action 'simulate': CLASS 2 compile mode. Default RebuildAll (safest).",
        +  "enum": [
        +    "RebuildAll",
        +    "BuildChanges"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / project_dir / description
        Previous value: -"Solution directory to auto-detect stations from (setup/list only. Defaults to the selected project."New value: +"Solution directory to auto-detect stations from and to scope station resolution (setup/list/start/stop/set_station_target/restore/target_pc/simulate. Defaults to the selected project."
      • addedInput schema / properties / skip_compile
        Added value: +{
        +  "default": false,
        +  "description": "With action 'simulate': skip the CLASS 2 compile step (reuse the existing build). Default false.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / skip_download
        Added value: +{
        +  "default": false,
        +  "description": "With action 'simulate': skip the download step (only compile + start). Default false.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / station / description
        Previous value: -"Station name from the solution (e.g. 'PLC', 'HMI', 'Local'). Picks the matching workspace. Mutually exclusive with name."New value: +"Station name from the selected project's solution (e.g. 'PLC', 'HMI', 'Local'). Resolution is scoped to the selected project; a station that only exists in another project's workspace is refused, and multiple matches report an ambiguity error and list the candidates. Pass name= to disambiguate. Mutually exclusive with name."
    • Addedlse_project
    • Addedmanage_lasalscreen
    • Changedplc_diagnostics6 fields changed
      • changedInput schema / properties / action / description
        Previous value: -"PLC diagnostics/maintenance action to perform."New value: +"PLC diagnostics/maintenance action: trace (DataAnalyzer run), file_upload/file_download/file_delete (files on the control), code_analysis (static analysis on the project or one source file), download_os (install a LasalOS .lbi — control reboots), clear_ram_image, save_project_on_plc (backup the running project on the control), download_connection_file (.lcf)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "trace",
        -  "file_upload",
        -  "file_download",
        -  "file_delete",
        -  "code_analysis"
        -]New value: +[
        +  "trace",
        +  "file_upload",
        +  "file_download",
        +  "file_delete",
        +  "code_analysis",
        +  "download_os",
        +  "clear_ram_image",
        +  "save_project_on_plc",
        +  "download_connection_file"
        +]
      • addedInput schema / properties / connection_file
        Added value: +{
        +  "description": "Optional .lcf connection file path (download_connection_file action only; omit to use the project's active connection file).",
        +  "type": "string"
        +}
      • addedInput schema / properties / os_path
        Added value: +{
        +  "description": "LasalOS update file (.lbi) to install (download_os action only).",
        +  "type": "string"
        +}
      • addedInput schema / properties / source_file
        Added value: +{
        +  "description": "Analyze a single source file instead of the whole project (code_analysis action only).",
        +  "type": "string"
        +}
      • addedInput schema / properties / timeout_s
        Added value: +{
        +  "description": "Timeout override in seconds. Defaults: 120s, or 600s for download_os.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Addedread_class_source
    • Addedrun_class2_script
    • Addedset_target_ip
    • Addedvalidate_guids
    • Changedvisu_project2 fields changed
      • changedInput schema / properties / operations / description
        Previous value: -"Ordered list of VISUDesigner operations (apply_changes only). Each has a 'type' field. Available types: update_all_stations | update_station | publish | add_text_lists | remove_text_lists | add_texts | remove_texts | change_texts | change_component_texts | set_text_list_revisions | set_component_text_list_revisions | csv_export_text_lists | csv_import_text_lists | csv_export_component_text_lists | csv_import_component_text_lists | set_datapoint_properties | set_datatype_properties | add_schemes | remove_schemes | add_scheme_entries | remove_scheme_entries | move_scheme_entries | set_scheme_inputs | set_scheme_properties | set_scheme_entry_properties | add_media_items | remove_media_items | add_code_modules | remove_code_modules | update_property_values | download"New value: +"Ordered list of VISUDesigner operations (apply_changes only). Each has a 'type' field. Available types: update_all_stations | update_station | publish | add_text_lists | remove_text_lists | add_texts | remove_texts | change_texts | change_component_texts | set_text_list_revisions | set_component_text_list_revisions | csv_export_text_lists | csv_import_text_lists | csv_export_component_text_lists | csv_import_component_text_lists | set_datapoint_properties | set_datatype_properties | add_schemes | remove_schemes | add_scheme_entries | remove_scheme_entries | move_scheme_entries | set_scheme_inputs | set_scheme_properties | set_scheme_entry_properties | add_media_items | remove_media_items | add_code_modules | remove_code_modules | update_property_values | update_runtime | delete_station | station_details | import_project | add_languages | remove_languages | set_language_properties | add_alarms | remove_alarms | set_alarm_properties | set_alarm_servers_or_groups | set_alarm_revisions | download"
      • changedInput schema / properties / operations / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "type": {
        -        "const": "update_all_stations",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "station_nr": {
        -        "description": "Station number to update (as defined in the VISUDesigner project)",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "update_station",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "station_nr"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "debug": {
        -        "default": false,
        -        "description": "Publish with additional debug information. Requires TypeScript support to be enabled in the project.",
        -        "type": "boolean"
        -      },
        -      "type": {
        -        "const": "publish",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Text lists to add (optionally with texts and revisions)",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "add_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "names": {
        -        "description": "Names of text lists to remove",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "names"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Text lists with texts to add",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "add_texts",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Text lists with text IDs to remove",
        -        "items": {
        -          "properties": {
        -            "ids": {
        -              "description": "IDs of texts to remove",
        -              "items": {
        -                "type": "string"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "name",
        -            "ids"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_texts",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Text lists with updated text values",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "change_texts",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Component text lists with updated text values",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "change_component_texts",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Text lists with their revision strings to set (use the 'revision' field)",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_text_list_revisions",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "text_lists": {
        -        "description": "Component text lists with their revision strings to set (use the 'revision' field)",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "description": "Text list name",
        -              "type": "string"
        -            },
        -            "revision": {
        -              "description": "Revision string, e.g. '1.0'",
        -              "type": "string"
        -            },
        -            "texts": {
        -              "description": "Text entries with translations per language",
        -              "items": {
        -                "additionalProperties": {
        -                  "type": "string"
        -                },
        -                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        -                "propertyNames": {
        -                  "type": "string"
        -                },
        -                "type": "object"
        -              },
        -              "type": "array"
        -            }
        -          },
        -          "required": [
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_component_text_list_revisions",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "text_lists"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "csv_path": {
        -        "description": "Destination CSV file path",
        -        "type": "string"
        -      },
        -      "languages": {
        -        "description": "Subset of language codes to export (omit for all)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "text_lists": {
        -        "description": "Subset of text list names to export (omit for all)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "csv_export_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "csv_path"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "file_paths": {
        -        "description": "CSV file paths to import from",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "languages": {
        -        "description": "Subset of language codes to import (omit for all)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "text_lists": {
        -        "description": "Subset of text list names to import (omit for all)",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "csv_import_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "file_paths"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "csv_path": {
        -        "description": "Destination CSV file path",
        -        "type": "string"
        -      },
        -      "languages": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "text_lists": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "csv_export_component_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "csv_path"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "file_paths": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "languages": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "text_lists": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "csv_import_component_text_lists",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "file_paths"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "properties": {
        -        "description": "List of property sets. Use property constants: AliasName, RefreshTime (High/Medium/Low/Standard), WriteProtected, AccessNumber, LimitLow, LimitHigh, Unit, Keyboard, EnumValue, InitValue, etc.",
        -        "items": {
        -          "properties": {
        -            "element": {
        -              "description": "Datapoint / datatype / scheme name",
        -              "type": "string"
        -            },
        -            "property": {
        -              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        -              "type": "string"
        -            },
        -            "value": {
        -              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        -              "type": [
        -                "string",
        -                "number",
        -                "boolean",
        -                "null"
        -              ]
        -            }
        -          },
        -          "required": [
        -            "element",
        -            "property",
        -            "value"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_datapoint_properties",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "properties"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "properties": {
        -        "items": {
        -          "properties": {
        -            "element": {
        -              "description": "Datapoint / datatype / scheme name",
        -              "type": "string"
        -            },
        -            "property": {
        -              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        -              "type": "string"
        -            },
        -            "value": {
        -              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        -              "type": [
        -                "string",
        -                "number",
        -                "boolean",
        -                "null"
        -              ]
        -            }
        -          },
        -          "required": [
        -            "element",
        -            "property",
        -            "value"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_datatype_properties",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "properties"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes to add. Entries and input can be specified to set them simultaneously.",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "add_schemes",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes to remove",
        -        "items": {
        -          "properties": {
        -            "name": {
        -              "type": "string"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_schemes",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes with entries to add. Position determines insertion point; entries beyond max are appended.",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "add_scheme_entries",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes with positions to remove. Use 'positions' or 'entries[].position'.",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_scheme_entries",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes with move operations. Use 'moves': [{from: N, to: M}, ...]",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "move_scheme_entries",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes with the 'input' field set to the datapoint name to use as input",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_scheme_inputs",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "properties": {
        -        "description": "PropertySets where 'element' is the scheme name. Available properties: Revision, LockOverloadCompareValue, LockOverloadSetValue",
        -        "items": {
        -          "properties": {
        -            "element": {
        -              "description": "Datapoint / datatype / scheme name",
        -              "type": "string"
        -            },
        -            "property": {
        -              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        -              "type": "string"
        -            },
        -            "value": {
        -              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        -              "type": [
        -                "string",
        -                "number",
        -                "boolean",
        -                "null"
        -              ]
        -            }
        -          },
        -          "required": [
        -            "element",
        -            "property",
        -            "value"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "scheme_type": {
        -        "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "set_scheme_properties",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "scheme_type",
        -      "properties"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "schemes": {
        -        "description": "Schemes with entries where each entry specifies position + property + value to set. Entry properties: Operator (<,<=,=,>=,>,<>), CompareValue, SetValue. For StateScheme SetValue: None, Active, Inactive, Invisible.",
        -        "items": {
        -          "properties": {
        -            "entries": {
        -              "description": "Scheme entries",
        -              "items": {
        -                "properties": {
        -                  "new_position": {
        -                    "description": "Target position for move operations",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "position": {
        -                    "description": "0-based position in the scheme",
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "property": {
        -                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        -                    "type": "string"
        -                  },
        -                  "value": {
        -                    "description": "Value to set for the property",
        -                    "type": [
        -                      "string",
        -                      "number",
        -                      "boolean",
        -                      "null"
        -                    ]
        -                  }
        -                },
        -                "required": [
        -                  "position"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "input": {
        -              "description": "Input datapoint name for the scheme",
        -              "type": "string"
        -            },
        -            "moves": {
        -              "description": "Move operations (for move_scheme_entries)",
        -              "items": {
        -                "properties": {
        -                  "from": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  },
        -                  "to": {
        -                    "maximum": 9007199254740991,
        -                    "minimum": -9007199254740991,
        -                    "type": "integer"
        -                  }
        -                },
        -                "required": [
        -                  "from",
        -                  "to"
        -                ],
        -                "type": "object"
        -              },
        -              "type": "array"
        -            },
        -            "name": {
        -              "description": "Scheme name",
        -              "type": "string"
        -            },
        -            "positions": {
        -              "description": "Entry positions (for remove_scheme_entries)",
        -              "items": {
        -                "maximum": 9007199254740991,
        -                "minimum": -9007199254740991,
        -                "type": "integer"
        -              },
        -              "type": "array"
        -            },
        -            "scheme_type": {
        -              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "scheme_type",
        -            "name"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "set_scheme_entry_properties",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "schemes"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "items": {
        -        "description": "Media items to add. Each needs media_type and path (full file path).",
        -        "items": {
        -          "properties": {
        -            "media_type": {
        -              "description": "Media type: 'Image', 'Video', 'Audio', 'Docs', 'Fonts', 'KeyboardLayouts', 'Other'",
        -              "type": "string"
        -            },
        -            "name": {
        -              "description": "File name including extension (for remove operations)",
        -              "type": "string"
        -            },
        -            "path": {
        -              "description": "Full file path (for add operations)",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "media_type"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "overwrite": {
        -        "default": false,
        -        "description": "Overwrite existing items with the same name",
        -        "type": "boolean"
        -      },
        -      "type": {
        -        "const": "add_media_items",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "items"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "items": {
        -        "description": "Media items to remove. Each needs media_type and name (filename + extension).",
        -        "items": {
        -          "properties": {
        -            "media_type": {
        -              "description": "Media type: 'Image', 'Video', 'Audio', 'Docs', 'Fonts', 'KeyboardLayouts', 'Other'",
        -              "type": "string"
        -            },
        -            "name": {
        -              "description": "File name including extension (for remove operations)",
        -              "type": "string"
        -            },
        -            "path": {
        -              "description": "Full file path (for add operations)",
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "media_type"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_media_items",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "items"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "paths": {
        -        "description": "Full paths to code module files (.js or .ts) to add",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "add_code_modules",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "paths"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "names": {
        -        "description": "File names (with extension) of code modules to remove",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "type": {
        -        "const": "remove_code_modules",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "names"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "type": {
        -        "const": "update_property_values",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "add_runtime": {
        -        "default": false,
        -        "description": "Force runtime download even if version matches",
        -        "type": "boolean"
        -      },
        -      "connection": {
        -        "description": "Connection string, e.g. 'TCPIP:192.168.1.100' or 'TCPIP:myhmi.local'. Use the 'TCPIP:' prefix for IP/DNS targets.",
        -        "type": "string"
        -      },
        -      "flags": {
        -        "default": 0,
        -        "description": "Download mode: 0=normal (default), 1=changes only, 2=publish+download changes",
        -        "maximum": 9007199254740991,
        -        "minimum": -9007199254740991,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "download",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "connection"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "update_all_stations",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "station_nr": {
        +        "description": "Station number to update (as defined in the VISUDesigner project)",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "update_station",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "station_nr"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "debug": {
        +        "default": false,
        +        "description": "Publish with additional debug information. Requires TypeScript support to be enabled in the project.",
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "publish",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Text lists to add (optionally with texts and revisions)",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "names": {
        +        "description": "Names of text lists to remove",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "names"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Text lists with texts to add",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_texts",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Text lists with text IDs to remove",
        +        "items": {
        +          "properties": {
        +            "ids": {
        +              "description": "IDs of texts to remove",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name",
        +            "ids"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_texts",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Text lists with updated text values",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "change_texts",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Component text lists with updated text values",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "change_component_texts",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Text lists with their revision strings to set (use the 'revision' field)",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_text_list_revisions",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "text_lists": {
        +        "description": "Component text lists with their revision strings to set (use the 'revision' field)",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Text list name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Revision string, e.g. '1.0'",
        +              "type": "string"
        +            },
        +            "texts": {
        +              "description": "Text entries with translations per language",
        +              "items": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "description": "Text entry: { \"id\": \"KEY\", \"De\": \"German text\", \"En\": \"English text\", ... }",
        +                "propertyNames": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "type": "array"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_component_text_list_revisions",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "text_lists"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "csv_path": {
        +        "description": "Destination CSV file path",
        +        "type": "string"
        +      },
        +      "languages": {
        +        "description": "Subset of language codes to export (omit for all)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "text_lists": {
        +        "description": "Subset of text list names to export (omit for all)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "csv_export_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "csv_path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "file_paths": {
        +        "description": "CSV file paths to import from",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "languages": {
        +        "description": "Subset of language codes to import (omit for all)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "text_lists": {
        +        "description": "Subset of text list names to import (omit for all)",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "csv_import_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "file_paths"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "csv_path": {
        +        "description": "Destination CSV file path",
        +        "type": "string"
        +      },
        +      "languages": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "text_lists": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "csv_export_component_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "csv_path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "file_paths": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "languages": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "text_lists": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "csv_import_component_text_lists",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "file_paths"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "properties": {
        +        "description": "List of property sets. Use property constants: AliasName, RefreshTime (High/Medium/Low/Standard), WriteProtected, AccessNumber, LimitLow, LimitHigh, Unit, Keyboard, EnumValue, InitValue, etc.",
        +        "items": {
        +          "properties": {
        +            "element": {
        +              "description": "Datapoint / datatype / scheme name",
        +              "type": "string"
        +            },
        +            "property": {
        +              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        +              "type": "string"
        +            },
        +            "value": {
        +              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        +              "type": [
        +                "string",
        +                "number",
        +                "boolean",
        +                "null"
        +              ]
        +            }
        +          },
        +          "required": [
        +            "element",
        +            "property",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_datapoint_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "properties"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "properties": {
        +        "items": {
        +          "properties": {
        +            "element": {
        +              "description": "Datapoint / datatype / scheme name",
        +              "type": "string"
        +            },
        +            "property": {
        +              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        +              "type": "string"
        +            },
        +            "value": {
        +              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        +              "type": [
        +                "string",
        +                "number",
        +                "boolean",
        +                "null"
        +              ]
        +            }
        +          },
        +          "required": [
        +            "element",
        +            "property",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_datatype_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "properties"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes to add. Entries and input can be specified to set them simultaneously.",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_schemes",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes to remove",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "type": "string"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_schemes",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes with entries to add. Position determines insertion point; entries beyond max are appended.",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_scheme_entries",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes with positions to remove. Use 'positions' or 'entries[].position'.",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_scheme_entries",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes with move operations. Use 'moves': [{from: N, to: M}, ...]",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "move_scheme_entries",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes with the 'input' field set to the datapoint name to use as input",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_scheme_inputs",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "properties": {
        +        "description": "PropertySets where 'element' is the scheme name. Available properties: Revision, LockOverloadCompareValue, LockOverloadSetValue",
        +        "items": {
        +          "properties": {
        +            "element": {
        +              "description": "Datapoint / datatype / scheme name",
        +              "type": "string"
        +            },
        +            "property": {
        +              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        +              "type": "string"
        +            },
        +            "value": {
        +              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        +              "type": [
        +                "string",
        +                "number",
        +                "boolean",
        +                "null"
        +              ]
        +            }
        +          },
        +          "required": [
        +            "element",
        +            "property",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "scheme_type": {
        +        "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_scheme_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "scheme_type",
        +      "properties"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "schemes": {
        +        "description": "Schemes with entries where each entry specifies position + property + value to set. Entry properties: Operator (<,<=,=,>=,>,<>), CompareValue, SetValue. For StateScheme SetValue: None, Active, Inactive, Invisible.",
        +        "items": {
        +          "properties": {
        +            "entries": {
        +              "description": "Scheme entries",
        +              "items": {
        +                "properties": {
        +                  "new_position": {
        +                    "description": "Target position for move operations",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "position": {
        +                    "description": "0-based position in the scheme",
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "property": {
        +                    "description": "Entry property to set, e.g. 'SetValue', 'CompareValue', 'Operator'",
        +                    "type": "string"
        +                  },
        +                  "value": {
        +                    "description": "Value to set for the property",
        +                    "type": [
        +                      "string",
        +                      "number",
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "position"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "input": {
        +              "description": "Input datapoint name for the scheme",
        +              "type": "string"
        +            },
        +            "moves": {
        +              "description": "Move operations (for move_scheme_entries)",
        +              "items": {
        +                "properties": {
        +                  "from": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "to": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "from",
        +                  "to"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "name": {
        +              "description": "Scheme name",
        +              "type": "string"
        +            },
        +            "positions": {
        +              "description": "Entry positions (for remove_scheme_entries)",
        +              "items": {
        +                "maximum": 9007199254740991,
        +                "minimum": -9007199254740991,
        +                "type": "integer"
        +              },
        +              "type": "array"
        +            },
        +            "scheme_type": {
        +              "description": "Scheme type constant: 'ColorScheme', 'StateScheme', 'FontStyleScheme', 'KeyboardScheme', 'KeyboardLayoutScheme', 'MediaScheme', 'NavigationScheme', 'TextScheme', 'UnitScheme', 'DatapointScheme', 'CompositeControlScheme'",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "scheme_type",
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_scheme_entry_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "schemes"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "items": {
        +        "description": "Media items to add. Each needs media_type and path (full file path).",
        +        "items": {
        +          "properties": {
        +            "media_type": {
        +              "description": "Media type: 'Image', 'Video', 'Audio', 'Docs', 'Fonts', 'KeyboardLayouts', 'Other'",
        +              "type": "string"
        +            },
        +            "name": {
        +              "description": "File name including extension (for remove operations)",
        +              "type": "string"
        +            },
        +            "path": {
        +              "description": "Full file path (for add operations)",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "media_type"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "overwrite": {
        +        "default": false,
        +        "description": "Overwrite existing items with the same name",
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "add_media_items",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "items"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "items": {
        +        "description": "Media items to remove. Each needs media_type and name (filename + extension).",
        +        "items": {
        +          "properties": {
        +            "media_type": {
        +              "description": "Media type: 'Image', 'Video', 'Audio', 'Docs', 'Fonts', 'KeyboardLayouts', 'Other'",
        +              "type": "string"
        +            },
        +            "name": {
        +              "description": "File name including extension (for remove operations)",
        +              "type": "string"
        +            },
        +            "path": {
        +              "description": "Full file path (for add operations)",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "media_type"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_media_items",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "items"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "paths": {
        +        "description": "Full paths to code module files (.js or .ts) to add",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_code_modules",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "paths"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "names": {
        +        "description": "File names (with extension) of code modules to remove",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_code_modules",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "names"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "update_property_values",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "update_runtime",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "station_nr": {
        +        "description": "Station number to delete from the project.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "delete_station",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "station_nr"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "output_path": {
        +        "description": "Destination JSON file for the update-station details.",
        +        "type": "string"
        +      },
        +      "station_nr": {
        +        "description": "Station number to diff against the project state.",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "station_details",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "station_nr",
        +      "output_path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "deep_merge": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "overwrite": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "source_path": {
        +        "description": "Source .lvp project to import from.",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "import_project",
        +        "type": "string"
        +      },
        +      "user_folder": {
        +        "default": true,
        +        "description": "Import the user-defined folder structure.",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "source_path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "languages": {
        +        "description": "Language names/codes to add (e.g. ['De','En']).",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_languages",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "languages"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "languages": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_languages",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "languages"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "properties": {
        +        "description": "Property sets where 'element' is the language name. Use the properties supported by lvd.Language (e.g. the constants behind Language.NameSet / Language.RevisionSet).",
        +        "items": {
        +          "properties": {
        +            "element": {
        +              "description": "Datapoint / datatype / scheme name",
        +              "type": "string"
        +            },
        +            "property": {
        +              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        +              "type": "string"
        +            },
        +            "value": {
        +              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        +              "type": [
        +                "string",
        +                "number",
        +                "boolean",
        +                "null"
        +              ]
        +            }
        +          },
        +          "required": [
        +            "element",
        +            "property",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_language_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "properties"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alarms": {
        +        "description": "Alarms to add (name, optional server/group and revision).",
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "description": "Alarm name",
        +              "type": "string"
        +            },
        +            "revision": {
        +              "description": "Alarm revision string",
        +              "type": "string"
        +            },
        +            "server_or_group": {
        +              "description": "Alarm server or group",
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "add_alarms",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "alarms"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "names": {
        +        "description": "Alarm names to remove",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "remove_alarms",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "names"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "properties": {
        +        "description": "Property sets where 'element' is the alarm name.",
        +        "items": {
        +          "properties": {
        +            "element": {
        +              "description": "Datapoint / datatype / scheme name",
        +              "type": "string"
        +            },
        +            "property": {
        +              "description": "Property constant, e.g. 'AliasName', 'RefreshTime', 'WriteProtected', 'LimitLow', 'LimitHigh', 'Unit', 'Keyboard', 'EnumValue', 'InitValue'",
        +              "type": "string"
        +            },
        +            "value": {
        +              "description": "Value to set. Numbers and booleans are auto-converted to strings by the API.",
        +              "type": [
        +                "string",
        +                "number",
        +                "boolean",
        +                "null"
        +              ]
        +            }
        +          },
        +          "required": [
        +            "element",
        +            "property",
        +            "value"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_alarm_properties",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "properties"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alarms": {
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "type": "string"
        +            },
        +            "server_or_group": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name",
        +            "server_or_group"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_alarm_servers_or_groups",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "alarms"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alarms": {
        +        "items": {
        +          "properties": {
        +            "name": {
        +              "type": "string"
        +            },
        +            "revision": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "name",
        +            "revision"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "set_alarm_revisions",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "alarms"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "add_runtime": {
        +        "default": false,
        +        "description": "Force runtime download even if version matches",
        +        "type": "boolean"
        +      },
        +      "connection": {
        +        "description": "Connection string, e.g. 'TCPIP:192.168.1.100' or 'TCPIP:myhmi.local'. Use the 'TCPIP:' prefix for IP/DNS targets.",
        +        "type": "string"
        +      },
        +      "flags": {
        +        "default": 0,
        +        "description": "Download mode: 0=normal (default), 1=changes only, 2=publish+download changes",
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "download",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "connection"
        +    ],
        +    "type": "object"
        +  }
        +]
  2. 31 tool updates
    • Changedapply_project_changes3 fields changed
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "default": false,
        +  "description": "Validate operations without applying them.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / operations / description
        Previous value: -"Ordered list of operations to apply. Each has a 'type' field. Channel ops (add/remove/rename_server, add/remove/rename_client) edit .st files directly and cascade to .lcn files. Network ops (create/delete/rename_network, add/remove/rename_object, create/delete_connection, set_init_value, delete_class) run via Lasal2.exe batch script."New value: +"Ordered list of CLASS 2 batch engine operations. Available types: create_network, delete_network, rename_network, duplicate_network, add_object, remove_object, rename_object, change_object_class, create_connection, delete_connection, set_init_value, delete_class, compile, download, set_task_order, set_task_time, set_task_cpu_core, set_multi_cpu_core, set_visualized_flag, set_comment_network, set_comment_object, set_network_options, reset_network_options, move_network_to_folder, set_parameter_value"
      • addedInput schema / properties / operations / items / oneOf
        Added value: +[
        +  {
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "create_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "deleteConnections": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "delete_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "newName": {
        +        "type": "string"
        +      },
        +      "oldName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "rename_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "oldName",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "name": {
        +        "type": "string"
        +      },
        +      "newName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "duplicate_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "add_object",
        +        "type": "string"
        +      },
        +      "visualized": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "x": {
        +        "default": 300,
        +        "type": "number"
        +      },
        +      "y": {
        +        "default": 300,
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "className",
        +      "objectName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "deleteConnections": {
        +        "default": true,
        +        "type": "boolean"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "remove_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "newName": {
        +        "type": "string"
        +      },
        +      "oldName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "rename_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "oldName",
        +      "newName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "change_object_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "className"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "fromClient": {
        +        "type": "string"
        +      },
        +      "fromObject": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "toObject": {
        +        "type": "string"
        +      },
        +      "toServer": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "create_connection",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "fromObject",
        +      "fromClient",
        +      "toObject",
        +      "toServer"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "clientName": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "delete_connection",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "objectName",
        +      "clientName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "channelName": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_init_value",
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "objectName",
        +      "channelName",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "className": {
        +        "type": "string"
        +      },
        +      "force": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "delete_class",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "className"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "options": {
        +        "default": "RebuildAll",
        +        "enum": [
        +          "RebuildAll",
        +          "BuildChanges",
        +          "UserClassesOnly",
        +          "NoDebugInfo"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "compile",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "add_loader_anyway": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "connection": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "download",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "position": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork",
        +          "background"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_order",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "position"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork",
        +          "background"
        +        ],
        +        "type": "string"
        +      },
        +      "time": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_time",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "time"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "core": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "task": {
        +        "enum": [
        +          "realtime",
        +          "cyclicwork"
        +        ],
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_task_cpu_core",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "task",
        +      "core"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "multiCore": {
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "set_multi_cpu_core",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "multiCore"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "isVisualized": {
        +        "type": "boolean"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_visualized_flag",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "isVisualized"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "comment": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_comment_network",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "comment"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "comment": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_comment_object",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "comment"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "optionNames": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "resetAllOthers": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "const": "set_network_options",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "optionNames"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "optionNames": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "type": {
        +        "const": "reset_network_options",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "optionNames"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "folder": {
        +        "type": "string"
        +      },
        +      "network": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "move_network_to_folder",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "folder"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "network": {
        +        "type": "string"
        +      },
        +      "objectName": {
        +        "type": "string"
        +      },
        +      "parameterName": {
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "set_parameter_value",
        +        "type": "string"
        +      },
        +      "value": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "network",
        +      "objectName",
        +      "parameterName",
        +      "value"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Removedapply_visu_changes
    • Addedbuild_project
    • Removedclose_class2
    • Removedclose_visudesigner
    • Removedcompile_project
    • Addedcontrol_plc
    • Changeddeploy_all2 fields changed
      • addedInput schema / properties / start_hmi_runtime
        Added value: +{
        +  "default": false,
        +  "description": "Start the local HMI runtime (DataService) and copy HMI files after a successful compilation/update. Default false.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / timeout_s
        Added value: +{
        +  "description": "Timeout override in seconds for compile and download steps.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
    • Removeddownload_project
    • Removeddownload_visu_project
    • Removedget_plc_state
    • Addedhmi_browser
    • Addedhmi_runtime
    • Removedinspect_project
    • Removedinspect_visu_project
    • Addedlars_runtime
    • Addedlasal_status
    • Addedmanage_class2
    • Addedmanage_visudesigner
    • Removedopen_class2
    • Removedopen_visudesigner
    • Addedplc_diagnostics
    • Addedplc_values
    • Removedread_class_source
    • Removedread_plc_values
    • Removedset_target_ip
    • Removedstart_plc
    • Removedstop_plc
    • Addedvisu_project
    • Removedwrite_class_source
    • Removedwrite_plc_values
  3. 21 tool updatesv0.1.0
    • First observedapply_project_changes
    • First observedapply_visu_changes
    • First observedclose_class2
    • First observedclose_visudesigner
    • First observedcompile_project
    • First observeddeploy_all
    • First observeddownload_project
    • First observeddownload_visu_project
    • First observedget_plc_state
    • First observedinspect_project
    • First observedinspect_visu_project
    • First observedopen_class2
    • First observedopen_visudesigner
    • First observedread_class_source
    • First observedread_plc_values
    • First observedselect_project
    • First observedset_target_ip
    • First observedstart_plc
    • First observedstop_plc
    • First observedwrite_class_source
    • First observedwrite_plc_values

TDQS

A3.6/5.0

Scored across 23 tools

Disambiguation4/5

Most tools target a distinct subsystem (CLASS 2, VISUDesigner, LASAL SCREEN, LARS, HMI, PLC), but there are genuine overlaps: build_project vs deploy_all both compile/download, run_class2_script overlaps apply_project_changes as a broader escape hatch, and the three 'engine operation' tools (visu_project, lse_project) are similar in shape. Descriptions help distinguish them but an agent could misselect among the deploy/build family.

Naming Consistency4/5

All names use snake_case consistently, which is good. However the verb pattern is mixed: many are verb_noun (build_project, control_plc, manage_class2, set_target_ip) while several are noun_topic (lasal_status, plc_values, lse_project, hmi_runtime), so the convention is readable but not uniform.

Tool Count4/5

23 tools is on the heavier side, but the domain spans multiple engines and deployment pipelines, so each tool has a defensible role. It borders on heavy but avoids redundancy for a system this complex.

Completeness4/5

Coverage is strong across the lifecycle: project selection/inspection, source editing, batch operations, builds, single- and multi-station deploys, PLC/runtime control, live values, diagnostics, GUID validation, LARS simulation and HMI simulation. Minor gaps remain (e.g. no explicit new CLASS 2 project creation or teardown), but the surface is largely complete and has no obvious dead ends.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to interact with B\&R Automation Studio projects by building code, running ARsim simulators, and reading or writing OPC UA variables. It facilitates industrial automation development and real-time variable integration through natural language commands.
    15
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    MCP server that connects AI assistants to Siemens TIA Portal via the Openness API. AI-assisted PLC programming, project management, hardware configuration, cross-reference analysis, and deployment. 19 tools, 230 actions.
    51
    -
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI agents to discover, inspect, edit, rebuild, and save Schneider Electric RemoteConnect and SCADAPack x70 IEC logic projects, including program sections, hardware, variables, and Modbus configuration.
    63
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI to operate STEP 7-Micro/WIN SMART via MCP, supporting offline STL/AWL analysis, project inspection, online PLC monitoring (snap7), and engine-injected operations like compile, download, upload, and symbol management through natural language.
    8
    -