industrial-mcp
An MCP server that gives Claude (or any MCP-compatible AI host) read access to industrial sensor data and safety-gated control over motors and actuators.
README
industrial-mcp
An MCP server that gives Claude (or any MCP-compatible AI host) read access to industrial sensor data and safety-gated control over motors and actuators.
The hard part of Physical AI isn't getting a language model to talk about a factory — it's getting it to act on one without anyone losing sleep. That requires three boring things working together:
- Tool schemas the model can understand and call correctly.
- Safety preconditions that block dangerous actions even when the model is confident.
- An audit trail that survives the next post-mortem.
This repo is a working implementation of all three, in under 500 lines of Python, using FastMCP. Default mode is read-only and ships with a deterministic mock adapter modeling a 7-silo grain storage facility, so it runs in CI with no infrastructure.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ MCP host (Claude Desktop, Claude Code, Cursor, etc.) │
│ user prompt ──► model decides which tool to call │
└──────────────────────────────┬──────────────────────────────────────┘
│ stdio (JSON-RPC over MCP)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ industrial-mcp (this repo) │
│ │
│ server.py ── wires tools, env config, audit log │
│ │ │
│ ├── tools.py ── 5 read tools + 1 write tool (dry-run default) │
│ │ │
│ ├── safety.py ── preconditions, advisory warnings │
│ │ │
│ ├── audit.py ── append-only JSONL of executed actions │
│ │ │
│ └── adapters/ │
│ ├── mock.py ← default, deterministic demo data │
│ ├── mqtt.py ← (your impl) live ESP32 fleet │
│ └── rest.py ← (your impl) thin REST adapter │
└──────────────────────────────┬──────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
[MQTT broker] [internal REST API] [historian / TSDB]
Quick start
Run the server, talk to it from Claude Desktop, see it work.
# 1. Run the server with the mock adapter (no infra required)
uvx industrial-mcp@latest
# 2. Add this to ~/Library/Application Support/Claude/claude_desktop_config.json
# (macOS) — see examples/claude-desktop-config.json
Then in Claude Desktop:
¿Qué silos tienen alerta crítica hoy?
Claude calls list_plants → get_active_alerts → answers with the
data. See examples/demo-transcript.md
for a full session.
To enable live (non-dry-run) execution against the mock adapter:
INDUSTRIAL_MCP_ALLOW_WRITES=true uvx industrial-mcp@latest
This flag does not affect dry runs — those always work. It only unlocks the path where a tool call would actually mutate state.
Tools exposed over MCP
| Tool | Type | Purpose |
|---|---|---|
list_plants |
read | List facilities the server can see. |
list_silos |
read | Silos at a plant with capacity in tons. |
get_silo_thermometry |
read | Latest thermometry snapshot (min/avg/max °C). |
list_motors |
read | Motors at a plant, optionally filtered by kind. |
get_active_alerts |
read | Active alerts, filterable by severity. |
trigger_motor_action |
write | Start/stop a motor — dry-run by default, safety-gated, audited. |
Tool schemas live in src/industrial_mcp/tools.py.
Keep their docstrings short and exact — they become the model's tool
descriptions.
Why three layers of safety, not one
trigger_motor_action will only execute when all of the following
hold:
- The LLM explicitly sets
dry_run=False. - The call includes an
operator_idand areason. - The server itself was started with
INDUSTRIAL_MCP_ALLOW_WRITES=true. - Every precondition in
safety.evaluate_motor_actionpasses.
Step 3 is the one that matters most. The model can hallucinate
dry_run=False; the operator field can be spoofed by a clever prompt;
the safety check can have a bug. But if the server was started
read-only, none of that touches a motor. The deploy posture is the
last word, not the prompt.
Every executed call is appended to an append-only JSONL audit log:
{"ts": 1779600000.12, "actor": "op-42", "action": "motor.start",
"target": "fan-7-1", "outcome": "applied",
"details": {"reason": "silo-7 at 32.1°C, manual fan-on"}}
Dry runs are not logged. They're not interesting and they'd dilute the signal.
Adapters
The mock adapter ships in src/industrial_mcp/adapters/mock.py and is
the only one wired in the scaffold. It produces deterministic data so
CI and demos behave identically.
To talk to a real plant, drop a sibling module (e.g. mqtt.py)
implementing the same surface — list_plants, list_silos,
get_silo_thermometry, list_motors, get_motor,
get_plant_context, get_active_alerts, apply_motor_action — and
select it with INDUSTRIAL_MCP_ADAPTER=mqtt.
A reference MQTT adapter (HiveMQ-compatible, paho-mqtt) is the next issue in the tracker.
Development
git clone https://github.com/brayangcastro/mcp-industrial-agent
cd mcp-industrial-agent
uv sync --extra dev
uv run pytest -v
uv run ruff check src tests
CI runs the same two commands on Python 3.11 and 3.12 — see
.github/workflows/ci.yml.
FAQ
Why not just give the model raw API keys? Because then every prompt injection is one HTTP call away from a production motor. The MCP surface is narrow on purpose: the model sees six functions, not your AWS console.
Why a separate dry_run flag instead of a confirmation step?
Confirmation steps add latency and break flow. The dry run returns
the outcome the model would have caused — preconditions, warnings,
state delta — as data the model can keep reasoning over. Live
execution is then a one-line escalation, not a five-prompt dance.
Is the audit log enough for compliance? No. It's enough to reconstruct what happened. It is not enough on its own for IEC 62443, IATF 16949, or similar. Pair it with your plant's existing change-management system; this repo is a starting point, not a finished compliance story.
Mock adapter only? Where's MQTT / OPC UA? This scaffold deliberately stops at the shape of the surface. Real adapters belong in a follow-up issue and are usually plant-specific anyway — the broker URLs, topic structures, and ACLs you can publish publicly are usually zero.
Status
Active scaffold, not yet 1.0. The shapes are stable; expect breaking changes in non-public APIs until the first MQTT adapter lands.
Author
Built and maintained by Brayan Castro — Ing.
Mecatrónica (ITESM Sonora Norte), operating BC Ingeniería from Guasave,
Sinaloa. Background: 4+ years building IoT systems for agroindustrial
grain handling (firmware ESP32 + thermocouple MUX + cloud), backend
services for property management and POS, and conversational AI agents
on top of Claude / GPT-4o. Reach out: info@ingebc.com.
License
MIT — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.