Model Context Protocol server for LabVIEW integration, providing tools to interact with LabVIEW IDE, run VIs, build projects, generate code from AIXML, and manage Actor Framework message classes
LabVIEW MCP exhibits strong technical depth in descriptions but inconsistent schema formalization. All 6 tools have detailed, domain-specific descriptions (100-500+ chars) explaining LabVIEW semantics, side effects, and prerequisites. However, input schemas lack formal type constraints: parameters are typed as string/integer/boolean but lack enums, patterns, or min/max bounds. Output schemas are entirely undocumented, no structured response definitions visible. Tool names follow verb_noun convention (run, build, create, convert, generate) but are overly specific (lvai_* prefix) rather than discoverable. Error handling is mentioned in descriptions but not formalized in schema. Security concerns (destructive operations, file I/O) are flagged in descriptions but lack permission gates or confirmation patterns.
RPC BuildFromBuildSpecification. MUTATING: runs a build specification of a .lvproj and returns the generated files. Writes build output to disk and can take minutes - raise timeoutSeconds accordingly. This is the CI-shaped capability of the interface.
RPC ConvertVIToAIXML. Serializes an existing VI into LabVIEW's AIXML text format and writes it to aiXmlFilePath. Does NOT modify the VI. With returnContent the XML is also returned inline, which is normally what you want when reading code. This is the reference path for learning the AIXML dialect before generating any. CACHED ON DISK, but only for VIs that belong to the LabVIEW INSTALLATION - the examples tree, vi.lib, user.lib and every LVAddon, which is to say exactly the example and palette VIs you read to learn from. MEASURED over 1677 of them: median 331 ms per export, p99 24 s, worst case 93 s, and the cost is loading the VI rather than writing the XML (size and duration correlate at r = 0.002). A second read of the same VI is a file copy, and needs no running LabVIEW at all. YOUR OWN CODE IS NEVER CACHED and needs no flag for that: an export depends on a VI's subVIs too, and user code changes one subVI at a time behind a caller whose own timestamp never moves. Every answer carries fromCache and a one-line cacheNote, so which of the two happened is visible rather than guessed. Pass refresh to re-export a cached VI anyway.
Several VIs through ConvertVIToAIXML in one call, written into outputDirectory. Use this when TRIAGING CANDIDATES - deciding which example or template is the right starting point - where the alternative is one tool call per candidate. WHAT IT DOES AND DOES NOT PARALLELISE, both measured. Cached exports are served CONCURRENTLY: a hit is a file copy in this process with no LabVIEW involved, and concurrent file reads are worth about 21x on a cold tree. Anything not cached is exported SEQUENTIALLY, because LabVIEW serialises the RPC anyway - six ConvertAIXMLToVI calls issued at once took 559 ms against 543 ms one after another, so firing them concurrently buys nothing and a slow one would make every other call queue behind it. The practical consequence: the first pass over a set of candidates costs what it costs, and every later pass is nearly free. Caching rules are those of lvai_convert_vi_to_aixml - installation VIs only, never your own code. Content is NOT returned inline by default: a batch of full exports is large, and the point here is to get the files onto disk cheaply so you can read the ones worth reading. Each answer gives that VI's xmlPath.
No output schemas documented. Tools return complex results (XML content, file paths, verification blocks, pane violations) but LLMs cannot predict response structure. Downstream tool chaining is impossible without trial-and-error.
Input parameters lack formal constraints. timeoutSeconds accepts any integer but should have min/max bounds (e.g., 1-3600). viPath and projectPath accept any string but should validate file existence or path format. No enums for constrained choices (e.g., panePattern values).
Destructive operations (run_vi, build, create_message_class, generate_vi) lack confirmation or dry-run patterns. Descriptions warn of side effects but no mechanism prevents accidental execution. No idempotent hints in schema.
Inferred effective spec: 2025-06-18+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 58 | 2025-06-18+ | v2 |
MUTATING: creates a complete Actor Framework MESSAGE class for one public method of an actor - the class, its private data (one field per parameter of the method), the `Do.vi` override that calls the method, and the `Send <Method>.vi` that enqueues it. IT AUTHORS NO DIAGRAM. A generated override of Message.lvclass:Do.vi is eBad whatever is on it; this drives NI's own Message Maker instead, which clones a template whose Do.vi is already a real override. Measured 2026-09-17 on Counter.lvclass:Increment.vi: Do.vi at execState 1 calling Counter.lvclass:Increment.vi with Amount wired from the message's own private data, and Send Increment.vi at execState 1 with the pane `Message Enqueuer` (11, required), `Amount` (10), `Message Priority (Normal)` (7), `error in (no error)` (8) -> `error out` (0), `Message Enqueuer out` (3) - byte for byte NI's own Send VI shape. NEEDS A PROJECT OPEN AND ACTIVE: every step reaches LabVIEW through Project:Active Project and answers Error 1055 without one. Pass projectPath and this call opens it. THE CLASS IS SAVED AT THE END, and that is not a detail. The Message Maker's changes to the CLASS - its private data control and the renamed Send member - live in memory, so a run that saves only the two VIs reports 0 at every stage, gives two VIs at execState 1, and leaves BOTH eBad after the next project close, with the class on disk still listing `Send Template.vi` and no payload field. Measured, then fixed with LVClass.Open + Save. VERIFIED FROM THE SAVED FILE: the answer's `verify` block is read back with pylabview, not from the run, so `fields` and `members` are what is on disk. THE ACTOR MUST DESCEND FROM Actor.lvclass - checked by walking the class file's own parent links, which is also how the LabVIEW installation is located, so the template and the message parent always come from the same install as the actor.
MUTATING: the whole create-a-VI sequence in one round trip - lvai_validate_aixml, then lvai_convert_aixml_to_vi, then lvai_connector_pane on the result. Stops at the first step that fails and reports which one, so a failure reads the same as calling the three by hand. USE THIS INSTEAD OF THE THREE SEPARATE CALLS when you are generating from AIXML you have just authored. It is not a shortcut past them: each step's own answer is returned under `steps`, including elapsedMs, so nothing is hidden. THE PANE CHECK IS THE POINT, not the saved turns. lvai_convert_aixml_to_vi cannot see a badly placed connector pane and neither can a run: a VI whose inputs sit on the output edge validates, generates and executes. That defect has shipped twice. `ok` here is false when the pane breaches NI's style guide, and the corrected conIdx values come back ready to paste - author them into the AIXML and call this again. `ok` false with `paneViolations` > 0 still means the .vi FILE WAS WRITTEN. The generation succeeded; it is the pane that needs another pass. Pass measurePane=false to skip the measurement - only worth it for a scratch probe with no connector pane at all. Pass panePattern to put the result on a SPECIFIC pane pattern instead of the station default - needed when the VI must match a pane that already exists, because a caller's wires bind to terminal positions and the same conIdx means different edges on a different pattern. It runs before the measurement, so what comes back describes the final pane.
RPC RunVIAsTopLevel. MUTATING: actually EXECUTES the VI in LabVIEW with the given control values and returns its indicator values. Side effects are whatever the VI does - it can drive hardware, write files or move a stage. inputs/outputs are string maps, and the values really do cross as STRINGS: measured, LabVIEW does NOT coerce them to the control's type. String controls work; a numeric or path control fails with errorCode 91 at Control Value:Set BEFORE the VI runs - as "42" and as 42 alike. So take numbers and paths in as strings and convert them on the diagram. On the way out an array or cluster indicator also fails to marshal, and there errorCode 91 arrives AFTER the VI has run correctly - it is not proof of failure. Details and the measurements in lvai_aixml_reference section 10. Never run a VI you have not inspected with lvai_describe_vi first.
Error handling is narrative (described in text) but not formalized. No structured error codes, recovery guidance, or categorization (retryable vs. fatal). Descriptions mention error codes (e.g., 'errorCode 91') but no mapping to actionable LLM responses.
Tool names use domain-specific prefix (lvai_*) that obscures intent. 'run_vi_as_top_level' is clearer than 'lvai_run_vi_as_top_level'. Prefix adds no semantic value and reduces discoverability in tool lists.