The CODESYS Installer registers add-on packages (Script Engine included) into
<install>\CODESYS\AdditionalFolders\<InstallationName>\, each with its own
profile.xml reusing the SAME <ProfileName> as the bare base profile. Launching
with --profile alone resolves to the base profile, which on such a box can have
zero plugins registered.
Symptoms this fixes:
- "The command line option 'runscript' has been set. However, there is no
script engine implementation available" -- the watcher never runs, so every
tool fails with "Watcher did not signal ready within 60000ms".
- A load dialog that reads as a contradiction: "created with CODESYS V3.5 SP19
Patch 2 and contains data that cannot be loaded by CODESYS V3.5 SP19
Patch 2". Same profile name, different plugin set.
Observed on this box: three profiles all named "CODESYS V3.5 SP19 Patch 2",
with 0 / 118 / 161 plugins registered. Only the 161 one has the Script Engine.
The Start Menu shortcut the installer generates already passes
--additionalfolder=; the server now can too.
detect.ts ranks every AdditionalFolders\* by registered plugin count and emits
the fullest in --detect / --print-config. Installs without AdditionalFolders are
unaffected and get no flag.
The open_project pre-flight was supposed to prevent this, but it reads
the project's profile from projectinspectiondata.auxiliary inside the
.project ZIP -- and a plain .project is NOT a ZIP. Verified across
3.5.19.20 .. 3.5.22.10: magic 23 89 ED 33, unzip -l fails, no plaintext
profile string. So inspectProjectFile always throws, the pre-flight
catches and proceeds, and the guard is dead code on real projects.
It also only ever covered open_project -- not the release pipeline.
Consequence in the field: a server bound to SP21 Patch 5 opened and
re-saved a 3.5.19.20 vessel project during release_project_version.
4,639,776 -> 4,688,496 bytes, committed and tagged. The tagged binary
stopped being the software on the boat.
Since the version cannot be recovered from the file, pin it in the repo.
New src/version-pin.ts resolves, most specific first:
1. .codesys-version next to the .project (one line, "3.5.19.20" or
"CODESYS V3.5 SP19"; comments and blanks skipped) -- the only
option when seeding a project with no release history
2. library.md's "CODESYS Development System" row -- every project
gets a pin for free after its first release
Policy is asymmetric so it guards the dangerous path without breaking
existing repos: bump_project_version and release_project_version refuse
on mismatch AND on no-pin; get_project_info, mirror_export and
list_project_libraries only warn on mismatch and proceed when unpinned.
Both saving tools accept allowVersionUpgrade: true to override.
Parsing note: library.md's row carries no dotted profile version, so it
is matched on the SP/Patch label only -- a naive version regex would
otherwise bind to the ScriptEngine's 4.2.0.0. Covered by a regression
test.
25 new unit tests; suite 180/180.
Also fixes an unrelated pre-existing test failure: the ASCII-only script
template check used readdirSync without filtering, so a local untracked
src/scripts/__pycache__/ made it fail with EISDIR.
102 tools total. SP21 ScriptEngine functional coverage complete per plan
(SVN/Composer/Cloud deliberately out of scope; plug_module and trace
tools deferred).
Persistent mode now uses a LazyPersistentExecutor everywhere the launcher
is not running: --no-auto-launch before first use, after shutdown_codesys,
and after a launch conflict. The first tool call launches the VISIBLE IDE
and delegates; nothing silently spawns --noUI processes anymore.
Why: headless spawns pop modal dialogs nobody can see (tool calls just
abort), hold .project locks (stale .~u files), and leave orphaned
CODESYS.exe processes that then block the next launch. Diagnosed live on
2026-06-11 while deploying TestN2k_v2_Fable: open_project/download ran
headless via the --no-auto-launch fallback and burned ~30 min on invisible
dialogs, zombie PIDs and lock-file cleanup.
Headless execution now requires explicit opt-in: --mode headless or
--fallback-headless.
Also lands the task-configuration tools from the 2026-06-09 session that
were complete but uncommitted: list_tasks, add_pou_to_task,
remove_pou_from_task (+ their IronPython scripts).
The server is a standard stdio MCP server and works with any MCP client, not
just Claude Code. Added a "Use with OpenAI Codex CLI" section covering the
~/.codex/config.toml location, the [mcp_servers.<name>] TOML table (the
equivalent of the --print-config JSON block), env-based credential injection,
tool_timeout_sec for slow CODESYS launches, and the codex mcp add shortcut.
Linked it from Quick Start step 3.
The phobiCS-tui CLI/UI is retired in favour of driving the codesys-mcp-sp21-plus
MCP tools directly from Claude Code (see https://docs.anthropic.com/claude-code).
The MCP server itself is unchanged; only the TUI front-end goes.
Removed:
- src/tui/ (browser + approve + shared + entry; 14 files)
- dist/tui/ (compiled output)
- tests/tui/ (14 .test.* files + the mini-mirror fixture tree)
- tsconfig.tui.json
- 3 superpowers plans/specs docs (2026-04-28 phobics-tui v0.1-v0.2, 2026-04-29 v0.3-live-values, 2026-04-28 tui-design)
- package.json: phobiCS-tui bin entry, build:tui script, TUI compile step in build, TUI typecheck step
- package.json: dependencies ink + react + diff (TUI-only); devDependencies @types/diff + @types/react + ink-testing-library
- README.md: ## phobiCS-tui section + ### Inline live values subsection
Git history side:
- Worktree .worktrees/phobics-tui removed (was on feature/phobics-tui-followup @ 7e427e9)
- Local + origin branches deleted:
- feature/phobics-tui (was 08ee361, 0 unmerged vs origin/main)
- feature/phobics-tui-followup (was 7e427e9, 0 unmerged vs origin/main)
- feature/phobics-tui-v0.3-live-values (was 9f4dc48, 0 unmerged vs origin/main)
- All three branches were merged into main, so deleting refs loses no history --
the commits remain reachable through main.
Knock-on (deliberately deferred):
- src/approve-gate.ts and the --approve-edits flag in src/bin.ts / src/server.ts
still exist. With the TUI gone, the gate auto-approves at every prompt and
prints a `[approve-gate] No TTY available -- phobiCS-tui cannot render` warning
to stderr. The infrastructure also still has callers in the uncommitted
add_device work, so a clean rip-out is left for a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: disable headless fallback by default
Persistent mode silently fell back to running CODESYS with --noUI
whenever the launch refused (e.g. another GUI instance was already
running). That left the user staring at no window while the MCP
spawned hidden processes per command. Flip the default of
--fallback-headless to false so the MCP errors out loudly instead;
opt in explicitly if silent --noUI is actually wanted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: clear stale lastError on launch retry and successful ready
get_codesys_status kept reporting historical "Last Error: Refusing
to launch..." messages forever because lastError was set on failure
but never reset. Reset to null at the top of launch() so a retry
starts clean, and again when the watcher signals ready so a
successful re-launch wipes prior errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* release: v0.9.2 -- no headless fallback by default + clear stale lastError
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Karstein Phobic Nyvold Kvistad <karstein.kvistad@maritimerobotics.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The line pointed back to phobicdotno/Codesys-MCP-SP21-plus, which is
the URL the visitor is already on when they're reading this on
GitHub. Upstream + npm + maintainer lines give enough provenance for
visitors arriving from npmjs.com or via search.
Documents the v0.3 live-values pump + TUI overlay:
- example output showing the inline '◀ live: <val>' annotations
- 500 ms server poll, 5 s TUI freshness window
- snapshot keyed by pou_name to reject stale POU views
- v0.3 scope: top-level vars only (deferred sub-property + ARRAY/STRUCT)
Updates the phobiCS-tui section to cover the new keybinds (/, o, d,
r, ?, v) and documents that --approve-edits now gates all 9
modifying MCP tools (create_pou, create_property, create_method,
create_dut, create_gvl, create_folder, delete_object, rename_object,
add_library) on top of the existing set_pou_code.
Also notes the Viewer syntax highlighting and the statusbar's
mirror-staleness indicator + small-terminal resize warning.
vitest tests/integration/e2e.test.ts:
- 10 new template-prep assertions, one per Symbol Configuration tool.
Each asserts no leftover {PLACEHOLDER} in the rendered script and
that the relevant CODESYS API method names appear (get_all_signatures,
application.create_symbol_config, configured_access, etc.).
- Drive-by: fix the existing add_library e2e test that was missing the
ALLOW_UNRESOLVED placeholder (added when the resolution gate landed
in d414c77). Test was previously failing on /\{[A-Z_]+\}/ regex.
Suite is now 107/107 green (excluding the orphan .worktrees/phobics-tui
suite that's been failing pre-this-change).
README.md:
- Tool count 31 -> 41.
- New "Symbol Configuration Tools" section under Library Management
with one row per tool.
- Project-structure tool count footnote updated.
docs/function-test-2026-04-28.md:
- Append "Symbol Configuration tools (added 2026-04-28 evening)" block
with a per-tool vitest/live status grid.
- Live SP22 column is deferred: the MCP tool list is negotiated at
Claude Code session start and doesn't refresh mid-session, so the
new tools aren't callable in the session that built them. Document
the round-trip cycle so a fresh session can run it.
- Note the SymbolAccess enum-value probe risk per the plan
(docs/superpowers/plans/2026-04-28-symbol-config-tools.md).
Python 3 ast.parse run against all 10 new + 1 helper scripts -- 11/11
parsed cleanly (catches the obvious IronPython 2.7 syntax issues that
Py3 would also flag).
Documents the new TUI bin and the opt-in approve-edits flag:
- browser invocation (auto-discovery and explicit path)
- approve invocation
- keybindings for both modes
- state file path on Windows vs POSIX, and the get_user_selection
bridge that lets an agent ground its actions in the current
selection
- --approve-edits scope: v0.1 gates only set_pou_code
Both the per-day verification docs and the references to them.
git mv preserves history:
docs/SMOKE-TEST-2026-04-25.md -> docs/FUNCTION-TEST-2026-04-25.md
docs/SMOKE-TEST-2026-04-28.md -> docs/FUNCTION-TEST-2026-04-28.md
Internal H1 + footer line updated to match. README.md and
OPEN-BUGS-CROSS-REFERENCE.md links retargeted.
WHY: connect_to_device and download_to_device against a password-protected
runtime pop a modal "Device User Login" dialog in the IDE. IronPython can't
marshal to the WPF UI thread to dismiss it, so headless / agent-driven
sessions block forever -- and even for interactive use, the dialog pops on
EVERY download, which is a constant friction point.
API: ScriptOnline.set_default_credentials(username, password) was added in
CODESYS scripting API 3.5.3.0. Effect lasts until end of the current script
execution. Source: https://content.helpme-codesys.com/en/ScriptingEngine/ScriptOnline.html
Implementation:
- New helper script src/scripts/register_device_credentials.py defines a
register_device_credentials_if_set() function that no-ops when DEVICE_USER
or DEVICE_PASSWORD is empty, gracefully skips on older SPs that lack
set_default_credentials, and never raises (always falls back to the
current dialog-prompting behaviour).
- connect_to_device.py and download_to_device.py call the helper as the
FIRST action inside their try blocks, before ensure_project_open and
any login() attempt, so credentials are registered before any code path
that could trigger the dialog.
- server.ts adds optional deviceUser / devicePassword args to both tools'
input schemas. Resolution order:
args.deviceUser (per-call override)
-> process.env.CODESYS_DEVICE_USER
-> '' (empty, dialog pops as before)
Same for devicePassword. Env-var path is the recommended config:
claude mcp add -s user codesys-sp22-patch1 \
-e CODESYS_DEVICE_USER=Karstein \
-e CODESYS_DEVICE_PASSWORD=codesys123 \
-- codesys-mcp-sp21-plus --codesys-path ... --codesys-profile ... \
--mode persistent --no-auto-launch
Backward compat: when both creds are empty (default for existing users),
the helper short-circuits and behaviour is byte-identical to 0.5.x. No
regression. Verified by smoke-testing prepareScriptWithHelpers locally
with both filled and empty inputs -- function definition + callsite are
both wired in either case; only set_default_credentials() is suppressed
when empty.
README updated for connect_to_device and download_to_device tool rows.
Version bumped 0.5.0 -> 0.6.0.
WHY: an unlicensed CODESYS Control runtime drops out of demo mode every 2
hours. systemctl is-active reports "active" even after the binary has
died, so a TCP probe on the runtime port (default 11740) is the only
honest liveness signal. The new tool gives MCP a one-call path to bring
the runtime back without dropping into a terminal.
Implementation choices:
- ssh2 (npm) instead of spawning ssh/sshpass: sshpass is not on the
default Windows path, and the target Pi's sshd 10.x rejects pubkey
signatures from this client environment in practice. ssh2 handles
password auth + remote stdin + exit-code capture cross-platform.
- sudo -S with the password fed on remote stdin -- avoids a NOPASSWD
sudoers entry on the PLC.
- After issuing the restart, polls 'ss -tln | grep :<port>' once per
second until the listen port is up or livenessWaitSeconds expires.
This is what catches a half-dead runtime that systemctl reports as
fine.
Defaults match the only Pi we currently target (codesys-pi.local /
karstein / codesys123 / codesyscontrol / port 11740) but every field
is overridable.
Smoke-tested against codesys-pi.local: restart exit 0, port back up
after ~3s.
Before delegating to CODESYS for the actual open, inspect the
.project's projectinspectiondata.auxiliary (via src/inspect.ts -- pure
offline, ZIP+XML, no CODESYS) and compare its saved SP+patch against
the server's configured --codesys-profile.
Three outcomes:
- exact match -> proceed silently
- same SP, different patch -> proceed with a warning prefix in the
response (CODESYS will pop its patch-difference dialog)
- SP mismatch -> refuse without opening; suggest the user either pick
a different MCP server entry or run --print-config --for-project to
generate one for the project's required SP
If inspection itself fails (file missing, malformed .project, profile
unparseable), pre-flight falls through silently -- the existing CODESYS
open path then produces its original error.
Run --print-config with --for-project pointing at a .project file
and the snippet narrows to just the install(s) that can open it
(exact SP+patch match, or fallback to same-SP-different-patch with
a warning about the conversion dialog). No more eyeballing -- the
project's projectinspectiondata.auxiliary tells us which CODESYS
to route to, and --for-project just looks it up.
Mutually exclusive with --sp. Errors are explicit (no install
matches at all, or both flags supplied).
The default mirror root was hard-coded to <projectDir>/mcp-mirror/,
which collides when two .project files live in the same folder
(e.g. \files\...\Multi plc test\ProjectA.project +
ProjectB.project both default to the same mirror -- each
mirror_export call clobbers the other's output).
New resolution rule (preserves backward-compat -- existing setups
unaffected):
- If <projectDir>/mcp-mirror/ already exists, use it
- Else if exactly one .project sibling, use <projectDir>/mcp-mirror/
- Else (multiple .project) use <projectDir>/<basename>_mcp_mirror/
Implemented as src/mirror-paths.ts (TS helper, used by server.ts
maybeOpenMirrorInVscode and unit-testable) plus the same logic
inlined in the Python scripts that need it (mirror_export.py et al.,
no shared-import infra exists CODESYS-side).
New MCP tool + --ssh-version CLI flag. Bypasses the CODESYS IDE
entirely: SSH to a CODESYS Control Linux PLC, sudo strings the boot
application binary, extract the X.Y.Z.W literal of
_MCP_PROJECT_VERSION.sVersion. Filters out 3.5.x.y CODESYS runtime
versions automatically.
Solves the case where the .project file is locked by another CODESYS
instance, or no CODESYS install is reachable, but the PLC is. Read-
only on the PLC (just strings the boot binary).
Requires SSH key auth + passwordless sudo for /usr/bin/strings on
the PLC. Both error paths surface exact-instructions error messages
(PowerShell key install command, sudoers line) instead of opaque
failures.
Smoke-tested against codesys-pi (RPi running CODESYS Control 3.5.22)
with MCPTest2 v1.5.0.0 downloaded -- correctly extracts 1.5.0.0 and
filters out the 3.5.22.0 runtime version literal.
The 75cf74d scaffold added the helpers; this commit makes them
load-bearing by switching every modifying tool's formatToolResponse
call to formatModifyingResponse. Without --auto-mirror, behaviour is
unchanged. With it: mirror_export runs after each successful edit and
'code --add <mirror>' fires once per project to surface the diff in
VSCode's Source Control panel.
Two pieces of doc lag the source had silently outpaced:
1. The embedded --print-config sample showed the old caveat ('only ONE
can be active at a time') even though the runtime output (in
src/detect.ts) was already updated to the post-0.4.8 wording about
multi-install coexistence. Sync the README sample.
2. The 'Reliability fixes' bullet for the launcher still described the
pre-0.4.8 behaviour (refuses ANY CODESYS.exe). Updated to the
path-filtered version. Also drop the git_* project.save() bullet --
those tools were removed in 5be20a6.
The CODESYS Git plugin wrappers (git_init, git_status, git_commit,
git_remote_add, git_branch_set_upstream_to, git_push) operated on the
binary .project file via CODESYS's IDE-side Git plugin. Drawbacks:
- Required a CODESYS Professional Developer Edition subscription
(HasGitLicense gate). Anyone without PDE got a fail-fast error on
every call -- the tools were dead weight for most users.
- Operated on a separate dual-storage repo (the .project stayed put,
the git repo lived in a sibling directory). Diffs were unreadable
because they're binary serialisations, not source text.
- Couldn't run on UNC paths -- the plugin rejected them.
- Duplicated functionality release_project_version already provides
via the system git binary against the source-mirror tree (which IS
human-readable diff-able .st files).
Removing all 6 tools, all 6 .py templates, and the README section.
Tool count drops 37 -> 31. release_project_version remains the
recommended path for CODESYS-project version control: mirror_export
gives you readable diffs in mcp-mirror/, then standard git commits
+ tags + push, no PDE license required.
Per https://docs.npmjs.com/cli/v11/using-npm/scripts, since npm@7 the
preinstall/install/postinstall scripts run in the background with stdout
AND stderr captured. The only way to surface them is the
`--foreground-scripts` opt-in flag (default false). Three failed
publish cycles (0.4.4, 0.4.5, 0.4.6) couldn't get around this -- the
limitation is by design, not a bug.
Removing src/postinstall.ts and the postinstall script entry from
package.json. The functionality (printing the .mcp.json snippet) is
still available -- it just runs on demand via:
codesys-mcp-sp21-plus --print-config
Updated the README Quick Start to a numbered 4-step flow:
1. npm install -g codesys-mcp-sp21-plus
2. codesys-mcp-sp21-plus --print-config
3. paste into project- or user-scoped .mcp.json
4. restart Claude Code
Plus a footnote explaining why no banner -- so a future maintainer
doesn't try to re-add postinstall and waste another publish cycle.
New flags:
- --print-config: scan installs and emit a JSON block per install with
derived server names (codesys-sp21-patch5, codesys-sp22-patch1, etc.)
- --sp <n>: filter to one SP family; collapses entry name to 'codesys'
when exactly one install matches
- --name <name>: override the entry name (only valid with --sp narrowing
to one)
Side effect: --detect now reuses the same detector and additionally
prints the derived profile name + suggested server entry name per
install, so even users sticking to manual config get the values
without guessing.
Refactored install discovery into src/detect.ts so both --detect and
--print-config share one implementation. New unit test fixture covers
version parsing, missing-exe, dedup, sort order, --sp filter behaviour,
--name override constraints, and verifies the emitted JSON parses back
once // comments are stripped.
The output also surfaces the multi-install caveat from launcher.ts:
the double-spawn guard refuses to start a second CODESYS.exe even on
a different exe path, so only one configured entry can be active at
a time.
- Lead with a clear "this is a fork" callout (upstream link, fork link, npm link, maintainer)
- New "What's new in this fork" section grouping all changes:
* Compatibility fixes (SP21+ watcher rewrite, KeyboardInterrupt cancel hardening)
* Upstream tool fixes (create_folder, compile JSON long, connect_to_device LoginMode + auto-login, ensure_project_open switch, set_pou_code wipe, add_library, list_project_libraries)
* New tools (mirror_export, bump_project_version, release_project_version, read_running_version_online, git_remote_add, git_branch_set_upstream_to, git_push)
* Reliability fixes (launcher refuses double-spawn, shutdown kills orphans, git_* persists via project.save)
- Promote npm install to the top of the install section; source install now follows
- MCP Tools tables now mark each tool as **NEW** or **FIXED** so readers can scan what came from this fork
The 'sp21-plus-migration-notes' branch name was shown in code-style
but not linked. Made it a hyperlink to
https://github.com/phobicdotno/Codesys-MCP-SP21-plus/tree/sp21-plus-migration-notes
so a reader landing on the README can click straight through to the
live source state without first navigating to the repo root.
Also added a sibling sentence pointing at the published npm registry
page (https://www.npmjs.com/package/codesys-mcp-sp21-plus) so the
About blurb now exposes the three canonical landing pages: upstream,
fork repo (+ branch), and npm.
Reader feedback: the install line 'npm install -g codesys-mcp-sp21-plus'
didn't make clear that the npm package IS this fork (rather than some
unrelated package or the upstream luke-harriman/Codesys-MCP).
Changes to the Installation section:
- Lead paragraph now states explicitly that the fork is published as
'codesys-mcp-sp21-plus' by phobic, and that this is this fork (not
upstream, not a Python package).
- 'npm install -g' command moved into a clear 'Install the fork from
npm' subsection with a bullet list explaining what -g does, where
the binary lands on PATH, and which deps come along for the ride.
- Added two verification commands (--version, --detect) so a first-time
user has an obvious next step after install.
- Added an upgrade command ('npm install -g codesys-mcp-sp21-plus@latest')
so the post-install workflow is fully documented.
- 'From source' subsection retitled 'Install the fork from source' for
parallel structure.
Package is live on the npm registry as of 2026-04-26 (version 0.4.0,
maintainer phobic). The bare-name install line that was previously
warned-against now actually works, so it's the leading install path
again. The git-clone workflow is demoted to a 'From source' subsection
for users who want to track sp21-plus-migration-notes directly,
contribute patches, or run a specific commit.
Verified live:
npm view codesys-mcp-sp21-plus version -> 0.4.0
User feedback: don't lead with npm registry concepts when the fork
isn't published. Replaced the three-option list (with the misleading
'not currently published' caveat) with a clean two-step git-clone
workflow:
1. git clone + npm install + npm run build (mandatory)
2. wire into .mcp.json via either:
A) command: 'node', args: ['<path>/dist/bin.js', ...]
(simplest -- no global state)
B) command: 'codesys-mcp-sp21-plus' after running 'npm link'
(only useful if you also want the bin on PATH for ad-hoc use)
Plus a short 'Updating' section that documents what to pull / rebuild
when the upstream branch advances.
Removed entirely:
- 'Option 1: npm install -g github:phobicdotno/...' (still works, but
drowns the simpler path)
- The 'Heads-up on npm install -g codesys-mcp-sp21-plus' caveat
paragraph (the new section doesn't mention the registry name at all,
so the warning has no premise)
Three explicit install paths replacing the misleading 'npm install -g codesys-mcp-sp21-plus' top-line (the fork is not published to npm; bare-name install would fail with 404):
1. npm install -g github:phobicdotno/Codesys-MCP-SP21-plus
-- installs directly from this repo, recommended for end users
2. git clone + npm install + npm run build + npm link
-- recommended for development; lets src/ edits take effect after a
build, and Python script edits hot-reload from dist/scripts/ without
one
3. git clone + npm install + npm run build, then node dist/bin.js
-- avoids touching global node_modules; full .mcp.json snippet shown
Also clarifies up-front that this is a Node/npm package, not a Python
package -- the .py files under src/scripts/ are CODESYS IronPython
templates bundled into the npm distribution, not a pypi project. There
is no pip install. Requirements section now lists the supported CODESYS
versions explicitly (SP19 / SP21 3.5.21.x / SP22 3.5.22.x) and notes
the PDE subscription gate on the git_* tools.
Project rename. The 'SP21+' identifier is more accurate than the
previous 'SP22+' label -- this fork specifically carries the SP21+
migration fixes (the upstream's system.execute_on_primary_thread()
removal and downstream API drift), and is forward-compat with later
SPs. The repo on GitHub has been renamed to
phobicdotno/Codesys-MCP-SP21-plus accordingly.
Substitutions (UTF-8 preserved this time -- prior PowerShell pass
mangled em-dashes via a Win-1252 round-trip):
- package.json: name codesys-mcp-sp22-plus -> codesys-mcp-sp21-plus,
bin entry, repository.url, homepage, description, author trailer
- README.md: title, banner, install + clone snippets, CLI invocations
- ARCHITECTURE.md: comparison-table column header + temp-dir prefix
- tests/TEST_OVERVIEW.md: title
- src/bin.ts: header comment + program().name()
- src/launcher.ts: SESSION_DIR_PREFIX
- src/types.ts: header comment
Compatibility phrase 'Works on SP19, SP21, and SP22+' and the technical
identifier 'SP22 Patch 1 fixes' (which name the actual CODESYS version)
were preserved -- those refer to CODESYS, not the project name.
README additions:
- Quick Start example switched from SP21 Patch 3 to SP22 Patch 1 to
match the more common modern install
- New 'Multiple CODESYS installations' subsection with worked
side-by-side example for SP21 (3.5.21.50) and SP22 (3.5.22.10) --
one named MCP server entry per install, called by name from Claude.
Documents the constraint that --codesys-path/--codesys-profile are
bound at server startup, that --detect lists installs, and that
config edits require a Claude Code restart
- Tool count corrected from 28 -> 37 in the Features bullets
- New Tools sections covering 10 previously-undocumented tools:
Version Anchor + Release Pipeline (bump_project_version,
release_project_version, read_running_version_online), Source
Mirror (mirror_export), and CODESYS Git PDE-gated (git_init,
git_status, git_commit, git_remote_add, git_branch_set_upstream_to,
git_push). Each row carries the actual operational gotchas
discovered during this session (UNC localRepoPath rejection,
push-without-upstream failure, optimizer stripping unreferenced
globals from the online symbol table, etc.)
- list_project_libraries + add_library row text updated to reflect
the post-fix behaviour (compiler-version capture; managed-overload
preference + resolution gate)
Local origin URL updated: phobicdotno/Codesys-MCP -> phobicdotno/Codesys-MCP-SP21-plus.
37/37 tests green.
Project identity rename. Concrete changes:
- package.json
- name: codesys-mcp-persistent -> codesys-mcp-sp22-plus (npm-safe;
'+' is not allowed in npm package names)
- description: prepended 'Codesys-MCP-SP22+' branding + brief
summary of the SP22+ fixes carried in this fork
- bin entry: codesys-mcp-persistent -> codesys-mcp-sp22-plus
- repository.url + homepage: now point at
github.com/phobicdotno/Codesys-MCP-SP22-plus (using -plus
spelling on the URL side; '+' would require URL-encoding)
- author: noted upstream + SP22+ fork attribution
- README.md: title + about-this-fork blurb + clone instructions
- tests/TEST_OVERVIEW.md: title
- ARCHITECTURE.md: comparison-table column header + temp-dir path
- src/bin.ts: file header + program().name()
- src/launcher.ts: SESSION_DIR_PREFIX (with note on backwards compat)
- src/types.ts: file header
Display name everywhere: 'Codesys-MCP-SP22+'.
npm package name: 'codesys-mcp-sp22-plus'.
Out of scope for this commit -- need user action:
- Local directory rename (C:/Users/karstein.kvistad/Codesys-MCP ->
...-SP22+) cannot be done while the persistent MCP is using dist/
from the current path; user can rename after shutting down VS Code.
- GitHub repo rename (phobicdotno/Codesys-MCP -> ...-SP22-plus or
...-SP22+) needs the github.com web UI; the package.json URLs
already point at the post-rename name so a 'git remote set-url
origin <new>' lines up after.
- MCP client config in .mcp.json or similar: the bin name changed
from 'codesys-mcp-persistent' to 'codesys-mcp-sp22-plus' -- update
any 'command' field that referenced the old name. (Local sessions
invoking node dist/bin.js directly are unaffected.)
37/37 tests still green after rename.
Prepended a blockquote section above the existing title that:
- Identifies this as a fork of luke-harriman/Codesys-MCP, links to both
upstream and the phobicdotno mirror.
- Explains why the fork exists (SP21+/SP22 removal of
system.execute_on_primary_thread() made upstream unusable on current
CODESYS releases).
- Summarises the two substantive fixes carried on this branch:
* SP21+/SP22 watcher rewrite (single-thread, primary)
* KeyboardInterrupt hardening so the CODESYS Cancel link no longer
pops the modal traceback dialog
- Links to docs/MIGRATION-SP21-PLUS.md and docs/SMOKE-TEST-2026-04-25.md
for the rationale and the per-tool verification results.
Original README content is unchanged below the notice.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.3.0 returning-watcher architecture — background thread polls for commands
and marshals execution onto the CODESYS UI thread, keeping the IDE fully
responsive between operations. File-based IPC with atomic writes, async mutex
command serialization, headless fallback, and 35 passing tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>