Forgeline
Forgeline is a read-only Modbus TCP monitoring server that exposes Modbus operations as safe MCP tools for AI agents, allowing inspection of industrial devices without modifying any device state.
get_device_info— Retrieve identity and connection details (vendor name, product code, revision, model name, host, port, unit ID) for the monitored Modbus device.read_holding_registers— Read 16-bit holding registers (FC 0x03) from a zero-based start address (0–65535), up to 125 registers at a time. Returns address→value pairs.read_input_registers— Read 16-bit read-only input registers (FC 0x04) from a zero-based start address (0–65535), up to 125 registers at a time. Returns address→value pairs.read_coils— Read single-bit on/off coil values (FC 0x01) from a zero-based start address (0–65535), up to 2000 coils at a time. Returns address→boolean pairs.
All tools are read-only — no writes or state changes are possible. The server also includes a bundled Modbus simulator for testing without physical hardware, is configurable via environment variables (host, port, unit ID, transport), and supports multiple deployment options including Docker Compose, local Python, and various MCP transports (stdio, SSE, streamable-http).
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., "@Forgelineread holding registers from address 0 to 4"
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.
Forgeline
Read-only Modbus TCP monitoring, exposed as safe MCP tools.
Forgeline is an MCP server that lets an AI agent monitor an industrial Modbus TCP device — reading holding/input registers, coils, and device identity — without being able to change anything.
It's read-only on purpose: there are no write or command tools, and no code that writes coils or registers, so a connected agent can't alter device state.
A simulated Modbus device is bundled, so you can run it with no hardware.
Status
Working MVP. Four read-only tools — get_device_info, read_holding_registers,
read_input_registers, read_coils — tested against the bundled simulator.
Related MCP server: safe-postgres-mcp
Project layout
forgeline/
├── src/forgeline/
│ ├── server.py # FastMCP server: registers MCP tools
│ └── tools.py # Read-only Modbus implementations (transport-agnostic)
├── simulator/
│ └── device.py # Bundled pymodbus TCP simulator (zero hardware)
├── docker-compose.yml # Starts simulator + server together
├── Dockerfile
├── pyproject.toml
├── README.md
└── LICENSE # Apache 2.0Quick start
Option A — Docker (simulator + server, one command)
docker compose up --buildThis starts:
simulator — a virtual Modbus device on
localhost:5020.forgeline — the MCP server over
streamable-httpathttp://localhost:8000/mcp, already pointed at the simulator.
Option B — Local Python
Requires Python 3.10+.
pip install -e .
# Terminal 1: start the bundled simulator
forgeline-simulator
# Terminal 2: run the MCP server (stdio transport, for an MCP client)
forgelineBy default the server talks to the simulator on 127.0.0.1:5020.
Configuration
All configuration is via environment variables.
Variable | Default | Description |
|
| Host of the Modbus TCP device to monitor. |
|
| Port of the Modbus TCP device. |
|
| Modbus unit / slave id. |
|
| Per-request timeout in seconds. |
|
| MCP transport: |
|
| Bind host for HTTP transports. |
|
| Bind port for HTTP transports. |
|
| Bind host for the bundled simulator. |
|
| Bind port for the bundled simulator. |
Connecting an MCP client
To launch Forgeline over stdio (e.g. from Claude Desktop or another MCP client),
register a server that runs the forgeline command. Example client config:
{
"mcpServers": {
"forgeline": {
"command": "forgeline",
"env": { "MODBUS_HOST": "127.0.0.1", "MODBUS_PORT": "5020" }
}
}
}(Start forgeline-simulator first, or point MODBUS_HOST/MODBUS_PORT at a
real device.)
Tools
get_device_info
Returns identity and connection details for the monitored device.
{
"host": "127.0.0.1",
"port": 5020,
"unit_id": 1,
"connected": true,
"device_identification_supported": true,
"identity": {
"vendor_name": "Forgeline",
"product_code": "FL-SIM-1",
"revision": "1.0.0",
"vendor_url": "https://github.com/codenikhildr/Forgeline",
"product_name": "Forgeline Modbus Simulator",
"model_name": "Virtual PLC",
"user_application_name": "Forgeline MVP Simulator"
}
}Devices that do not implement Modbus device identification still return
connection details, with device_identification_supported: false.
read_holding_registers / read_input_registers
Read 16-bit registers — holding (FC 0x03, read/write on the device) or input (FC 0x04, read-only measurements). Parameters:
Param | Type | Default | Bounds |
| int | — |
|
| int |
|
|
// read_holding_registers(address=0, count=5)
{
"start_address": 0,
"count": 5,
"unit_id": 1,
"values": [
{ "address": 0, "value": 100 },
{ "address": 1, "value": 101 },
{ "address": 2, "value": 102 },
{ "address": 3, "value": 103 },
{ "address": 4, "value": 104 }
]
}read_coils
Read single-bit on/off coils (FC 0x01). Parameters:
Param | Type | Default | Bounds |
| int | — |
|
| int |
|
|
// read_coils(address=0, count=4)
{
"start_address": 0,
"count": 4,
"unit_id": 1,
"values": [
{ "address": 0, "value": false },
{ "address": 1, "value": true },
{ "address": 2, "value": false },
{ "address": 3, "value": true }
]
}Requests outside these bounds (count over the limit, or a range that exceeds the 16-bit address space) are rejected before any request reaches the device.
Simulator data map
The bundled simulator pre-populates each table (addresses are zero-based):
Table | FC | Addresses | Values |
Holding registers | 0x03 | 0–99 |
|
Input registers | 0x04 | 0–99 |
|
Coils | 0x01 | 0–99 |
|
Discrete inputs | 0x02 | 0–99 |
|
Development
Run the test suite — it starts the bundled simulator on a test port and exercises all four tools plus the input-validation guards:
pip install -e ".[dev]"
pytestCI runs the same suite on every push and pull request across Python 3.10–3.12.
License
Apache License 2.0. See LICENSE.
Available Tools
4 toolsget_device_infoA
Get identity and connection details for the monitored Modbus device.
Returns the device's vendor, product code, revision and related fields (when the device supports Modbus device identification), plus the host, port and unit id Forgeline is connected to. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description declares the tool is 'Read-only', which is a key behavioral trait. It also notes that certain fields are conditional ('when the device supports...'), providing transparency beyond the empty schema. No annotations are present, so the description fully handles transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the main action, and every sentence adds value. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description thoroughly explains what is returned (vendor, product code, revision, host, port, unit id). It is sufficient for an AI to understand the tool's output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so schema_description_coverage is 100%. Per guidelines, baseline is 4. No additional parameter information is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves identity and connection details for a Modbus device. It uses a specific verb 'Get' and specifies the resource (device info). The sibling tools read coils/registers, which are distinct, so this tool is well differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly state when to use this tool versus alternatives. It implies usage for device identity and connection details, but no when-not or alternative references are provided. However, the context is clear enough from the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_coilsA
Read coils (FC 0x01) from the monitored Modbus device.
Coils are single-bit on/off values. Returns the start address, count, unit id, and a list of address -> boolean value pairs. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Zero-based start address (0..65535). | |
| count | No | Number of coils to read (1..2000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It clearly states 'Read-only' and describes the return structure (start address, count, unit id, list of address->boolean pairs). This sufficiently discloses that the operation is safe and has no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise—three sentences with no fluff: purpose, explanation of coils, and return value structure. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool is simple and no output schema exists, the description adequately covers the return components. Missing are error conditions and prerequisites (e.g., device connection), but for a basic read operation the description is largely complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already describes both parameters well. The description adds context about coils being 'single-bit on/off values' but does not expand on parameter meaning beyond the schema. Baseline 3 is appropriate; the description adds marginal value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the specific verb 'read' and resource 'coils' and includes the function code (FC 0x01). It distinguishes from siblings like 'read_holding_registers' by specifying it reads single-bit values, making the tool's purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool vs. alternatives. It does not mention when not to use it or compare to sibling tools. The sibling names are listed externally but not referenced in the description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_holding_registersB
Read holding registers (FC 0x03) from the monitored Modbus device.
Holding registers are 16-bit read/write values (Forgeline reads them only). Returns the start address, count, unit id, and a list of address -> value pairs. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Zero-based start address (0..65535). | |
| count | No | Number of registers to read (1..125). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden. It correctly states the tool is read-only and describes the return format (start address, count, unit id, list of address->value pairs). However, it does not disclose potential error conditions, timeouts, or concurrency behavior, leaving gaps in transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (2 sentences) and front-loads the key purpose with the function code. It efficiently covers the operation, data type, and return structure without unnecessary detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description adequately describes the return structure. It covers the essential aspects of the operation for a simple read tool. However, it omits details like the unit id source or defaults, which could be inferred but are not explicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for both parameters (address and count) with clear ranges and defaults. The description adds no new information about parameter semantics beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads holding registers using Modbus function code 0x03, specifying the data type (16-bit read/write values). It implicitly distinguishes from siblings like read_coils and read_input_registers by name and context, but could be more explicit about differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives or any prerequisites. It mentions 'Read-only' but does not specify when not to use it or any preconditions for the Modbus device.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_input_registersA
Read input registers (FC 0x04) from the monitored Modbus device.
Input registers are 16-bit read-only measurements. Returns the start address, count, unit id, and a list of address -> value pairs.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Zero-based start address (0..65535). | |
| count | No | Number of registers to read (1..125). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It states the tool reads read-only input registers, implying no side effects, but does not elaborate on error behavior, potential delays, or other operational traits. Adequate but not comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with action and context. Every word is purposeful with no redundancy. Efficient and clear.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with two well-documented parameters, the description covers the purpose, register type, and return format. Lacks only finer behavioral details, but overall complete given the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline 3. The description only mentions address and count as part of the return but adds no additional meaning or syntax details beyond what the schema provides. No new parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads input registers via Modbus function code 0x04, specifying they are 16-bit read-only measurements. This distinguishes it from sibling tools like read_coils and read_holding_registers by naming the specific register type and function code.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for reading input registers but provides no explicit guidance on when to use this tool versus alternatives like read_holding_registers. No exclusion criteria or context for selection are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
get_device_info - First observed
read_coils - First observed
read_holding_registers - First observed
read_input_registers
TDQS
Each tool has a distinct purpose: get_device_info for identity/connection, read_coils for single-bit values, read_holding_registers for 16-bit read/write registers, and read_input_registers for 16-bit read-only registers. No overlap in functionality.
All tool names follow a consistent verb_noun pattern using lowercase and underscores (e.g., get_device_info, read_coils). The naming convention is uniform and predictable.
With 4 tools, the server is well-scoped for its purpose of monitoring a Modbus device. The count is within the ideal range of 3-15 tools and covers essential read operations without unnecessary bloat.
The tool set covers device identity and the three primary read function codes (coils, holding registers, input registers) for Modbus monitoring. A minor gap is the absence of reading discrete inputs (FC 0x02), but this is a reasonable omission for a basic monitoring server.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Read-only MCP server for the OPERANT AI operating-agent calibration benchmark.
Read-only MCP server exposing a user ORANO library to their own AI agent.
1Read-only MCP server for turva.dev, an agent-readiness audit and advisory service.
Read-only MCP tools for AI agent discovery, structured resources, and NIULAI information.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceThis MCP server enables AI agents to read MQTT and Sparkplug B data via tools like list_topics, get_latest, and read_all, providing read-only access to latest sensor values.1MIT
- AlicenseNot gradedqualityBmaintenanceA zero-config, read-only PostgreSQL MCP server that enforces read-only access at the database level using READ ONLY transactions, allowing AI agents to safely explore schemas and run SELECT queries without risk of mutation.49MIT
- FlicenseNot gradedqualityBmaintenanceRead-only MCP server for diagnosing H7-TOOL hardware via Modbus, USB HID, and Lua diagnostics, exposing only safe read operations.10-
- FlicenseAqualityCmaintenanceA secure, read-only MCP server for AI-powered system monitoring. It provides real-time OS metrics, config discovery, and safe log tailing to enable autonomous infrastructure audits without shell access risks.4-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/codenikhildr/Forgeline'
If you have feedback or need assistance with the MCP directory API, please join our Discord server