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.
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.
Runs after `npm install -g codesys-mcp-sp21-plus`. Detects every
CODESYS install on PATH and prints the ready-to-paste .mcp.json
block per install (same output as `--print-config`).
Guards:
- Skipped during local installs / dev clones (npm_config_global != true)
- Skipped in CI (CI=true or npm_config_ci=true)
- Wrapped in try/catch + 'node ... || true' so a banner failure never
blocks the install
- Non-Windows: prints a note and exits cleanly
- Zero CODESYS installs: prints a hint pointing at --print-config
Resolves the awkward 'now run these two commands to verify and get
your config' step from the README.
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.
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>