TC-MCP
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
A note from the author
I'm an automation and control engineer with 13 years of experience, mostly on Beckhoff TwinCAT systems. Every line of code in this repository was written by AI, and the project is still an early draft — yet it already writes PLC code that makes me feel outclassed, and it drives TwinCAT 3.1.4026.27 entirely on its own.
My goal is a fully automated programming system that never requires TwinCAT 3 to be opened by hand — the same way I haven't opened Visual Studio in years. I'll let you know when I get there. Until then: enjoy what AI makes possible, before it takes your job.
TC-MCP - TwinCAT 3 knowledge and engineering agent
Public repository: https://github.com/bonnypro/TwinCAT3-MCP
main is the DSH-first line of this repository: DSH workflow, CLI-driven
local-simulation acceptance, waveform and build diagnostics. The original
OpenCode MCP integration lives on the opencode branch, which is the port
target: features finished and verified here are ported there.
TC-MCP is an agent workspace for the whole TwinCAT 3 ecosystem: XAE/XAR, PLC/ST, MC3, NC PTP, NC I, CNC, EtherCAT, drives, ADS, Automation Interface, Scope, HMI, OPC UA/IoT, licensing, TcPkg, and project automation.
The public repository contains code, tests, configuration, documentation, and source-only TwinCAT templates. It does not contain the copyrighted PDF store, extracted PDF text, the SQLite knowledge database, runtime artifacts, or official Beckhoff compiled-library binaries.
<workspace>\
TC-MCP\ # product: MCP servers, automation code, docs, templates
TEST\ # optional local experiments/evidence, not part of the repoTC-MCP is intentionally product-only. Put probes, test clones, generated
runs, screenshots, and other non-MCP work in a sibling TEST folder. The
ignored TC-MCP/runtime directory is disposable execution output and should be
cleaned after acceptance runs.
Current status
F1 knowledge layer: working (official PDFs + SQLite FTS5)
F2 automation layer: working (local UM simulation)
Tests: 263 tests, 16 skipped by default
TwinCAT: 3.1.4026.27
TF5500 MC3: 4.0.19
Python: 3.15+
Node: 26+
ADS target: 127.0.0.1.1.1:851Recently completed:
MC_ExternalSetpointGeneratorreproduces the LoadControl waveform (0 → 1000 → hold 1 s → 0) on an MC3 axis.templates/mc3_minimalis a working minimal MC3 project with JobTask, MC-instance data areas, simulation drive, and full cyclic mapping.tc_write_pousupports real POU methods (methodsarray) instead of stuffingMETHODblocks into the declaration text.License preflight:
python scripts\check_licenses.py.TwinCAT-specific dialogs are suppressed with
TcAutomationSettings.SilentModein addition todte.SuppressUI.tests/test_real_mc3.pyautomates thetemplates/mc3_minimalacceptance: build, activate,MC_Power/IsInControl, trigger the external setpoint generator.Build failures now carry the PLC compiler errors (
file(line) : error: C0046:) from the XAE Build pane, not only MSBuild's generic message.tests/test_real_mc3_waveform.pycaptures the generator,FB_LoadControl, and the axis in one 10 ms PLC buffer and scores the waveform (generator vs LoadControl max 10, mean 0.88; axis vs generator max 4, mean 1.33).tests/test_real_mc3_move.pydrivesMC_MoveAbsoluteon the simulated MC3 axis: target 100, velocity 50,Done,ErrorId=0, no overshoot, final error 0.tests/test_real_mc3_relative.pydrivesMC_MoveRelative+30 then -30: bothDone,ErrorId=0, final error 0, ends at the start position.tests/test_real_mc3_halt.pyhalts an in-flight move withMC_Halt: stops at ~27.8 (trigger 25),ErrorId=0, then returns the axis to 0.tests/test_real_mc3_stop.pyaborts a move withMC_Stop, blocks motion untilExecuteis released, then homes the axis.tests/test_real_mc3_setposition.pyre-zeroes the axis withMC_SetPositionand proves the next absolute move uses the new zero.tests/test_real_mc3_status.pyreads the axis state machine withMC_ReadStatus: standstill → discrete motion → standstill.tests/test_real_ram_upset.pyre-implementsTEST/PMAC/72RamUpset.pmcwithMC_MoveAbsolute+TON(force modelled from penetration) and captures one cycle's position/force curves into CSV/JSON/SVG.tests/test_real_ram_insert.pyports71RamInsert.pmc: absolute move toINSERT_POS, wait inside the in-position window, position curve.tests/test_real_clamp_ram.pyports the stack branch of70ClampRam.pmc: clamp approach, simulated LVDT seat detection withMC_Halt, stack read.tests/test_real_ram_stroke.pyports74RamStroke.pmc: stroke move and arrival window (the closest existing program after missing 69).tests/test_real_mc3_error.pyproves the PLC error path:Jerk := 0surfaces as0x81AB / 33195, thenMC_Resetclears it and a valid move works again.DSH is the primary agent environment; finished features are ported to the
opencodebranch.scripts\tc.ps1is a thin wrapper for doctor / license / test / accept / kb / status, so the common tasks are one command each.
Detailed handoff for the next agent:
docs/HANDOFF_DEEPSEEK.mdRelated MCP server: docpack MCP Server
Quick start
Requirements: Windows, TwinCAT 3 XAE/XAR with standard PLC libraries, Python 3.15+, Node.js 26+, Git, and DeepSeek Harness (DSH).
git clone https://github.com/bonnypro/TwinCAT3-MCP.git TC-MCP
cd TC-MCP
python -m pip install --user -r requirements.txt
python -m unittest discover -s tests -qOr use the thin wrapper for the common tasks:
pwsh scripts\tc.ps1 runtime
pwsh scripts\tc.ps1 test
pwsh scripts\tc.ps1 accept
pwsh scripts\tc.ps1 summary
pwsh scripts\tc.ps1 kb "MC_LoadControl"
pwsh scripts\tc.ps1 licenseDSH is the primary environment: open the workspace and drive the project with
Python directly (python -m app.cli ..., scripts\..., python -m unittest).
The tc-auto / tc-mcp MCP servers remain available for MCP clients but are
not required for DSH work.
tc-mcp starts without a database; run python -m app.cli update once to
download the official PDFs and create data/knowledge.sqlite. That is a large
download and is intentionally not part of the repository.
The OpenCode integration (.opencode/, opencode.jsonc, /tc-* commands)
lives on the opencode branch; it is not part of this tree. Features are
ported there after they are finished and verified on main.
Before any MC3 run, check the local trial/valid license:
python scripts\check_licenses.pyRequired for MC3: TC3 PLC, TC3 ADS, TC3 MC3 Base, TC3 MC3 Axis.
MCP servers
Both servers are product capabilities for MCP clients. DSH drives the project through Python directly and does not require them.
tc-mcp - read-only knowledge
search- search the local Beckhoff PDF knowledge base with citationsget_document- read an indexed documentstatus- counts and last ingest time
The knowledge policy is official Beckhoff PDFs only. No InfoSys HTML crawling, no local reference corpus.
tc-auto - local simulation automation
automation_mcp_server.py is a stdio MCP server with a persistent XAE/ADS
session. It is local-simulation only.
tc_status
tc_revision
tc_list_templates
tc_create
tc_write_pou
tc_write_dut
tc_write_gvl
tc_plc_add_library
tc_plc_list_libraries
tc_project_info
tc_project_tree
tc_archive_export
tc_snapshot
tc_restore
tc_build
tc_activate
tc_verify_symbol
tc_ads_state
tc_ads_read
tc_ads_write
tc_ads_read_many
tc_ads_write_many
tc_ads_wait
tc_list_pous
tc_read_pou
tc_list_symbols
tc_ads_discover
tc_validate_project
tc_test_run
tc_run_loadcontrol
tc_closetc_write_pou accepts an optional methods array:
{
"name": "FB_Derived",
"declaration": "{attribute 'c++_compatible'}\nFUNCTION_BLOCK FB_Derived EXTENDS MC_ExternalSetpointGenerator IMPLEMENTS ITcMcExternalSetpointGenerator",
"methods": [
{
"name": "OnCyclicSetpointGeneration",
"declaration": "METHOD OnCyclicSetpointGeneration : HRESULT\nVAR_INPUT\nEND_VAR",
"implementation": "OnCyclicSetpointGeneration := S_OK;"
}
]
}Methods are written as real <Method> children through
ITcXmlDocument.DocumentXml.
Templates
Template | Purpose |
| Standard minimal TwinCAT PLC project |
| Minimal MC3 axis + simulation drive + external setpoint generator |
| Scope YT chart bindings for LoadControl |
Minimal MC3 axis template
tc_create { name: "mc3-run", template: "templates/mc3_minimal/Minimal.sln" }
tc_build
tc_activate
tc_ads_read { symbol: "MAIN.fbPowerMC3Slave.Status", type: "BOOL" }
tc_ads_read { symbol: "MAIN.Mc3SlaveAxis.McToPlc.Std.IsInControl", type: "BOOL" }
tc_ads_write { symbol: "MAIN.bStartTest", value: "true", type: "BOOL" }
tc_ads_read { symbol: "MAIN.fbActivateMc3ExtSg.Active", type: "BOOL" }
tc_ads_read { symbol: "MAIN.fbGen.rPosition", type: "LREAL" }The template contains:
PlcTask+MJTJobTask +MET+MPTMC-instance
DataAreas(PlcToMc/McToPlc)MC3
Slaveaxis + simulation drivefour cyclic links (
McToPlc^Std/Set/Act,PlcToMc^Std)FB_LoadExtSetpointderived fromMC_ExternalSetpointGeneratorMAINwithMC_PowerandMC_ActivateExternalSetpointGeneration
Observed on this laptop:
build: ok=True, errors=0, warnings=0
activate: ok=True
PLC: RUN (5, 0)
MC_Power: Status=True, ErrorId=0
Axis: IsInControl=True
Generator: bStartTest=True -> Active=True
Position: 492.0(about 0.5 s into the 1000/s ramp)A TcCOM TypeSystem warning about OTCID_PositionEncoder may appear while
loading the MC3 axis description; it does not block build or activation.
Examples
LoadControl simulation
tc_run_loadcontrol creates a fresh project, writes FB_LoadControl + MAIN,
validates ST/PLC XML, builds, verifies TMC symbols, activates local simulation,
commands a 1000 lb setpoint, holds 1 s, releases, and returns an ADS report.
max_actual_lbs: 1000.0
hold_elapsed_s: 1.01
final_actual_lbs: 0.0
complete: true
release_seen: trueThis is a simulated force loop. The laptop has no TF5560 hydraulic package,
no real force sensor, no real actuator, and no safety-rated hardware.
rActualLbs is a deterministic PLC simulation and must not be treated as a
physical pressure test.
MC3 external setpoint
FB_LoadExtSetpoint extends MC_ExternalSetpointGenerator and produces the
same waveform as FB_LoadControl:
0 → 1000(1000/s, 1 s)
1000 hold 1 s
1000 → 0(2000/s, 0.5 s)Measured (451 samples, ~10 ms):
external setpoint vs LoadControl max error: 10.0 (one 10 ms step)
external setpoint vs LoadControl mean error: 0.0347
MC3 axis vs external setpoint max error: 4.0
MC3 axis vs external setpoint mean error: 1.325Full report and evidence:
docs/mc3_external_setpoint.md..\TEST\evolution\mc3_external_setpoint\evidence\
Architecture
automation/core project/task models and DAG
automation/ports XaePort, AdsPort, PlcValidatorPort
automation/adapters dry-run, XAE DTE/COM, pyads, PLC XML validator
automation/services Runner, AutomationSession, licensing
automation/security workspace, simulation, lock, audit, safety-project policy
automation/validation ST review and XML validation
automation/examples LoadControl and MC3 external setpoint sources
automation/evolution self-iteration, trusted evaluation, channels, GC
automation/evaluation hidden task bank, evidence, ADS probe
app/ PDF knowledge CLI
templates/ source-only TwinCAT templatesF1 is the knowledge/MCP layer. F2 adds the automation layer; it is local simulation only and does not touch real hardware, remote targets, or safety projects.
Safety boundaries
tc-autois local simulation only by default.Target platform is
TwinCAT OS (x64)becauseXarModeis UM.ADS uses
127.0.0.1.1.1:851; no remote route or real hardware.Hardware activation is rejected by
ProjectSpecandSafetyPolicy.ADS reads are read-only;
ensure_running()is the only state write.One XAE, one XAR, one ADS session at a time.
Never write to a safety project.
Writes only under
runtime/or..\TEST.Back up
.tsproj,.xti,.plcproj, and source files before manual edits.
Testing
python -m unittest discover -s tests -qExpected: Ran 263 tests ... OK (skipped=16).
Real-XAE integration tests are opt-in, local-simulation only, and need DSH full access because the file sandbox blocks ADS local IPC:
$env:TC_MCP_REAL_XAE='1'
python -m unittest tests.test_real_mc3 -v
python -m unittest tests.test_real_mc3_waveform -v
python -m unittest tests.test_real_mc3_move -v
python -m unittest tests.test_real_mc3_relative -v
python -m unittest tests.test_real_mc3_halt -v
python -m unittest tests.test_real_mc3_stop -v
python -m unittest tests.test_real_mc3_setposition -v
python -m unittest tests.test_real_mc3_status -v
python -m unittest tests.test_real_ram_upset -v
python -m unittest tests.test_real_ram_insert -v
python -m unittest tests.test_real_clamp_ram -v
python -m unittest tests.test_real_ram_stroke -v
python -m unittest tests.test_real_build_diagnostics -v
python -m unittest tests.test_real_xae tests.test_real_session -v
python -m unittest tests.test_real_mc3_error -vOr run all of them, one process per module (recommended; avoids a stale
TcXaeShell COM object leaking into the next test). The script retries a failed
module once and writes TEST/evolution/real_acceptance/latest.json:
python scripts\run_real_acceptance.pytests.test_real_mc3 builds, activates, and exercises templates/mc3_minimal
on PLC 851 (MC_Power, IsInControl, external setpoint generator).
tests.test_real_mc3_waveform composes FB_LoadControl and a 300-sample
waveform buffer into the same project, then compares the external setpoint
generator, the reference FB, and the MC3 axis.
tests.test_real_build_diagnostics compiles a deliberately broken POU and
asserts the PLC compiler error (file, line, C0046) reaches BuildResult.
Run python scripts\check_licenses.py first; the first two need MC3 licenses.
Repository layout
TC-MCP\
app\ PDF knowledge CLI
automation\ F2 automation core, adapters, services, evolution
config\ sources.json, automation.toml, eval/, evolution.toml
docs\ architecture, LoadControl, MC3 report, handoff
scripts\ checks, runners, Scope, evolution, MCP launcher
templates\ minimal, mc3_minimal, scope
tests\ unit tests; real-XAE tests opt-in
automation_mcp_server.py tc-auto
mcp_server.py tc-mcp
AGENTS.md project rules
README.md this fileDocumentation
docs/HANDOFF_DEEPSEEK.md- detailed handoff and backlogdocs/mc3_external_setpoint.md- MC3 external setpoint reportdocs/loadcontrol.md- LoadControl simulationdocs/architecture.md- architecturedocs/ACCEPTANCE.md- what every real acceptance test provesdocs/PORTING.md- how finished features are ported to theopencodebranchdocs/MC3_ERRORS.md- MC3/TwinCAT error codes seen here and their fixesdocs/PITFALLS.md- blocker log, triage order and the regression guards added for each lessondocs/RELEASE_NOTES.md- what eachv0.xtag containsdocs/STATUS_2026-11-05.md- work done today, current runtime blockage and recovery stepsdocs/PUBLISHING.md- publish checklistdocs/evolution/- evolution control-plane notes (historical snapshots)AGENTS.md- project rules and command list
Publishing
git push origin main:mainmain is the DSH release line. The OpenCode tree lives on origin/opencode
and receives ports once a feature is finished here; do not force-push over it.
License
MIT; see LICENSE. Third-party notices are in THIRD_PARTY_NOTICES.md.
PyMuPDF is optional and not distributed; the default parser is pypdf.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only MCP server for the OrchestKit docs: full-text search + Markdown fetch. No auth.
Read-only search and page retrieval from the public Atisbo documentation corpus. No authentication.
Read-only MCP server over the developer docs for the portfolio's JSON API, MCP, A2A and NLWeb.
Search, read, and automate TextMine documents, records, workflows, integrations, and agent tasks.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides local search and git-synced access to Klipper 3D printer documentation.15 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables querying and exploring a bundled knowledge base through tools for manifest, table of contents, node retrieval, and full-text search.24 npm1MIT
- FlicenseNot gradedqualityCmaintenanceProvides local cached access to PaperMC documentation with full-text search, category browsing, and update detection.-
- FlicenseNot gradedqualityCmaintenanceLocal documentation search server for AI models using hybrid retrieval (phrase, keyword, vector). Provides MCP tools to search and fetch documentation from bundled or custom doc sets without any external API keys.-