Tools
Tool reference.
Every tool is a typed, stable interface to PLCs.ai. Names are stable, snake_case, and prefixed plcs_. Reads are safe; writes are consequential and may be billable — see Safety & billing.
Inputs below are the agent-visible parameters. The server manages transport details for you: model tools (plcs_interpret, plcs_generate_code) run synchronously and return one complete result; writes accept an optional idempotency_key (omit it and the server mints one per call); and file uploads take a file_path/file_inline/file_blob_url instead of raw multipart. For a large or locally-generated file, plcs_stage_upload returns a short-lived upload URL you PUT the bytes to — then pass it back as file_blob_url, so the file never streams through the model.
Connect & discover
plcs_health
Authenticated health check
Authenticated connectivity check for PLCs.ai. Returns the organization id resolved from your credential and the actor type. Use this first to confirm the connection works and which organization you are acting as. Requires only a valid credential — no extra permission.
Inputs
plcs_list_projects
List projects
List the PLC projects this credential can see, most-recently-touched first. Returns identity metadata only (id, name, vendor, version, analysis status) — NOT the project source; read source with plcs_get_project_source. Results are filtered to the credential's project scope and paginated via an opaque cursor (pass cursor from a prior response to page). Requires only a valid credential — no extra permission.
Inputs
| Input | Type | Description |
|---|---|---|
team_id | string | Restrict to a single team. |
limit | integer | Page size (default 50, max 200). |
cursor | string | Opaque cursor from a previous response's next_cursor. |
plcs_get_project
Get a project
Get one project's identity and current-version metadata plus a short analysis_status summary (not the full results blob). An unknown or out-of-scope id returns a not-found error. Requires only a valid credential.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
Read source & live data
plcs_get_project_source
Read a project's source
Read a project's source in one of four representations via format: parsed (default — vendor-neutral parsed structure as JSON), raw (the current committed version's L5X XML or Siemens ZIP, handed back as a file path or short-lived URL, never inline), scl (aggregated Structured Text), or ladder (aggregated ladder rungs). ALL formats reflect the LATEST committed version — including in-app edits saved on the platform, so raw never returns a stale originally-uploaded file. NOTE: parsed on a large project can exceed the inline size ceiling and fail with a too-large error — when that happens, retry with format=raw. Requires the code_read permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
format | string enum |
plcs_get_live_values
Latest live tag values
Get the latest live tag values for a project, as streamed by a Desktop Companion App (DCA) session. This is PLCs.ai's most differentiated read: real values off the running plant. IMPORTANT: when no DCA is actively streaming, the response is a normal success with live: false and an empty tags object — this is the expected "no live session" state, NOT an error. Requires the hmi_view permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
plcs_get_tag_history
Recent value history for a tag
Get the recent, most-recent-first value history for a single tag (tag is required) from the current Desktop Companion App session. Returns an empty history when no live session has streamed that tag — a normal state, not an error. Requires the hmi_view permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
tag required | string | The tag name to fetch history for. |
limit | integer | Max entries (default 50, max 600). |
Ground & interpret
plcs_search_context
Retrieve grounded context for a query
Retrieve grounded context for a natural-language query from a project: returns the matching source chunks with similarity scores (highest-score first) and human-readable citations (e.g. program · routine, a block name, or a filename). This is RETRIEVAL, NOT GENERATION: there is no synthesized answer — YOU reason over the returned chunks yourself. Use it to ground your own reasoning in real source material before answering a question about the plant or code (distinct from any interpretation tool, which would return a model-written answer). A project with no searchable content returns an empty chunks array — a normal state, not an error. Optional limit caps the chunk count (default 8, max 25). Requires the code_read permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
query required | string | The natural-language query to retrieve context for. |
limit | integer | Max chunks to return (default 8, max 25). Alias top_k. |
plcs_interpret
Interpret a prompt against a project
Ask PLCs.ai's own PLC-specialized assistant to INTERPRET a project and get back a written, cited answer in one blocking call: { answer, citations, usage }. This is GENERATION, not retrieval: PLCs.ai produces a synthesized answer for you — distinct from plcs_search_context, which returns only raw source chunks for YOU to reason over, and from plcs_generate_code, which writes or modifies logic. Prefer this when the human EXPLICITLY asks for PLCs.ai's own interpretation/opinion of what the code does or why; otherwise ground your own reasoning with plcs_search_context instead. answer is the prose interpretation; citations are the source identifiers backing it (suppress them with include_citations: false). It reads only — it creates NO version and changes nothing in the project. If the organization is paused at its API spend limit the call fails with a spend-limit error — surface it to the human (they can raise the limit in Settings) and do not retry. Requires the ai_explain permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
prompt required | string | The question to ask about the project. |
include_citations | boolean | Whether to include source citations in the response. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
Analyze
plcs_start_analysis
Start an async analysis job
Start an asynchronous analysis run on a project (dead code, missing handshakes, cycle-time, etc.) and get back a job id immediately — this does NOT block until the analysis finishes. Returns { analysisId, status }; then poll plcs_get_analysis with that analysisId until status is complete (or error). A queued/running status is normal progress, NOT a failure. If the organization is paused at its API spend limit the call fails with a spend-limit error — surface that to the human (they can raise the limit in Settings); do not retry automatically. Requires the analysis_tab permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
plcs_get_analysis
Poll an analysis job
Poll the status of an analysis job started by plcs_start_analysis, by its analysisId. While the job is queued/running the response carries a message with poll guidance and no results yet — keep polling, this is normal, not an error. When status is complete the results are populated; when error, errors are populated. This is a read (no charge). Requires the analysis_tab permission.
Inputs
| Input | Type | Description |
|---|---|---|
analysisId required | string | The analysis job id returned by startAnalysis. |
Generate & save
plcs_generate_code
Generate or modify PLC code (proposal)
Ask the assistant to PRODUCE or MODIFY PLC logic and get back a reviewable proposal in one blocking call: { generated_code, code_blocks, citations, usage }. generated_code is the full markdown proposal (prose + fenced ladder/st/scl blocks + inline insertion directives); code_blocks lifts those fenced blocks out for programmatic use. CRITICAL SAFETY PROPERTY — it PROPOSES, NEVER DEPLOYS: this creates NO version and changes nothing in the project. To persist a proposal you must take a separate, explicit step (plcs_save_version, which needs the code_write permission). If the organization is paused at its API spend limit the call fails with a spend-limit error — surface it to the human and do not retry. Requires the ai_generate permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
prompt required | string | What to generate or change (e.g. "Add a 5-second start-up delay timer"). |
target | object | Optional hint for which program/routine to target. Folded into the prompt as guidance; the assistant decides the final placement. |
target.program | string | — |
target.routine | string | — |
include_citations | boolean | Whether to include source citations in the response. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
plcs_save_version
Commit a new version (Save project)
Persist a NEW version of an existing project from an updated vendor file — the headless equivalent of "Save project". IRREVERSIBLE & CONSEQUENTIAL: a successful commit bumps the project's current version and re-runs analysis — so a client may ask you to confirm first. Provide the file ONE of three ways: file_path (a path on the machine running this server, read in on-prem/local mode), file_inline (base64-encoded bytes), or file_blob_url (a URL the API can fetch). The server picks inline-vs-large-file transport by size automatically — you do NOT base64 large files yourself. originalFilename is optional when using file_path (derived from the path). If you GENERATED/edited the file locally and this server is remote (no shared disk for file_path), do NOT use file_inline — base64 costs a token per byte. Instead call plcs_stage_upload first, PUT the bytes to the upload_url it returns, then pass its file_blob_url + originalFilename here (token-free). The uploaded file MUST be the same vendor as the project (an L5X stays L5X, a Siemens ZIP stays Siemens) — a mismatch returns a 400. Re-sending the exact current bytes is a safe no-op that returns 200 with resolution: identical_file and NO new version. This only persists what you give it — author a change first with plcs_generate_code, review it, THEN save. Requires the code_write permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
name | string | Optional display name for the project. |
acknowledge_billing | boolean | Acknowledges the per-project charge for an enterprise per-project organization. Only consulted when this upload would create a NEW billable project; ignored for every other org type and for add-version / identical-file. When a new billable project is created without this set to true, the request is rejected with 402 billing_acknowledgement_required (carrying the projected cost); resend with true to confirm. Ignored on POST /projects/{id}/versions. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
originalFilename | string | The vendor file name (e.g. "Injection_Molding.L5X" or "Reference_Coiler.zip"). Optional when using file_path — derived from the path basename. |
file_path | string | Path to the vendor file on the machine running this MCP server (on-prem/local mode). The server reads it and handles upload sizing. |
file_inline | string | Base64-encoded file bytes — an alternative to file_path when the file is not on the server's filesystem. Large files are routed to the large-file flow automatically. |
file_blob_url | string | A URL the PLCs.ai API can fetch the file bytes from (large-file escape hatch). Provide originalFilename alongside it. |
plcs_stage_upload
Stage a file upload (token-free)
Stage a TOKEN-FREE file upload for a subsequent plcs_save_version or plcs_ingest_project. Use this whenever the file you want to save was generated or edited LOCALLY and this MCP server is remote — so file_path (which needs a shared disk) is unavailable and file_inline would cost a token for every byte of the file. It returns an upload_url: PUT the raw file bytes there over plain HTTP (e.g. curl -T <file> "<upload_url>") so the bytes never pass through the model. It also returns a file_blob_url that the PLCs.ai API fetches the bytes from. After uploading, call plcs_save_version / plcs_ingest_project with that file_blob_url and originalFilename. The links are short-lived. This creates NO project version on its own, is NOT billable, and makes no change to any project.
Inputs
| Input | Type | Description |
|---|---|---|
filename required | string | The vendor file name to stage, e.g. "PG_CM13.L5X" or "Reference_Coiler.zip". |
Export
plcs_export_plc
Export the project to its vendor PLC file
Start an asynchronous export of a project's current committed version to its native vendor format (Rockwell .L5X or a Siemens TIA .zip) and get back a job id immediately — this does NOT block. Returns { exportId, status }; then poll plcs_get_export with that exportId until status is complete, and fetch the bytes with plcs_download_export. Exports the current version as-is (no edits). Requires the export_plc permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
plcs_export_pdf
Render a PDF report for the project
Start an asynchronous render of a PDF documentation report for a project's current committed version (it does NOT include in-app chat history). Returns { exportId, status } immediately; poll plcs_get_export until complete, then fetch the bytes with plcs_download_export. Requires the export_pdf permission.
Inputs
| Input | Type | Description |
|---|---|---|
id required | string | The project id. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
plcs_get_export
Poll an export job
Poll the status of an export job started by plcs_export_plc / plcs_export_pdf, by its exportId. While pending/running the response carries a message with poll guidance and no artifact yet — keep polling, this is normal, not an error. When status is complete, download_url (a relative path) and filename are populated — but prefer plcs_download_export to actually retrieve the bytes. When error, error carries a short reason. This is a read (no charge). Gated on the export's matching permission (export_plc / export_pdf).
Inputs
| Input | Type | Description |
|---|---|---|
exportId required | string | The export job id returned by startPlcExport / startPdfExport. |
plcs_download_export
Download a completed export artifact
Retrieve the finished artifact (L5X / Siemens ZIP / PDF) of a complete export job by its exportId. The bytes are handed back as a local file path (on-prem) or a short-lived signed URL (cloud) — NEVER inlined into the response, so a large ZIP/PDF never floods the conversation. Read the artifact from the returned path/URL. Call plcs_get_export first and only download once status is complete. Gated on the export's matching permission.
Inputs
| Input | Type | Description |
|---|---|---|
exportId required | string | The export job id returned by startPlcExport / startPdfExport. |
Ingest & embed
plcs_ingest_project
Ingest an L5X / Siemens export
Upload an L5X (Rockwell) or Siemens TIA ZIP export to create or update a project (billed identically to a UI upload). CONSEQUENTIAL — a client may ask you to confirm first. Provide the file ONE of three ways: file_path (a path on the machine running this server, read in on-prem/local mode), file_inline (base64-encoded bytes), or file_blob_url (a URL the API can fetch); the server picks inline-vs-large-file transport by size automatically. If you GENERATED the file locally and this server is remote (no shared disk for file_path), do NOT use file_inline — base64 costs a token per byte; call plcs_stage_upload first, PUT the bytes to its upload_url, then pass its file_blob_url + originalFilename here (token-free). BILLING CONSENT: for an enterprise per-project organization, creating a NEW billable project returns 402 billing_acknowledgement_required with a projected-cost block (price_per_project_cents, currency, billed_count_after). DISCLOSE that cost to the human and only resend with acknowledge_billing: true on an EXPLICIT human go-ahead — NEVER acknowledge billing on your own. A 402 billing_setup_required means billing is not set up yet — the human must set it up in the desktop app, then retry. Note: a project-scoped key may only ADD a version to an in-scope identity; it can never create a NEW identity (use an unscoped key for that). Requires the project_upload permission.
Inputs
| Input | Type | Description |
|---|---|---|
name | string | Optional display name for the project. |
acknowledge_billing | boolean | Acknowledges the per-project charge for an enterprise per-project organization. Only consulted when this upload would create a NEW billable project; ignored for every other org type and for add-version / identical-file. When a new billable project is created without this set to true, the request is rejected with 402 billing_acknowledgement_required (carrying the projected cost); resend with true to confirm. Ignored on POST /projects/{id}/versions. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |
originalFilename | string | The vendor file name (e.g. "Injection_Molding.L5X" or "Reference_Coiler.zip"). Optional when using file_path — derived from the path basename. |
file_path | string | Path to the vendor file on the machine running this MCP server (on-prem/local mode). The server reads it and handles upload sizing. |
file_inline | string | Base64-encoded file bytes — an alternative to file_path when the file is not on the server's filesystem. Large files are routed to the large-file flow automatically. |
file_blob_url | string | A URL the PLCs.ai API can fetch the file bytes from (large-file escape hatch). Provide originalFilename alongside it. |
plcs_mint_embed_token
Mint a read-only embed token
Mint a short-lived, project-scoped, read-only token for the embeddable assistant iframe. Regardless of your key's scope the token is intersected down to read-only (ai_explain + hmi_view) — a browser-delivered token can never carry a write scope. Returns { token, expires_at, permissions, project_id }. The minting key must itself have at least ai_explain.
Inputs
| Input | Type | Description |
|---|---|---|
project_id required | string | The project the embed token may access. |
idempotency_key | string | Optional idempotency key (e.g. a UUID). Normally omit it — the server generates one per call. Pass the SAME key to safely retry this write without double-billing: a replay returns the original result. |