Skip to main content
Glama
Edge-JB
by Edge-JB

plc_pou

Create, read, edit, and delete PLC program organization units (POUs) and folders within the TwinCAT XAE IEC project offline, including code and declaration text editing, batch operations, and pattern-based search across the project tree.

Instructions

PLC object authoring + code edit on the open solution (OFFLINE engineering only — edits land in-memory and reach a runtime only via a later guarded plc_download + twincat_restart_runtime). Tree paths use ^ separators; safety (TISC-rooted) paths are rejected by policy. CREATE — create / create_batch (parent, name, subType, language?, returnType?, extends?, implements?, declText?, before?): CreateChild sub-types 602 Program, 603 Function (returnType required), 604 FunctionBlock, 605 Enum, 606 Struct, 607 Union, 608 Action, 609 Method, 611 Property (returnType required), 615 GVL, 616 Transition, 618 Interface, 619 Visualization, 623 Alias, 629 ParameterList, 631 UML. language IECLANGUAGETYPES 0 NONE/1 ST/2 IL/3 SFC/4 FBD/5 CFC/6 LD (default 1). extends/implements for FB 604 / Program 602 derivation (618 uses extends as its base); declText seeds DUT/GVL decl. For code POUs prefer set_decl after create. FOLDERS — create_folder (parent, name, before?) creates a PLC folder (sub-type 601) under parent (a PLC subtree node, POUs/DUTs/GVLs container, or another folder); returns the same shape as create. create_folder_batch (creates:[{parent,name,before?}], save?) loops continue-on-error, returns {count,succeeded,failed,results} KEEPING success rows (each carries the created child identity) — list a parent-folder entry before its child (array order). create / create_batch already author INTO a folder when parent is the folder's path — no separate action needed. TEMPLATE — import_template (parent, paths[]) imports POU template file(s) (CreateChild sub-type 58). READ (cheap-first: outline for structure; get_decl/get_impl with grep{} or range{} to slice; full text only when the whole body is needed — a large full read returns a hint nudging the next call to slice) — get_decl / get_impl / get_document / get_graphical (path). get_decl/get_impl take an optional range {start,end} (1-based inclusive line slice, clamped) OR grep {pattern, context?} (regex over lines + context each side); mutually exclusive; default full text. Both report lineCount; get_impl also returns language (textual 1 ST/2 IL; graphical 3 SFC/4 FBD/5 CFC/6 LD -> lineCount:0 + {graphical:true, hint}). get_graphical (path) READ-ONLY inspects a graphical (LD/FBD/SFC/CFC) body: returns {language,languageName,itemType,source,readOnly,xml} where xml is the object's network XML (NWL 'BoxTree' for LD/FBD/IL, or the SFC/CFC archive), pulled live from the POU document (for an Action/Method/Transition it reads the PARENT POU's document, since get_document/GetDocumentXml only work on a top-level POU). Diagnostic only — graphical bodies are NOT text-editable; change them in the XAE GUI. Refuses textual languages (use get_impl). outline (path) returns structure WITHOUT full text: header + varBlocks + child code items. WRITE — set_decl / set_decl_batch (path, declText); set_impl / set_impl_batch (path, exactly one of implText|implXml — implXml is TwinCAT object XML, round-trip only, for graphical languages); set_document (path, documentXml). SURGICAL TEXT EDIT (read-modify-write, returns ONLY the changed region +/-2 ctx; target decl|impl, CRLF/LF preserved; refuses graphical impl): replace (find literal substring, replaceWith, expectCount? default 1 — fails without writing on 0 or count mismatch); replace_lines (start, end, text — 1-based inclusive span, OOB throws); insert (exactly one of at|after|before, text); insert_in_var_block (block e.g. VAR_INPUT, text, occurrence? — inserts before that block's END_VAR); append (text — default target impl). All surgical writes accept validate:true to run CheckAllObjects after (default off). DISCOVER (cheap-first: find for path-by-name; search only for content patterns) — tree (plcPath?, path? subtree root, depth?, typeFilter?) does a read-only recursive Child() walk of the IEC project and returns {plcPath,projectPath,rootPath,count,tree:[{path,name,type,itemType,subType?,childCount,children?,truncated?}]} (type is a normalized label: Program/FB/Function/FunctionBlock/Struct/Enum/Union/Alias/GVL/Interface/Method/Property/Action/Transition/Visualization/ParameterList/UML/Folder/Project/Task/Unknown; depth 1 = direct children only; typeFilter is a comma list of type labels to KEEP, ancestors retained as scaffolding). find (plcPath?, path?, name? substring or /regex/, typeFilter?; at least one of name/typeFilter) returns a FLAT {plcPath,projectPath,count,matches:[{path,name,type,itemType,subType?,childCount}]} so a caller can resolve a ^ path from a name without the whole nested blob. GREP — search (pattern [regex/.NET or substring], ignoreCase?, declOnly?|implOnly? [mutually exclusive], plcPath?, path? subtree root, maxResults? default 50/max 5000 — raise for exhaustive scans; truncated:true signals the cap was hit) is a project-wide find-in-code: walks every code object under the IEC project, greps DeclarationText + (ST-only) ImplementationText line-by-line, returns {pattern,plcPath,scanned,searched,count,truncated,matches:[{path,section:'decl'|'impl',line,text}]}; graphical bodies are scanned-but-not-searched. Read-only/offline. Decl/impl text is CACHED (warm repeat sub-100ms vs ~16s cold); the cache self-invalidates on edits through this tool, dirty-checks open IDE editors, and is backstopped by a file-save watcher — pass refresh:true to force a full live re-pull. DELETE — delete (path OR parent+name) GUARDED offline delete of one PLC object via parent.DeleteChild; dryRun:true previews {wouldDelete,target}, confirm="ALLOW_TWINCAT_DELETE" to actually delete; verifies the child exists first, refuses TISC. LIFECYCLE (OFFLINE, unguarded, refuses TISC) — rename (path, newName = bare name) renames in place, returns {path,newName,newPath}. move (path, newParent, before?) reparents one object preserving decl/impl/document/sub-objects via export-import-delete in ONE attach (no native reparent exists); refuses no-op/into-self/into-own-descendant moves; returns {path,newParent,newPath,name,via}. BUILD-CHECK — check_objects (plcPath?, default first PLC under TIPC) runs CheckAllObjects on the nested IEC project (no download). Mutating batch verbs (create_batch, set_decl_batch, set_impl_batch) accept save:true to save once after the batch.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
atNoinsert before this 1-based line (lineCount+1 appends)
endNoreplace_lines: 1-based inclusive last line
findNoreplace: exact literal substring (NOT regex)
grepNoget_decl/get_impl: regex over lines + context each side (default 2); mutually exclusive with range
nameNo
pathNo
saveNo
textNoreplacement / insert / append text
afterNoinsert after this 1-based line
blockNoinsert_in_var_block: VAR-block keyword e.g. VAR_INPUT
depthNotree: max recursion depth (1 = direct children only); default unlimited
itemsNo
pathsNo
rangeNoget_decl/get_impl: 1-based inclusive line slice; mutually exclusive with grep
startNoreplace_lines: 1-based inclusive first line
actionYes
beforeNocreate: sibling name to insert before (string). insert: 1-based line to insert before (int, alias of at)
dryRunNodelete: preview the target without deleting
parentNo
targetNosurgical edit target; default decl (append defaults impl)
confirmNodelete: must equal ALLOW_TWINCAT_DELETE to actually delete
createsNo
detailsNoset_decl_batch/set_impl_batch: include ok:true rows; default failures-only ({count,succeeded,failed} always reported). create_batch/create_folder_batch always keep success rows (they carry child identity), so details is a no-op there.
extendsNo
implXmlNo
newNameNorename: new bare object name (not a path)
patternNosearch: regex (.NET syntax) or plain substring, matched per-line against each object's decl/impl text
plcPathNo
refreshNosearch: force a full live re-pull, bypassing the decl/impl text cache for the searched scope (default false). Open editors are always dirty-checked automatically; use this only as an escape hatch after structural ops or for paranoia.
subTypeNo
declOnlyNosearch: search only DeclarationText; mutually exclusive with implOnly
declTextNo
implOnlyNosearch: search only ImplementationText (ST-only); mutually exclusive with declOnly
implTextNo
languageNo
validateNosurgical writes: run CheckAllObjects after the edit (default off)
newParentNomove: ^-separated destination parent tree path (TISC refused)
ignoreCaseNosearch: case-insensitive match (default false)
implementsNo
maxResultsNosearch: cap on returned match rows (default 50, max 5000; raise for exhaustive scans); stops the walk and sets truncated:true when hit
occurrenceNoinsert_in_var_block: which matching block (1-based, default 1)
returnTypeNo
typeFilterNotree/find: comma list of normalized type labels to keep/match (case-insensitive), e.g. 'FB,Method,Struct'
documentXmlNo
expectCountNoreplace: required occurrence count (default 1)
replaceWithNo
Behavior5/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure and does so comprehensively. It describes the offline-only nature, in-memory edits with delayed runtime effect, guarded delete requiring explicit confirmation, refusal of TISC-rooted paths, caching behavior with self-invalidation, dirty-checking and file-save watcher for search, and the fact that graphical bodies are not text-editable (diagnostic only via get_graphical). It also notes that batch operations continue on error and return structured results with success rows. All critical behavioral traits are transparent.

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?

The description is very long and dense, packing a huge amount of information into a single block of text. It is structured by action category (CREATE, READ, WRITE, SURGICAL TEXT EDIT, DISCOVER, DELETE, LIFECYCLE, BUILD-CHECK) which helps navigation, but the lack of line breaks, bullet points, or headings makes it hard to scan quickly. Every sentence earns its place, but the overall conciseness suffers from the sheer volume. A little restructuring would improve readability without losing content.

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?

Given the tool's high complexity (46 parameters, up to 28 enum actions, nested objects, no output schema), the description is remarkably complete. It covers all major action categories, parameter semantics, behavioral traits, ordering dependencies (e.g., list a parent folder entry before its child in create_folder_batch), and error handling (e.g., replace fails on count mismatch). The absence of an output schema is mitigated by describing return shapes in the text. However, some edge cases (e.g., what happens when move fails mid-operation) are not mentioned, and the caching details could be more precise about when refresh is truly needed.

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 59%, meaning many parameters lack descriptions in the schema. The description compensates by explaining parameters in context for each action (e.g., subType values and their meanings, language enum values, range and grep usage for get_decl/get_impl, expectCount for replace, validate for surgical writes). However, some parameters like 'details', 'at', 'before' dual-type, and 'occurrence' are still only partially explained relative to the rich action set. Overall, the description adds significant meaning beyond the schema, but the schema itself still has gaps that are not fully covered.

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 begins by clearly stating 'PLC object authoring + code edit on the open solution,' which specifies the verb (author and code edit) and the resource (PLC objects). It thoroughly differentiates from siblings by emphasizing OFFLINE engineering only, tree path separators, and safety policy for TISC paths. This makes the tool's purpose unmistakable and distinct from building, downloading, or runtime tools like xae_build, plc_download, or twincat_restart_runtime.

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?

The description explicitly states when to use this tool ('OFFLINE engineering only') and when not to ('refuses TISC'). It provides detailed alternatives for specific operations (e.g., 'For code POUs prefer set_decl after create', 'read-modify-write cycle for surgical edits', 'cheap-first: outline for structure; get_decl/get_impl with grep or range'). It distinguishes between discovery, reading, writing, and lifecycle operations, and guides the agent on cost-saving strategies like using outline before full text, or search for content patterns vs find for path-by-name.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Edge-JB/TwinCAT-XAE-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server