Skip to main content
Glama
MCP PLC Core

MCP PLC Core

by Maxkrempl

MCP PLC Core šŸ­

Universal MCP Server for industrial PLC communication — works with ANY PLC.

Connect any industrial controller to AI agents (Claude, GPT, OpenClaw) via MCP protocol. Siemens, Schneider, ABB, Mitsubishi, Omron, Allen-Bradley, WAGO, CODESYS, Arduino, ESP32, or any custom PLC — write an adapter and it just works.

Don't see your PLC? Write an adapter — takes 15 minutes. Just implement 6 methods in the PLCAdapter interface.

AI Agent (Claude, GPT, OpenClaw)
    ↓ MCP protocol (stdio)
MCP PLC Core
    ↓ your adapter (Modbus, S7, OPC UA, EtherNet/IP...)
PLC → Sensors, Alarms, Motors, Actuators

Quick Start

# Install
npm install mcp-plc-core

# Schneider / ABB / WAGO / CODESYS / Arduino
PLC_HOST=192.168.1.100 npx mcp-plc --adapter modbus

# Siemens S7-1200/1500/300/400
npm install nodes7
PLC_HOST=192.168.1.100 npx mcp-plc --adapter s7

# Mitsubishi / Omron / Allen-Bradley / anything else
npx mcp-plc --adapter ./my-custom-adapter.js

Related MCP server: OpenTIA-MCP

Built-in Adapters

Adapter

Protocol

Port

PLC Types

modbus

Modbus TCP

502

Schneider, ABB, WAGO, CODESYS, Arduino

s7

S7 (RFC1006)

102

Siemens S7-1200/1500/300/400

Custom Adapter — Works with ANY PLC

Implement the PLCAdapter interface for your PLC. Regardless of manufacturer, protocol, or model — if it has TCP/IP or serial connectivity, you can write an adapter.

PLCs you can write adapters for:

  • Siemens S7-200/300/400/1200/1500/1700

  • Schneider M340/M580/Modicon

  • ABB AC500/AC580

  • Mitsubishi MELSEC iQ-R/F/L

  • Omron NJ/NX/NP

  • Allen-Bradley ControlLogix/CompactLogix

  • WAGO PFC200/750

  • CODESYS-based controllers

  • Bosch Rexroth IndraMotion

  • Beckhoff TwinCAT

  • Fanuc CNC (FOCAS)

  • Haas / DMG Mori / Mazak

  • Arduino + EthernetShield

  • ESP32 + Modbus/S7 gateway

  • Any custom TCP/UDP protocol

import { PLCAdapter, SensorData, AlarmData, StatusData, SetpointData, OutputData } from "mcp-plc-core";

export class MyPLCAdapter implements PLCAdapter {
  readonly name = "My PLC";
  readonly protocol = "my-protocol";

  async connect() { /* ... */ }
  async disconnect() { /* ... */ }
  isConnected(): boolean { /* ... */ }

  async readSensors(): Promise<SensorData> {
    return {
      temperature: 25.3,
      pressure: 6.2,
      motorSpeed: 1500,
      production: 1234,
    };
  }

  async readAlarms(): Promise<AlarmData> {
    return { active: [], count: 0 };
  }

  async readStatus(): Promise<StatusData> {
    return { status: "running" };
  }

  async readSetpoints(): Promise<SetpointData> {
    return { temperature: 25, pressure: 6, speed: 1500 };
  }

  async readOutputs(): Promise<OutputData> {
    return { green: true, yellow: false, red: false };
  }

  async writeSetpoint(parameter: string, value: number): Promise<boolean> {
    // Write to your PLC...
    return true;
  }
}

Then use it:

import { startServer, MyPLCAdapter } from "mcp-plc-core";

const adapter = new MyPLCAdapter();
await startServer({
  adapter,
  limits: {
    temperature: { min: 0, max: 50 },
    pressure: { min: 0, max: 10 },
  },
});

MCP AI Integration

Claude Desktop / OpenClaw

{
  "mcpServers": {
    "plc": {
      "command": "npx",
      "args": ["mcp-plc", "--adapter", "modbus"],
      "env": {
        "PLC_HOST": "192.168.1.100",
        "PLC_PORT": "502"
      }
    }
  }
}

Siemens S7

{
  "mcpServers": {
    "plc": {
      "command": "npx",
      "args": ["mcp-plc", "--adapter", "s7"],
      "env": {
        "PLC_HOST": "192.168.1.100",
        "PLC_SLOT": "1"
      }
    }
  }
}

Tools

Tool

Description

Example

read_sensor

Read sensor value

"What's the temperature?"

get_alarms

Get active alarms

"Any alarms active?"

get_status

Full system status

"How's the line running?"

get_setpoints

Current setpoints

"What are the setpoints?"

write_setpoint

Write setpoint (safe!)

"Set temperature to 35°C"

get_all

Everything at once

"Give me all data"

Resources

Resource

Description

plc://tags

Available sensors/tags

plc://alarms

Alarm definitions

plc://status

Current status

plc://info

PLC and adapter info

Safety

  • āœ… Read-only by default — no writes without explicit tool call

  • āœ… Safety limits — configurable min/max for setpoints

  • āœ… Audit logging — all tool calls logged

  • āœ… Adapter isolation — protocol-specific errors don't leak

  • āš ļø Write protection — only setpoint registers, never I/O directly

Architecture

src/
ā”œā”€ā”€ adapter.ts          ← PLCAdapter interface (implement this)
ā”œā”€ā”€ server.ts           ← MCP server (generic, adapter-agnostic)
ā”œā”€ā”€ cli.ts              ← CLI entry point
ā”œā”€ā”€ index.ts            ← Package exports
└── adapters/
    ā”œā”€ā”€ modbus.ts       ← Modbus TCP adapter (built-in)
    └── s7.ts           ← Siemens S7 adapter (built-in)

Writing a New Adapter

6 methods. 15 minutes. Works with any PLC.

  1. Create src/adapters/myplc.ts

  2. Implement PLCAdapter interface (6 methods)

  3. Register in cli.ts:

if (adapterName === "myplc") {
  const { MyPLCAdapter } = await import("./adapters/myplc.js");
  return new MyPLCAdapter({ host, port });
}
  1. Submit PR! šŸŽ‰

Supported Protocols (via adapters)

Protocol

Status

Adapter

Modbus TCP

āœ… Built-in

modbus

S7 (RFC1006)

āœ… Built-in

s7

OPC UA

āœ… Via community

node-opcua

EtherNet/IP

āœ… Via community

ethernetip

BACnet

āœ… Via community

bacstack

MQTT + Sparkplug B

āœ… Via community

mqtt

Mitsubishi MC Protocol

šŸ”Ø Community needed

—

Omron FINS

šŸ”Ø Community needed

—

Allen-Bradley CIP

šŸ”Ø Community needed

—

Bosch Rexroth

šŸ”Ø Community needed

—

Fanuc FOCAS

šŸ”Ø Community needed

—

Haas NGC

šŸ”Ø Community needed

—

Any custom TCP/UDP

āœ… Adapter interface

PLCAdapter

Don't see your protocol? Implement PLCAdapter — 6 methods, 15 minutes of work. Submit a PR and it'll be in the next release.

Environment Variables

Variable

Default

Description

PLC_HOST

127.0.0.1

PLC IP address

PLC_PORT

varies

PLC port (502 for Modbus, 102 for S7)

PLC_ADAPTER

modbus

Adapter to use

PLC_RACK

0

Rack number (S7 only)

PLC_SLOT

1

Slot number (S7: 1, S7-300/400: 2)

License

MIT — use it, fork it, build adapters for your PLC.


HD WebDesign — MCP for industrial automation

Available Tools

6 tools
get_alarmsC

Get all active alarms from the PLC.

Inputs: no named parameters.

get_allA

Get all PLC data at once: sensors, alarms, status, setpoints, outputs.

Inputs: no named parameters.

get_setpointsC

Get current setpoint values.

Inputs: no named parameters.

get_statusC

Get overall PLC system status.

Inputs: no named parameters.

read_sensorB

Read a sensor value from the PLC.

Inputs: sensor (required).

write_setpointA

Write a setpoint value to the PLC. Validates against safety limits.

Inputs: value (required), parameter (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 6 tools

    Disambiguation4/5

    Tools are mostly distinct: read_sensor, get_alarms, get_status, get_setpoints, and write_setpoint each target a specific domain area. The main overlap is get_all, which subsumes the individual getters, potentially confusing an agent about whether to call it or individual tools, though descriptions make the distinction reasonably clear.

    Naming Consistency4/5

    Naming follows a consistent verb_noun pattern: read_sensor, get_alarms, get_status, get_setpoints, write_setpoint, get_all. Minor inconsistency exists with 'read' vs 'get' for data retrieval (read_sensor uses read while others use get), but this is a small deviation and the pattern is otherwise uniform.

    Tool Count5/5

    Six tools is a well-scoped set for a PLC control server, covering the essential read and write operations without bloat. Each tool serves a clear purpose, and the count is appropriate for the domain.

    Completeness4/5

    The surface covers reading sensors, alarms, status, and setpoints, plus writing setpoints with safety validation. Notably missing are operations for controlling outputs (writing discrete/analog output values) and acknowledging alarms, which are common PLC tasks. However, get_all consolidates reads, and setpoint writing is the safety-relevant write path.

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      B
      maintenance
      MCP server that connects WAGO PLCs to LLM agents via the WDx/WDA REST API, enabling AI assistants to read sensor values, change configuration, trigger firmware updates, or monitor entire PLC fleets without custom code.
      233 PyPI
      4
      -
    • A
      license
      A
      quality
      D
      maintenance
      MCP server for industrial PLC integration, enabling AI to read tags, monitor alarms, and interact with Allen-Bradley ControlLogix PLCs via natural language.
      9
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      The first and only MCP server for PLC (Programmable Logic Controller) intelligence. Give any AI agent direct access to industrial automation data — ladder logic, tag databases, cross-references, fault root cause analysis, and sequence blockers
      MIT