Answer
The WAGO PLC MCP server cannot flash a PLC. A person or CI runs the separate fwupdate tool, and that tool needs a committed Git approval for the device and the firmware revision.
invoke_methodrefuses allfirmware*and0-0-update-*methods, so an agent cannot start an update.1upload_filesends the full file with onePUT, and the WDA docs record413for that call. Firmware uploads need chunks of about 4 MB.23- In GitOps mode, the agent only proposes the change. A person reviews and merges the proposal.4
Applies toServer 2.4.4, firmware 4.9.1 and 02.00.13. Checked in code and docs. No device touched. The upload limit was not tested through the MCP server.
Who can write firmware to a PLC?
Diagram structure
- AI agent
agent - Engineer or CI
engineer - Firmware files
files - MCP server
mcp - Approval repository
policy - fwupdate tool
tool - WAGO PLC
plc - Audit log
audit agent→mcp· reads, proposesengineer→policy· commitspolicy→tool· checkedfiles→tool· selectedmcp→plc· no firmwaretool→plc· flashesmcp→audit· recordstool→audit· records
Both paths write to the same hash-chained audit log. The log also records each refusal.5
What must be ready before you start?
| Item | Requirement |
|---|---|
| Host | Docker with Compose, and Git. Windows 10 or 11 and Linux both work. |
| Network | HTTPS (port 443) from the host to each PLC. The container uses network_mode: host. |
| Tool | The image wagoalex/wago-plc-mcp-server-fwupdate and the fwupdate/ folder of the repository. |
| Firmware | The files from WAGO: .wup, or a signed .zip for the CC100-IEC62443. |
| Approval | A committed firmware-policy.yaml that names the device IP and the exact revision. |
| Credentials | The WBM user name and password. Use one Docker secret for each device if the passwords differ. |
| Device folder | /tmp/fwupdate on the PLC, with group admin and mode 0770. |
| Minimum build | PFC300: 30. CC100, PFC200 G2, TP600, and Edge Controller: 28. The CC100-IEC62443 has no check. |
| Maintenance window | A stopped machine or process, because the PLC restarts during the update. |
Which firmware file does each device take?
| Device | Firmware file | Revision to approve |
|---|---|---|
| CC100 | CC100-Linux | 4.9.1 |
PFC200 G2, except 0750-8217 | PFC-G2-Linux | 4.9.1 |
PFC200 G2 0750-8217 (modem) | PFC-G2-Linux-red-autoupdate | Modem only4.9.50 |
| PFC300 | PFC-300-Linux | 4.9.1 |
| TP600 and Edge Controller | TP-Linux | 4.9.1 |
| WP400 | WP400-Linux | 4.9.1 |
| CC100-IEC62443 | wago-image-wago-cc100-02.00.13-fw-bundle.zip | Keep zeros02.00.13 |
Both PFC-G2 files list the same article numbers, so the file data cannot identify 0750-8217. The approved revision selects the file.6
How do you run an update?
Diagram structure
- Get firmware files
get-files - Set connection values
set-env - Commit approval
commit - Do a dry run
dry-run - Flash the PLC
flash - Verify audit log
verify commit→dry-rundry-run→flash· passedflash→verify· doneget-files→set-envset-env→commit
- Get firmware files
Copy the
.wupor.zipfiles into thefirmwarefolder. - Set connection values
Copy
_envto.env. SetPLC_IPandPLC_PASSWORD. - Commit approval
Add the IP and the revision to
firmware-policy.yaml. Commit the file. - Do a dry run
Run the tool with
DRY_RUN=true. The tool uploads and checks the file, then cancels. - Flash the PLC
Stop the machine. Run the tool. Wait for
==> Done. - Verify audit log
Run
audit_verify.py. The result must show an intact chain.
yamlapprovals:
192.168.1.10: "4.9.1"bashcp _env .env
docker compose pull
docker compose run --rm -e DRY_RUN=true fwupdate
docker compose run --rm fwupdateTo update all approved PLCs, replace fwupdate with fleet in the last two commands. The tool then updates one PLC after the other.7
Which route should you use?
| Route | Approval | Who runs it | Use it when |
|---|---|---|---|
| Tool by hand | Entry in firmware-policy.yaml | You, on a host in the plant network | No runner is available |
ops/fw-*.yaml file | The merged pull request | CI, at the merge | Best recordFor routine work |
| Run workflow | Entry in firmware-policy.yaml | CI, when you click it | The approval exists and you want to use it now |
The CI routes need a self-hosted runner and the apply.yml and firmware.yml workflows. They also need the FIRMWARE_SOURCE and AUDIT_SYSLOG variables. Without AUDIT_SYSLOG, a CI run leaves no audit record.6
What should you expect during the flash?
- Duration
- 5 to 15 minutes for each PLC. About 20 minutes on the CC100-IEC62443.
- CC100 restart
- Up to 10 minutes.
- Progress
- It stops at about 93%. The status
Unconfirmed (4)is the real signal. - Last line
==> Done.with the status and the new firmware version.
What stops an update?
| Message | Action |
|---|---|
has uncommitted changes | Commit the file. On Windows, also add .gitattributes with *.yaml text eol=lf. |
not listed in the firmware policy | Add the device in a pull request. |
is approved for firmware X, but the resolved bundle is Y | Correct the policy, or the firmware folder. |
bundles match order number | Set TARGET_VERSION to the exact revision. |
Device is already at | No action is necessary. Set FW_ALLOW_REFLASH=true only for an intentional reflash. |
below the minimum | First update to the intermediate build in the message. |
activate failed | Make /tmp/fwupdate on the PLC. Use the command below. |
bashmkdir -p /tmp/fwupdate && chgrp admin /tmp/fwupdate && chmod 770 /tmp/fwupdate