MCP服务器

一个CLI优先的MCP服务器,通过ADS连接到Beckhoff TwinCAT PLC,并支持LLM代理的按需读取和受保护的写入确认功能。

  • by hugo-palafox
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 hugo-palafox/ads-mcp-server

使用说明

ads-mcp-server

CLI-first MCP server that connects to Beckhoff TwinCAT PLCs via ADS and exposes on-demand reads plus guarded write confirmation for LLM agents.

Scope

  • ADS read access and guarded write confirmation flow
  • On-demand reads only
  • Machine config in JSON (data/machines)
  • Curated memory JSON (data/memory)
  • MCP tool surface for machine, catalog, and memory

Install

pip install -e .

CLI commands

Use documentation/example addresses in public configurations and replace them with values for your own lab environment.

ads-mcp setup-machine --machine Machine1 --ip 127.0.0.1 --ams-net-id 192.168.1.100.1.1 --ads-port 851
ads-mcp set-write-permission --machine Machine1 --enabled
ads-mcp set-write-permission --machine Machine1 --disabled
ads-mcp discover --machine Machine1
ads-mcp list-groups --machine Machine1
ads-mcp list-tags --machine Machine1
ads-mcp list-tags --machine Machine1 --group Globals
ads-mcp memory add-tag --machine Machine1 --tag Globals.bRun
ads-mcp memory add-group --machine Machine1 --group Globals
ads-mcp memory remove-tag --machine Machine1 --tag Globals.bRun
ads-mcp memory list --machine Machine1
ads-mcp memory clear --machine Machine1
ads-mcp read --machine Machine1 --tag Globals.bRun
ads-mcp read-memory --machine Machine1
ads-mcp serve

Notes

  • pyads is required for live PLC communication.
  • PLC writes require two-step confirmation (request_tag_write then confirm_tag_write) and are blocked unless:
    • machine config sets mcp.read_only to false
    • resolved tag exists in discovered_tags
    • resolved tag name contains button (case-insensitive)

Write example (MCP tools)

Writes are exposed through MCP tools (not direct CLI write commands).

  1. Request write:
{
  "tool": "request_tag_write",
  "args": {
    "machine_id": "Machine1",
    "tag_name": "MAIN.StartButton",
    "value": true
  }
}

Response (example):

{
  "status": "pending",
  "request_id": "f0f4f8d3-7f2f-4e8a-93c8-6d8028e2d2e7",
  "resolved_tag_name": "MAIN.StartButton",
  "guardrail_passed": true
}
  1. Confirm write:
{
  "tool": "confirm_tag_write",
  "args": {
    "machine_id": "Machine1",
    "request_id": "f0f4f8d3-7f2f-4e8a-93c8-6d8028e2d2e7",
    "confirmed": true
  }
}

Response (example):

{
  "status": "written",
  "tag_name": "MAIN.StartButton"
}