devidasjadhav/go-mdbus-mcp
If you are the rightful owner of go-mdbus-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
This project is a Model Context Protocol (MCP) server that provides Modbus TCP connectivity, focusing on reading and writing holding registers and coils.
Modbus MCP Server
This is a simplified MCP (Model Context Protocol) server that provides Modbus TCP connectivity with a focus on reading holding registers.
Features
- Modbus TCP Client: Connects to Modbus TCP servers with per-operation connections
- MCP Tools: Provides 4 tools for reading/writing holding registers and coils
- Modular Architecture: Well-organized code structure with separate packages
- Automatic Connection Management: Fresh connections for each operation prevent timeouts
- HTTP Transport: Uses streamable HTTP transport for MCP communication
- Debug Logging: Includes detailed logging for troubleshooting
Project Structure
.
├── main.go # Entry point and server setup
├── config/
│ └── config.go # Configuration structures
├── modbus/
│ ├── client.go # Modbus client implementation
│ └── tools.go # MCP tool definitions
├── docs/ # 📚 Comprehensive documentation
│ ├── README.md # Documentation overview
│ ├── architecture.md # System architecture & design
│ ├── api-reference.md # Complete API documentation
│ ├── development.md # Development guide & workflow
│ └── deployment.md # Production deployment guide
├── go.mod # Go module definition
├── go.sum # Dependency checksums
├── test_gemini.py # Gemini integration test script
├── gemini_integration_guide.md # Complete Gemini integration guide
└── README.md # This file (main project README)
🤖 CI/CD Pipeline
This project includes a comprehensive GitHub Actions CI/CD pipeline that automatically:
- Tests the code on every push and pull request
- Builds binaries for multiple platforms (Linux, macOS, Windows)
- Creates releases when you push version tags
- Builds Docker images and pushes to Docker Hub
- Generates release notes automatically
Creating a Release
-
Update version in code (optional)
-
Create and push a tag:
git tag v1.0.0 git push origin v1.0.0 -
Or use the Makefile:
make release-patch # v0.0.1 → v0.0.2 make release-minor # v0.0.1 → v0.1.0 make release-major # v0.0.1 → v1.0.0 -
GitHub Actions will:
- Run tests and build binaries
- Create a GitHub release
- Upload platform-specific binaries
- Generate automatic release notes
- Build and push Docker image
Available Platforms
The CI/CD pipeline builds binaries for:
- Linux: amd64, arm64
- macOS: amd64, arm64 (Apple Silicon)
- Windows: amd64
Docker Support
Automated Docker builds are triggered on releases:
# Pull the latest image
docker pull ghcr.io/devidasjadhav/go-mdbus-mcp:latest
# Or use a specific version
docker pull ghcr.io/devidasjadhav/go-mdbus-mcp:v1.0.0
Prerequisites
- A running Modbus TCP server (for testing, you can use a simulator)
- Port 8080 available for the MCP server
Usage
Command Line Arguments
--modbus-ip: Modbus server IP address (default: 192.168.1.22)--modbus-port: Modbus server port (default: 5002)
Start the Server
Using Go Directly
# Build first
go build -o modbus-server main.go
# Connect to test Modbus server on default port
./modbus-server
# Connect to specific Modbus server
./modbus-server --modbus-ip 192.168.1.100 --modbus-port 502
Using Make
# Quick development setup
make setup
make build
make run
# Or run in development mode
make run-dev
# Show all available commands
make help
Using Docker
# Build and run
make docker-build
make docker-run
# Or manually
docker build -t modbus-mcp-server .
docker run -p 8080:8080 -p 8081:8081 modbus-mcp-server
Available Tools
- read-holding-registers: Read Modbus holding registers with automatic reconnection
- read-coils: Read Modbus coils (digital inputs/outputs) with bit processing
- write-holding-registers: Write values to Modbus holding registers
- write-coils: Write values to Modbus coils (digital outputs)
Example API Calls
List Available Tools
curl -X POST \
-H "Content-Type: application/json" \
-d '{"method":"tools/list", "id":1}' \
http://localhost:8080/mcp
Read Holding Registers
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"read-holding-registers","arguments":{"address":0,"quantity":10}},"id":1}' \
http://localhost:8080/mcp
Expected Response:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"text": "Holding registers at address 0: [100 42 0 0 0 0 0 0 0 123]",
"type": "text"
}
]
},
"id": 1
}
Read Coils
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"read-coils","arguments":{"address":0,"quantity":14}},"id":1}' \
http://localhost:8080/mcp
Expected Response:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"text": "Coils at address 0: [false true true true true true false false false false false true false false]",
"type": "text"
}
]
},
"id": 1
}
Write Holding Registers
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"write-holding-registers","arguments":{"address":10,"values":[1234,5678,9999]}},"id":1}' \
http://localhost:8080/mcp
Expected Response:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"text": "Successfully wrote 3 values to holding registers starting at address 10: [1234 5678 9999]",
"type": "text"
}
]
},
"id": 1
}
Write Coils
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"write-coils","arguments":{"address":5,"values":[true,false,true,true,false]}},"id":1}' \
http://localhost:8080/mcp
Expected Response:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"text": "Successfully wrote 5 values to coils starting at address 5: [true false true true false]",
"type": "text"
}
]
},
"id": 1
}
Read Coils
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"read-coils","arguments":{"address":0,"quantity":8}},"id":2}' \
http://localhost:8080/mcp
Expected Response:
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"text": "Coils at address 0: [true false true false false false false true]",
"type": "text"
}
]
},
"id": 2
}
Connection Management
The server uses a per-operation connection strategy to prevent timeout issues:
- Per-Operation Connections: Creates a fresh TCP connection for each read operation and closes it immediately after
- No Persistent Connections: Eliminates connection timeout problems that occur with idle persistent connections
- Automatic Cleanup: Connections are automatically closed using defer statements to ensure proper resource management
- Fresh Handler Creation: Each operation creates a new Modbus handler for reliable communication
- Timeout Handling: 10-second timeout per operation for reliable operation with slower networks
- Debug Logging: Detailed logs help troubleshoot connection and communication issues
Testing
Automated Tests
Run the automated tests:
go test ./...
Or with mcp-autotest:
mcp-autotest run -u http://localhost:8080/mcp testdata -- go run main.go --modbus-ip 127.0.0.1 --modbus-port 502
Manual Testing
Build and run the server:
go build -o modbus-server main.go
./modbus-server --modbus-ip 192.168.1.22 --modbus-port 5002
📚 Documentation
For comprehensive documentation, see the directory:
- - Complete guide to all documentation
- - System design, data flow, and design decisions
- - Complete API documentation with examples
- - Setup, workflow, and contribution guidelines
- - Production deployment and configuration
Quick Start for Documentation:
- New to the project? → Start with
- Need API details? → Check
- Want to contribute? → Read
- Deploying to production? → Follow
Manual Testing with mcptools
The server has been tested and verified to work correctly with the MCP protocol. You can test it using the mcptools CLI tool.
Installation
# Install mcptools
go install github.com/f/mcptools/cmd/mcptools@latest
# Make sure it's in your PATH or use the full path
~/go/bin/mcptools --help
Testing the Server
-
Start the MCP server:
cd sample go run main.go -
Test server functionality with direct HTTP requests:
# Initialize connection curl -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}},"id":0}' \ http://localhost:8080/mcp # List available tools curl -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \ http://localhost:8080/mcp # Call a tool curl -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my-great-tool","arguments":{}},"id":2}' \ http://localhost:8080/mcp
Expected Results
✅ Server Status: The server starts successfully on http://localhost:8080/mcp
✅ Available Tools (2 tools):
read-holding-registers- Read Modbus holding registers with per-operation connectionsread-coils- Read Modbus coils (digital outputs) with per-operation connections
✅ Tool Functionality:
- Read Operations:
- Returns holding register values as uint16 arrays:
[100 42 0 0 0 0 0 0 0 123] - Returns coil states as boolean arrays:
[false true true true true true false false] - Properly processes Modbus bit-packed coil data (8 coils per byte)
- Returns holding register values as uint16 arrays:
- Write Operations:
- Writes multiple holding register values:
[1234 5678 9999] - Writes multiple coil states:
[true false true true false] - Automatic data conversion (uint16[] to bytes for registers, bool[] to bit-packed bytes for coils)
- Writes multiple holding register values:
- Uses per-operation connections to prevent timeout issues
- Provides detailed error messages for connection issues
✅ MCP Protocol Compliance: Server properly handles initialization, tool listing, and tool calling according to MCP specification
✅ Connection Resilience: Server automatically reconnects when the Modbus server connection is lost
Modbus Configuration
- Slave ID: Fixed to 0 (common default for Modbus TCP servers)
- Timeout: 10 seconds (increased for better reliability)
- Connection: TCP with per-operation connections (connect → read → close)
- Connection Management: Fresh connections for each operation to prevent timeouts
Recent Improvements
Version Updates
- Modular Architecture: Refactored code into organized packages (config, modbus)
- Enhanced Tool Set: Added write functionality for both holding registers and coils
- Per-Operation Connections: Fixed timeout issues by using fresh connections for each operation
- Improved Code Organization: Separated concerns into logical modules
- Automatic Connection Cleanup: Proper resource management with automatic connection closing
- Debug Logging: Added detailed logging for troubleshooting connection and communication issues
Connection Resilience
The server now handles network interruptions gracefully:
- Uses per-operation connections to prevent timeout issues
- Creates fresh Modbus handlers for each operation
- Automatic connection cleanup prevents resource leaks
- Provides clear error messages for debugging
- Eliminates persistent connection timeout problems
Error Handling
The server provides detailed error messages and automatic recovery for:
- Modbus connection failures: Automatic reconnection attempts
- Invalid addresses or quantities: Clear validation error messages
- Communication timeouts: 10-second timeout with retry logic
- Protocol errors: Detailed logging for troubleshooting
- Connection drops: Graceful handling with handler recreation