Beckhoff PLC MCP Server
Enables read-only access to Beckhoff TwinCAT PLCs via ADS, allowing queries of device info, symbols, variables, and EtherCAT diagnostics through natural language.
README
Beckhoff PLC MCP Server
An MCP (Model Context Protocol) server that provides read-only access to Beckhoff TwinCAT PLCs via ADS (Automation Device Specification).
Features
- Query PLC device information and state
- List and search PLC symbols
- Read single or multiple PLC variables
- Dynamic PLC discovery and connection via UDP (port 48899)
- EtherCAT diagnostics - master state, slave count, topology, and slave info
- Custom ADS port access - query and read from any ADS port (e.g., I/O Image ports)
- Graceful startup - server starts even if no local PLC is connected
- Automatic ADS route creation
- Automatic symbol caching for fast lookups
- Support for common TwinCAT data types
Prerequisites
- Python 3.10 or higher
- Beckhoff TwinCAT runtime with ADS enabled
- ADS routing configured (for remote PLCs)
Installation
# Clone or navigate to the project directory
cd beckhoff_mcp
# Install with pip
pip install -e .
# Or install dependencies directly
pip install mcp pyads pydantic
Uninstallation
To uninstall the current version before installing a new one:
# Uninstall the package
pip uninstall beckhoff_mcp
# Verify it's removed
pip show beckhoff_mcp
Configuration
Default Connection Settings
The server attempts to connect to a local TwinCAT PLC on startup:
AMS_NET_ID = "127.0.0.1.1.1" # Localhost AMS Net ID
AMS_PORT = 851 # TwinCAT 3 PLC Runtime 1
Note: If no local PLC is available (e.g., TwinCAT is not running or is in Config mode), the server will start in disconnected mode. You can then use beckhoff_discover_and_connect to connect to a remote PLC.
To modify the default settings, edit src/beckhoff_mcp/server.py and update the constants at the top of the file.
Dynamic Connection (Runtime)
You can also connect to remote PLCs at runtime using the beckhoff_discover_and_connect tool. Simply ask Claude to connect to a specific IP address:
<beckhoff:mcp: ip=192.168.1.54>
Or with credentials for automatic route creation:
Connect to PLC at 192.168.1.54 with username admin and password secret
Common AMS Port Numbers
| Port | Description |
|---|---|
| 851 | TwinCAT 3 PLC Runtime 1 |
| 852 | TwinCAT 3 PLC Runtime 2 |
| 853 | TwinCAT 3 PLC Runtime 3 |
| 854 | TwinCAT 3 PLC Runtime 4 |
Usage
Running the Server
# Using the installed script
beckhoff_mcp
# Or run directly
python -m beckhoff_mcp.server
Claude Desktop Configuration
Add to your Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"beckhoff_mcp": {
"command": "python",
"args": ["-m", "beckhoff_mcp.server"]
}
}
}
Or if installed as a package:
{
"mcpServers": {
"beckhoff_mcp": {
"command": "beckhoff_mcp"
}
}
}
Available Tools
beckhoff_get_device_info
Get PLC device name and version information.
Input: None
Output:
{
"device_name": "TwinCAT PLC",
"version": {
"major": 3,
"minor": 1,
"build": 4024
}
}
beckhoff_get_device_state
Get current ADS state and device state.
Input: None
Output:
{
"ads_state": {
"code": 5,
"name": "Run"
},
"device_state": 0
}
beckhoff_list_symbols
List available PLC symbols with optional filtering and pagination.
Input:
filter(optional): Filter pattern with wildcards (e.g.,"GVL_*","*Motor*")limit(optional, default 50): Maximum results to returnoffset(optional, default 0): Pagination offset
Output:
{
"symbols": [
{"name": "GVL.bStart", "type": "BOOL", "comment": "Start button"},
{"name": "GVL.nCounter", "type": "INT", "comment": "Cycle counter"}
],
"pagination": {
"total": 150,
"offset": 0,
"limit": 50,
"returned": 50,
"has_more": true,
"next_offset": 50
}
}
beckhoff_get_symbol_info
Get detailed information about a specific symbol.
Input:
symbol_name(required): Full symbol name (e.g.,"MAIN.bStart")
Output:
{
"name": "MAIN.bStart",
"type": "BOOL",
"index_group": 16448,
"index_offset": 0,
"size": 1,
"comment": "Start button"
}
beckhoff_read_variable
Read a single PLC variable by symbol name.
Input:
symbol_name(required): Full variable name (e.g.,"GVL.nCounter")
Output:
{
"name": "GVL.nCounter",
"type": "INT",
"value": 42
}
beckhoff_read_variables
Read multiple PLC variables at once.
Input:
symbol_names(required): List of variable names
Output:
{
"results": [
{"name": "GVL.bStart", "type": "BOOL", "value": true},
{"name": "GVL.nCounter", "type": "INT", "value": 42}
],
"errors": null,
"summary": {
"requested": 2,
"successful": 2,
"failed": 0
}
}
beckhoff_discover_and_connect
Discover and connect to a remote PLC by IP address using UDP discovery.
Input:
ip_address(required): IP address of the target PLCusername(optional): PLC login for route creationpassword(optional): PLC password for route creationams_port(optional, default 851): ADS port numberroute_name(optional): Custom name for the route
Output:
{
"success": true,
"ip_address": "192.168.1.54",
"discovered_ams_net_id": "192.168.1.54.1.1",
"ams_port": 851,
"route_added": true,
"device_info": {
"device_name": "CX-12345",
"version": {"version": 3, "revision": 1, "build": 4024}
},
"symbols_cached": 150
}
beckhoff_connection_status
Get information about the current PLC connection.
Input: None
Output:
{
"ams_net_id": "192.168.1.54.1.1",
"ams_port": 851,
"ip_address": "192.168.1.54",
"is_remote": true,
"is_connected": true,
"symbols_cached": 150
}
EtherCAT Diagnostic Tools
beckhoff_get_ethercat_master_state
Get the EtherCAT master state (Init, PreOp, SafeOp, Op).
Input: None
Output:
{
"master_state": {"code": 8, "name": "Op"},
"ams_net_id": "192.168.1.54.1.1",
"ethercat_port": 65535
}
beckhoff_get_ethercat_slave_count
Get the number of connected EtherCAT slaves.
Input: None
Output:
{
"slave_count": 5,
"ams_net_id": "192.168.1.54.1.1"
}
beckhoff_get_ethercat_topology
Get the full EtherCAT network topology with all slave information.
Input: None
Output:
{
"slave_count": 3,
"slaves": [
{"address": 1, "state": {"code": 8, "name": "Op"}, "vendor_id": 2, "product_code": 100663346},
{"address": 2, "state": {"code": 8, "name": "Op"}, "vendor_id": 2, "product_code": 100728882}
],
"ams_net_id": "192.168.1.54.1.1"
}
beckhoff_get_ethercat_slave_info
Get detailed information about a specific EtherCAT slave.
Input:
slave_address(required): The slave address (1-indexed)
Output:
{
"address": 1,
"state": {"code": 8, "name": "Op"},
"vendor_id": 2,
"product_code": 100663346,
"crc_errors": 0,
"ams_net_id": "192.168.1.54.1.1"
}
Custom ADS Port Tools
Some EtherCAT devices (like EK1200 EtherCAT Couplers) expose their I/O data on custom ADS ports rather than the standard EtherCAT master port (0xFFFF). Use these tools to access such devices.
beckhoff_query_ads_port
Query a custom ADS port to discover available symbols and device information.
Input:
ads_port(required): The ADS port number (e.g., 27905 or 0x6D01)
Output:
{
"ads_port": 27905,
"ads_port_hex": "0x6D01",
"ams_net_id": "5.59.203.226.1.1",
"ip_address": "192.168.1.67",
"success": true,
"device_info": {
"device_name": "EK1200",
"version": {"version": 3, "revision": 1, "build": 4024}
},
"state": {
"ads_state": {"code": 5, "name": "Run"},
"device_state": 0
},
"symbol_count": 4,
"symbols_preview": [
{"name": "Inputs.EL1008.Channel 1.Input", "type": "BOOL"},
{"name": "Outputs.EL2008.Channel 1.Output", "type": "BOOL"}
]
}
beckhoff_read_from_port
Read a variable from a custom ADS port.
Input:
ads_port(required): The ADS port number (e.g., 27905)symbol_name(required): The symbol name to read
Output:
{
"name": "Inputs.EL1008.Channel 1.Input",
"type": "BOOL",
"value": true,
"ads_port": 27905
}
How to find the ADS port: In TwinCAT XAE, double-click on the device (e.g., under I/O > Devices > EtherCAT), go to the "ADS" tab, and note the "ADS Server Port" value.
Supported Data Types
| TwinCAT Type | Description |
|---|---|
| BOOL | Boolean (TRUE/FALSE) |
| BYTE | 8-bit unsigned |
| SINT | 8-bit signed |
| USINT | 8-bit unsigned |
| INT | 16-bit signed |
| UINT | 16-bit unsigned |
| DINT | 32-bit signed |
| UDINT | 32-bit unsigned |
| LINT | 64-bit signed |
| ULINT | 64-bit unsigned |
| REAL | 32-bit float |
| LREAL | 64-bit float |
| STRING | Text string |
| TIME, DATE, DT, TOD | Time types (as UDINT) |
| WORD, DWORD, LWORD | Bit string types |
Note: Complex types (arrays, structures) are not fully supported for reading. The server will return type information but may not be able to read the value directly.
Troubleshooting
Connection Errors
If you see connection errors:
- Verify TwinCAT is running: Check that TwinCAT System Service is running and the PLC is in Run mode
- Check AMS Net ID: Ensure the AMS Net ID in the server matches your system (run
hostnamein TwinCAT XAE to find it) - Verify ADS routing: For remote connections, ensure ADS routes are configured on both systems
- Check firewall: ADS uses TCP port 48898 by default
Symbol Not Found
If symbols are not found:
- Ensure the PLC project is activated and running
- Check the exact symbol name including namespace (e.g.,
MAIN.,GVL.) - Symbol names are case-sensitive
- Try
beckhoff_list_symbolswith a filter to find the correct name
License
MIT License
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。