tcgen-st-test-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tcgen-st-test-mcpNormalize my review ST and run the tests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
tcgen-st-test-mcp
Offline semantic validation for TcGen Structured Text review bundles.
This MCP server accepts inline TcGen review-ST sources, normalizes the supported
subset into STruC++-compatible ST, builds either JSON-spec tests or TcGen
framework-style tests, and runs them through the strucpp CLI in a temporary
workspace.
Passing results mean only:
Offline semantic test passed for the normalized STruC++ model. Final TwinCAT compilation or target validation may still be required for vendor libraries, task behavior, I/O, ADS, motion, lifecycle methods, and runtime-specific behavior.
Every source-processing request must set candidateSourcePath to the exact
sources[].path of the staged candidate. Exactly one source must match. Reports
bind that candidate to the result through:
{
"subject": {
"candidateSourcePath": "cut.st",
"candidateSha256": "...",
"dependencyBundleSha256": "...",
"discoveredFrameworkTests": ["FB_Test_LimitCounter"],
"selectedFrameworkTests": ["FB_Test_LimitCounter"]
}
}Semantic generation and run results use report schema v2. The execution contract adds explicit coverage and generated-test identity alongside the candidate/dependency hashes:
{
"schemaVersion": 2,
"testMode": "generated",
"coveredExecutableObjects": ["FB_Adder"],
"generatedTestNames": ["adds two integers"],
"hashes": {
"testSource": "..."
}
}testMode is generated for JSON testSpec requests and framework for
TcGen framework requests. Generated coverage names the declared target POU.
Framework coverage names only the concrete FB_Test_* blocks executed by the
offline wrappers; it does not infer production-object coverage. The legacy v1
run contract remains published as
schemas/semantic-report-v1.schema.json.
The candidate hash covers its exact UTF-8 content. The dependency hash covers
JSON.stringify of the remaining {path, content} entries sorted ordinally by
path and then content, so source-array ordering cannot change the identity.
The packaged
schemas/dependency-bundle-hash-vectors.json
contract publishes exact canonical JSON and lowercase SHA-256 vectors for
cross-language implementations, including JavaScript-specific escaping and
UTF-8 behavior.
For tcgen_st_test_run, scope may narrow dependencies but cannot exclude any
object parsed from candidateSourcePath. The run report's
normalization.includedObjects lists only objects actually emitted into the
compiled source; candidate objects excluded by scope or normalization block the
run.
Tools
tcgen_st_backend_checktcgen_st_normalizetcgen_st_test_generatetcgen_st_test_run
Related MCP server: codeviewer-mcp
CLI
tcgen-st-test backend-check
tcgen-st-test normalize request.json
tcgen-st-test generate request.json
tcgen-st-test run request.jsonTest Modes
tcgen_st_test_generate and tcgen_st_test_run accept exactly one test
authority:
testSpec: the original JSON step format, converted into STruC++TESTblocks.frameworkTest: TcGen/TwinCAT-style ST tests where the request sources include the CUT plus concreteFB_Test_* EXTENDS FB_TestCaseBaseblocks.
When options.includeArtifacts is true, run reports include the generated ST
in artifacts.generatedTestFile even when preflight blocks execution. Compiler
stdout, stderr, diagnostics, and assertion messages have terminal control
sequences removed and temporary workspace roots replaced with <workspace>.
Non-passing compiler/runtime output is also promoted into structured report
diagnostics so consumers do not need to relay raw artifact streams. An exit-0
backend result with no parsed tests is rejected as backend_error.
Every testSpec.tests[].name must be unique ignoring case and surrounding
whitespace. Duplicate names block generation and execution because result
evidence must identify each generated test unambiguously.
Framework mode uses:
{
"frameworkTest": {
"mode": "tcgen-test-framework",
"executionContract": "tcgen-framework-multiscan-v1",
"testFunctionBlocks": ["FB_Test_LimitCounter"],
"targetMappings": [
{
"testFunctionBlock": "FB_Test_LimitCounter",
"productionTarget": "FB_LimitCounter",
"testSourcePath": "test.st",
"testSourceSha256": "<lowercase SHA-256 of the exact test.st content>"
}
],
"maxScans": 200
}
}When testFunctionBlocks is present it must name every discovered submitted
framework test. To focus a run, submit only the relevant test sources rather
than selecting an arbitrary passing subset. Reports expose both
discoveredFrameworkTests and selectedFrameworkTests for independent checks.
targetMappings is mandatory and one-to-one. Every selected FB_Test_* and
every executable object in candidateSourcePath must be represented exactly
once. The MCP verifies the exact source path and UTF-8 content SHA-256, confirms
that the test source instantiates or references the production target outside
comments and strings, and requires at least one m_xAssert* call over an
observed value rather than a literal-only smoke assertion. Framework runner
registration programs and framework infrastructure are not production targets.
Generation keeps the submitted TwinCAT framework ST byte-for-byte in
testFile and frameworkTestFiles. The separately generated STruC++ execution
adapter is returned in generatedTestFile; hashes.testSource identifies that
adapter, while each framework source retains its own trusted mapping hash.
Both generate and run responses also expose artifactIdentities[]. Canonical
submitted sources use role: "framework_st", visibility: "review", while the
separate adapter uses role: "execution_adapter",
visibility: "technical". Each identity includes a stable artifact ID, path,
content SHA-256, UTF-8 byte length, and primary flag; consumers must select the
reviewable source by role rather than by the legacy field name.
Semantic report v2 publishes the verified identities and structural evidence in
frameworkTargetCoverage[] (assertionCount, targetReferenceCount, and
verified). Generate and run tool metadata advertise the
frameworkTargetCoverageV1, frameworkMultiScanV1,
twinCatShortCircuitOperatorsV1, twinCatBistableAliasesV1,
frameworkAssertionLedgerV1, frameworkAssertionProgressV1,
frameworkLifecycleV1, frameworkArtifactRolesV1,
frameworkAssertionRunningProgressV1, and (on
tcgen_st_test_run)
candidateCompilePreflightV1 capabilities. The candidate-preflight capability
means the trusted scheduler can compile the exact candidate and dependency
bundle with a deterministic internal smoke specification before spending a
model call on Framework ST design. The short-circuit capability
requires the pinned STruC++ distribution to compile TwinCAT AND_THEN and
OR_ELSE natively with lazy right-hand-side evaluation; the MCP never rewrites
them to eager operators. The
required tcgen-framework-multiscan-v1 contract calls m_xExecute(TRUE) once,
then calls m_xExecute(FALSE) once per offline PLC scan while m_xIsBusy()
remains true. The offline task interval is deterministic: each resumed scan is
preceded by ADVANCE_TIME(1000000) (one millisecond), allowing IEC timers to
progress without introducing STruC++ syntax into the submitted Beckhoff ST.
Synchronous tests that finish on the initial call remain valid. Successful
terminal paths set both _eState and _eExecuteState to Passed and clear
_xPhaseBusy. A multi-scan test declares udiStep : UDINT, advances through
CASE udiStep OF on FALSE-trigger calls only while both inherited states remain
Running, and clears _xPhaseBusy on success and failure. Its m_xIsBusy()
implementation is the side-effect-free _xPhaseBusy observer. The private
adapter independently asserts the final ST_TestCaseResult states and counters.
The additive assertions[] field identifies every meaningful submitted
m_xAssert* call by source path, source SHA-256, one-based line, mapped target,
stable assertionId, and stable checkpoint identity. Generation reports use
status: "not_run". The private offline adapter records every dynamic assertion
invocation in a bounded ledger and emits one independent checkpoint per source
assertion. A single STruC++ invocation therefore returns complete passed,
failed, or not_reached evidence without changing the submitted Framework ST.
The parent wrapper and every checkpoint execute a fresh test-FB/CUT instance;
checkpoint tests never query assertion state left behind by another TEST.
The adapter binds runtime rows to stable assertion IDs rather than treating the
human-readable assertion message as identity. Reached rows include start and
completion timestamps, and unreached rows are explicit rather than inferred as
passing.
Request-bound progress emits queued, running, and completed checkpoint
phases with the canonical Framework source line so a client can highlight the
currently executing assertion without displaying the execution adapter.
assertionLedger reports the stable ledger hash, completeness, and counts while
the legacy first-error result remains available. Report v1 remains unchanged.
In framework mode the MCP normalizes the CUT and agent-authored test FBs and
replaces uploaded framework infrastructure such as FB_TestRunner,
I_TestCase, FB_TestCaseBase, and GVL_TestResults with a compact
STruC++-compatible shim. A PROGRAM containing both FB_TestRunner and
m_udiRegisterTest is structurally recognized as runner registration and
rewritten to a compiled offline registration surrogate; ordinary production
PROGRAM MAIN objects remain unchanged. Generated wrapper TEST blocks then
execute every concrete FB_Test_* instance. A failing assertion is returned as
verdict: "failed" with a human-readable aggregate in tests[].message and the
exact per-assertion cause in assertions[] and assertionLedger.
Semantic report v2 also exposes backend.executionAttempted, distinguishing a
normalization/preflight rejection from an invocation that reached STruC++.
backend.standardFunctionBlockContracts is loaded from the compiler-generated
libs/iec-function-block-contracts.json sidecar. Preflight validates the
sidecar schema, library/contract versions, its canonical payload byte count and
SHA-256, every machine-readable pin signature and alias collision, and the RS/SR
TwinCAT pin order and dominance semantics. The installed runtime manifest must
contain and hash this sidecar; a missing, altered, or incompatible contract
fails closed. A compiler rejection of an admitted
TwinCAT pin is reported as backend_incompatibility, never as a candidate bug.
The stdio server runs independent tool requests concurrently so Virtual Tests for parallel workers are not serialized by the MCP transport. Callers that send an MCP progress token receive request-bound phase notifications. MCP cancellation notifications abort the matching active semantic child process; progress tokens, grants, and authorization data are never forwarded to backend children. Assertion completion notifications are emitted as backend result lines arrive; the authoritative report remains the final complete ledger.
Local Development
Use Node.js 22 or later.
npm ci
npm run build
npm run bundle
npm run build:exenpm run bundle produces the self-contained Node.js 22 MCP runtime at
dist/tcgen-st-test-mcp.cjs. It includes runtime dependencies and can be copied
into the TcGen product pack without node_modules or a sibling checkout.
npm run build:exe additionally produces
dist/tcgen-st-test-mcp.exe, a Windows x64 executable containing its own
Node.js 22 runtime. The product launcher should use this executable; the CJS
bundle remains useful for npm and source-development workflows.
For local development against a sibling STruC++ checkout:
git clone https://github.com/AgileAutomationTechnologies/STruCpp.git C:\Users\fboid\source\python\STruCpp
cd C:\Users\fboid\source\python\STruCpp
git checkout development
$env:STRUCPP_PATH = "C:\Users\fboid\source\python\STruCpp"
$env:STRUCPP_GPP_PATH = "C:\msys64\ucrt64\bin\g++.exe"STRUCPP_PATH may point to a strucpp executable, dist/node/cli.js, or the
STruC++ repository root. STRUCPP_GPP_PATH is optional for backend checks, but
tcgen_st_test_run needs a working g++ for STruC++ --test execution.
Inside the standalone MCP executable, a repository/JavaScript STruC++ path also
requires a real external Node executable through TCGEN_ST_NODE_PATH or PATH;
the packaged MCP refuses to recursively use itself as Node. Prefer native
strucpp-win.exe in product installations, which needs no external Node.
The v0.8.6 Windows validation target is the AgileAutomationTechnologies STruC++
downstream release at commit 8b8d07542a3ece531fe7e66c900a08549036aa01,
based on upstream STruC++ 0.5.13 plus the qualified TcGen downstream patch set,
identified as 0.5.13-tcgen.6.
Backend checks and semantic runs fail closed when the detected STruC++ version
is missing or differs from the complete 0.5.13-tcgen.6 distribution version.
Verification
npm run verify
npm run verify:native
npm run fixtures
npm run smoke:mcp
npm run pack:checkRelease automation can export a deterministic, complete Framework assertion report contract after building the package:
npm run export:semantic-report-contract -- C:\temp\mcp-0.8.6-framework-assertion-report.jsonThe exported JSON contains the current mcpVersion and intentionally omits
mcpCommit. The release orchestrator must inject the immutable commit from the
published MCP revision rather than asking the exporter to infer it from a
possibly dirty working tree.
Native verification expects:
$env:STRUCPP_PATH = "C:\Users\fboid\source\python\STruCpp"
$env:STRUCPP_GPP_PATH = "C:\msys64\ucrt64\bin\g++.exe"Reference STruC++ checks:
cd C:\Users\fboid\source\python\STruCpp
npm run build
npm run typecheck
node dist\node\cli.js --version
node dist\node\cli.js tests\st-validation\function_blocks\fb_accumulator.st --gpp C:\msys64\ucrt64\bin\g++.exe --test tests\st-validation\function_blocks\test_fb_accumulator.st
node dist\node\cli.js tests\st-validation\function_blocks\basic_fb.st --no-default-libs --gpp C:\msys64\ucrt64\bin\g++.exe --test tests\st-validation\function_blocks\test_basic_fb.stWorkspace Retention
Temporary workspaces are deleted by default. keepWorkspace only returns a
workspace path when both are true:
the request sets
options.keepWorkspace = true;the local environment sets
TCGEN_ST_ALLOW_KEEP_WORKSPACE=true.
Without that environment flag, keepWorkspace is ignored and a non-blocking
SANDBOX_KEEP_WORKSPACE_DISABLED diagnostic is returned.
Known STruC++ Limitation
The upstream basic_fb sample declares Toggle, while bundled OSCAT libraries
also define TOGGLE. Run that sample with --no-default-libs; use
fb_accumulator as the default-library native smoke until library shadowing is
handled upstream.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgileAutomationTechnologies/tcgen-st-test-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server