Skip to main content

ControlForge MCP Server Guide

James M. Belcher Founder, JMB Technical Services LLC April 2026 | ControlForge v1.0.540


1. Overview

ControlForge includes a built-in MCP (Model Context Protocol) server that gives AI assistants like Claude Code, Cursor, Windsurf, and other MCP-compatible tools direct access to all PLC functionality. With 80 tools covering programs, tasks, variables, HMI, debugging, protocol analysis, fleet management, and more — an AI assistant can build, deploy, and debug complete PLC applications without touching the IDE.

The MCP server is built into the ControlForge binary. No external dependencies, no separate installation, no Node.js required.

What Can an AI Do With These Tools?

CapabilityTools Used
Learn the systemcontrolforge_coding_rules, controlforge_capabilities, controlforge_guide_search, controlforge_functions
Write and validate ST codecontrolforge_functions (verify), controlforge_program_validate, controlforge_program_create
Deploy programscontrolforge_deploy (one-call), or controlforge_program_createcontrolforge_task_set_programscontrolforge_task_reload
Build HMI dashboardscontrolforge_hmi_template, controlforge_hmi_create, controlforge_hmi_update
Monitor variablescontrolforge_variable_list, controlforge_variable_get, controlforge_variable_set, controlforge_watch_create
Debug programscontrolforge_debug_enable, controlforge_debug_set_breakpoint, controlforge_debug_step_over
Analyze protocolscontrolforge_analyzer_start, controlforge_analyzer_transactions, controlforge_analyzer_decode
Manage fleetcontrolforge_fleet_discover, controlforge_fleet_list
Configure the systemcontrolforge_config_get, controlforge_config_update, controlforge_nodered_status

2. Quick Start

2.1 Start ControlForge

./controlforge project.goplc --api-port 8082

2.2 Add the MCP Server to Claude Code

claude mcp add controlforge -- /path/to/controlforge mcp

That's it. Next time you start Claude Code, all 80 tools will be available. The MCP server connects to your running ControlForge instance over HTTP.

2.3 Add to Other MCP Clients

For any MCP-compatible client, configure a stdio transport:

{
"mcpServers": {
"controlforge": {
"command": "/path/to/controlforge",
"args": ["mcp"]
}
}
}

2.4 Authentication

If your ControlForge instance has JWT authentication enabled, set the token as an environment variable:

export CONTROLFORGE_AUTH_TOKEN="your-jwt-token-here"

The MCP server reads CONTROLFORGE_AUTH_TOKEN at runtime and includes it as a Bearer header on every request.


3. How It Works

The MCP server uses JSON-RPC 2.0 over stdio. It acts as a lightweight HTTP client — translating MCP tool calls into REST API requests against a running ControlForge instance.

Every tool accepts host and port parameters, so a single MCP session can manage multiple ControlForge instances. The host parameter supports shorthand: "45" expands to "10.0.0.45".


4. Complete Tool Reference

4.1 Documentation & Learning (5 tools)

ToolDescription
controlforge_coding_rulesRead this first. Mandatory ST coding rules — function verification, code style, GVL patterns, common mistakes. No parameters needed.
controlforge_capabilitiesSupported IEC 61131-3 features, data types, and limits
controlforge_functionsSearch available ST functions by name or category. Authoritative source — if a function isn't returned here, it doesn't exist. Supports search, category, limit, names_only filters.
controlforge_function_blocksList all function blocks (TON, TOF, CTU, PID, etc.) — stateful blocks requiring instance variables
controlforge_guide_searchProgramming guides — GVL, cross-task communication, hardware I/O patterns

Example: Search for Modbus functions

controlforge_functions(host="localhost", port=8082, search="modbus", limit=10)

4.2 Programs (7 tools)

ToolDescription
controlforge_program_listList all programs
controlforge_program_getGet source code and metadata for a program
controlforge_program_createCreate a new program or GVL
controlforge_program_updateUpdate an existing program's source
controlforge_program_deleteDelete a program
controlforge_program_validateValidate ST source without saving — catches syntax errors before deploy
controlforge_deployOne-call deploy — validates, creates programs, assigns to task, and reloads. Collects all errors so you can fix them in one pass.

Example: Deploy a temperature controller

controlforge_deploy(
host="localhost", port=8082,
task="MainTask",
programs=[
{name: "GVL_Temp", source: "VAR_GLOBAL (GVL_Temp)\n temp : REAL := 22.5;\n setpoint : REAL := 25.0;\nEND_VAR"},
{name: "POU_TempCtrl", source: "PROGRAM POU_TempCtrl\nVAR\n error : REAL;\nEND_VAR\n error := GVL_Temp.setpoint - GVL_Temp.temp;\nEND_PROGRAM"}
]
)

4.3 Tasks (8 tools)

ToolDescription
controlforge_task_listList all tasks with scan times, programs, and stats
controlforge_task_getGet task details (config + runtime state)
controlforge_task_createCreate a new task (cyclic execution container)
controlforge_task_updateUpdate scan time, priority, or watchdog settings
controlforge_task_set_programsSet which programs/GVLs run in a task
controlforge_task_reloadHot-reload a single task without stopping others
controlforge_task_startStart a specific task
controlforge_task_stopStop a specific task

4.4 Variables (5 tools)

ToolDescription
controlforge_variable_listList all variables with current values
controlforge_variable_getRead a single variable by name
controlforge_variable_setWrite a value to a variable
controlforge_variable_bulk_getRead multiple variables in one call
controlforge_tag_listList I/O tags (driver-mapped variables)

4.5 HMI Pages (6 tools)

ToolDescription
controlforge_hmi_templateGet a starter HTML template with controlforge-hmi.js wired up
controlforge_hmi_listList all HMI pages
controlforge_hmi_getGet a page's HTML source
controlforge_hmi_createCreate a new HMI page (served at /hmi/<name>)
controlforge_hmi_updateUpdate a page's HTML
controlforge_hmi_deleteDelete a page

HMI pages are full HTML documents that use the controlforge-hmi.js helper library:

// Include in your HMI page
<script src="/hmi/controlforge-hmi.js"></script>

// Read/write variables
controlforge.read("GVL_IO.temperature")
controlforge.write("GVL_IO.setpoint", 25.0)

// Poll all variables every 500ms
controlforge.subscribe(function(vars) {
// vars = { "program.varname": { value: ..., type: "..." }, ... }
}, 500)

// Poll specific variables
controlforge.subscribeTo(["GVL_IO.temp", "GVL_IO.pressure"], callback, 500)

// WebSocket for real-time updates
controlforge.connect(function(data) { /* real-time push */ })

// System info
controlforge.info() // version, platform, etc.
controlforge.runtime() // state, uptime, scan time

4.6 Runtime Control (7 tools)

ToolDescription
controlforge_runtime_statusGet runtime state, uptime, scan time
controlforge_infoGet server info (version, platform)
controlforge_runtime_startStart the runtime — begins executing all tasks
controlforge_runtime_stopStop the runtime
controlforge_runtime_pausePause execution (can resume)
controlforge_runtime_resumeResume from pause
controlforge_runtime_reloadReload all programs without full restart

4.7 Step Debugger (9 tools)

ToolDescription
controlforge_debug_enableEnable the step debugger
controlforge_debug_disableDisable the step debugger
controlforge_debug_stateGet debugger state — stopped line, call stack, variables
controlforge_debug_set_breakpointSet a breakpoint at a program:line
controlforge_debug_list_breakpointsList all breakpoints
controlforge_debug_continueContinue to next breakpoint
controlforge_debug_step_intoStep into function/FB call
controlforge_debug_step_overStep over (execute without entering)
controlforge_debug_step_outStep out of current function/FB

Example: Debug a program

controlforge_debug_enable(host="localhost", port=8082)
controlforge_debug_set_breakpoint(host="localhost", port=8082, program="POU_Main", line=15)
controlforge_debug_continue(host="localhost", port=8082)
controlforge_debug_state(host="localhost", port=8082) // see where it stopped
controlforge_debug_step_over(host="localhost", port=8082)

4.8 Watch Windows (4 tools)

ToolDescription
controlforge_watch_listList all watch windows
controlforge_watch_createCreate a watch window for a set of variables
controlforge_watch_getPoll current values for a watch window
controlforge_watch_deleteDelete a watch window

4.9 Diagnostics (4 tools)

ToolDescription
controlforge_faultsGet active faults and error conditions
controlforge_diagnosticsGet scan times, memory usage, task stats
controlforge_logsGet recent log entries
controlforge_driversList I/O drivers and their connection status

4.10 Integrations (8 tools)

ToolDescription
controlforge_nodered_statusCheck if Node-RED is running
controlforge_nodered_startStart Node-RED subprocess
controlforge_nodered_stopStop Node-RED
controlforge_nodered_restartRestart Node-RED
controlforge_fuxa_statusCheck if FUXA SCADA is reachable
controlforge_config_getGet current runtime configuration (YAML)
controlforge_config_updateUpdate runtime configuration
controlforge_config_exportExport configuration as YAML file

4.11 Libraries (2 tools)

ToolDescription
controlforge_library_listList loaded ST libraries and their functions
controlforge_library_getGet a library's metadata and source

4.12 Fleet Management (2 tools)

ToolDescription
controlforge_fleet_discoverScan local network for ControlForge instances via mDNS
controlforge_fleet_listList known fleet nodes (filter by role, tier, family)

4.13 Protocol Analyzer (5 tools)

ToolDescription
controlforge_analyzer_statusGet capture status and statistics
controlforge_analyzer_startStart capturing protocol traffic (filter by protocol, device, direction)
controlforge_analyzer_stopStop capture
controlforge_analyzer_transactionsGet captured transactions with decoded fields
controlforge_analyzer_decodeDecode a raw hex packet offline

Supported protocols: Modbus TCP/RTU, FINS TCP/UDP, EtherNet/IP, S7, OPC UA, DNP3, BACnet, SEL

4.14 L5X Import/Export (2 tools)

ToolDescription
controlforge_l5x_importImport Rockwell L5X file → ST programs
controlforge_l5x_exportExport ST program → L5X XML for Studio 5000

4.15 Store-and-Forward (2 tools)

ToolDescription
controlforge_saf_statusGet offline buffering stats
controlforge_saf_pendingGet pending messages not yet forwarded

4.16 I/O Mappings (2 tools)

ToolDescription
controlforge_io_listList all I/O point mappings (%IX, %QX, %IW, %QW, %MW)
controlforge_io_createCreate a new I/O point mapping

4.17 Project (2 tools)

ToolDescription
controlforge_project_saveSave project to disk
controlforge_cluster_statusGet cluster status for all connected nodes

When building a PLC application from scratch, follow this order:

Step 1: Learn the System

controlforge_coding_rules() // Mandatory — learn the rules
controlforge_capabilities(host, port) // What data types and features exist
controlforge_guide_search(host, port) // GVL patterns, cross-task, hardware I/O

Step 2: Search for Functions

controlforge_functions(host, port, search="modbus") // Verify EVERY function before using it
controlforge_function_blocks(host, port) // Check available FBs (TON, PID, etc.)

Step 3: Write and Validate Code

controlforge_program_validate(host, port, source="...") // Check syntax before deploying

Step 4: Deploy

controlforge_deploy(host, port, task="MainTask", programs=[...]) // One call does it all

Step 5: Monitor

controlforge_variable_list(host, port) // See all variables
controlforge_variable_get(host, port, name="...") // Read specific values
controlforge_watch_create(host, port, tags=[...]) // Set up monitoring

Step 6: Build HMI

controlforge_hmi_template() // Get starter HTML
controlforge_hmi_create(host, port, name="dashboard", content="...", title="My Dashboard")

Step 7: Debug (if needed)

controlforge_debug_enable(host, port)
controlforge_debug_set_breakpoint(host, port, program="POU_Main", line=15)
controlforge_debug_state(host, port) // Inspect stopped state

6. Testing the MCP Server

A comprehensive test suite is included:

# Build the binary
go build -o goplc-dev ./cmd/controlforge

# Start a ControlForge instance
./goplc-dev project.goplc --api-port 8082

# Run the test suite (in another terminal)
python3 tests/mcp_test.py

# Run specific test groups
python3 tests/mcp_test.py --group debug,hmi,deploy

# Target a remote instance
python3 tests/mcp_test.py --host 10.0.0.34 --port 8302

# List available test groups
python3 tests/mcp_test.py --list

The test suite exercises all 80 tools in 18 groups and typically completes in under 5 seconds.


7. Troubleshooting

MCP server not responding

  • Ensure the binary is built: go build -o controlforge ./cmd/controlforge
  • Test directly: echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | ./controlforge mcp 2>/dev/null

Tools return "connection error"

  • Ensure a ControlForge instance is running on the target host:port
  • Check firewall: sudo ufw allow 8082/tcp
  • Verify with curl: curl http://localhost:8082/api/info

Authentication errors

  • Set export CONTROLFORGE_AUTH_TOKEN="your-token" before starting the MCP client
  • The token is read from the environment on every request

Tool not found

  • Run tools/list to see all registered tools
  • Ensure you're running the latest binary (check version with controlforge_info)