README.md 9.6 KB

Data Collector MCP

基于 FastMCP 的采集器 MCP 服务。

首期提供:

  • project.list
  • modbus.point_collect_test
  • bacnet.point_collect_test
  • bacnet.point_search
  • bacnet.bbmd_whois
  • collector.modbus_device_create
  • collector.modbus_point_create
  • collector.s7_device_create
  • collector.s7_point_create
  • collector.bacnet_device_create
  • collector.bacnet_device_edit
  • collector.bacnet_point_create
  • collector.bacnet_point_edit
  • collector.device_list

默认 MCP 地址:http://127.0.0.1:8501/mcp

配置

服务使用 PostgreSQL,通过 DATABASE_URL 连接数据库。

项目配置存放在 sys_config 表中,key 为 mcp_data_collector_projects

如果需要手动建表,推荐使用 PostgreSQL IDENTITY,不要直接引用未创建的 sys_config_id_seq

CREATE TABLE IF NOT EXISTS public.sys_config (
    id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    key character varying(128) NOT NULL UNIQUE,
    value json NOT NULL
);

也可以不手动建表,服务启动并访问配置时会通过 SQLAlchemy 自动创建表,但数据库用户需要有建表权限。

[
  {
    "project_key": "dev-01",
    "project_name": "DEV开发环境",
    "base_url": "http://127.0.0.1:8000",
    "data_collector_base_url": "http://127.0.0.1:32080",
    "username": "admin",
    "password": "123456",
    "enabled": true
  }
]

data_collector_base_url 缺失时会直接报错,不回退到 base_url

启动

python -m data_collector_mcp

可选环境变量:

  • DATABASE_URL,必填
  • MCP_HOST,默认 0.0.0.0
  • MCP_PORT,默认 8501
  • MCP_PATH,默认 /mcp
  • UPSTREAM_REQUEST_TIMEOUT,默认 60
  • MCP_LOG_ARGUMENT_MAX_LENGTH,默认 10000,MCP tool 入参日志最大长度;超出后截断

服务会为每次 MCP tool 调用输出结构化 JSON 日志,包含 trace_id、工具名、入参、开始时间、结束时间和耗时。passwordtokenauthorizationsecret 等敏感字段会自动脱敏。

测试

python -m unittest discover -s tests

MCP 连通性测试

先启动 MCP 服务:

$env:DATABASE_URL = "postgresql+psycopg2://postgres:password@127.0.0.1:5432/data_collector_mcp"
& ".venv\Scripts\python.exe" -m data_collector_mcp

另开一个 PowerShell 窗口,列出 tools:

& ".venv\Scripts\python.exe" tools\test_mcp_call.py --list-tools

调用 project.list

& ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool project.list

调用 collector.device_list

& ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool collector.device_list --args '{"project_key":"dev-01","num_points":false}'

测试脚本会先打印本次 MCP tool 请求 payload,例如:

{
  "request": {
    "url": "http://127.0.0.1:8501/mcp",
    "tool": "collector.device_list",
    "arguments": {
      "project_key": "dev-01",
      "num_points": false
    }
  }
}

批量创建 Modbus 设备时传 devices 数组,每个设备必须包含:

  • devices[].device_type:协议类型,1=TCP2=RTU3=UDP4=RTU OVER TCP5=RTU OVER UDP
  • devices[].ip:IP 地址
  • devices[].port:端口号
  • devices[].name:设备名称
  • devices[].slave_id:Modbus 从站 ID
  • devices[].word_order:字顺序,1=Big Endian2=Small Endian
  • devices[].byte_order:字节顺序,1=Big Endian2=Small Endian
  • devices[].address_base:地址基准,会转换为汇采接口的 address_offset

设备创建工具会依次调用汇采创建设备接口,全部创建调用完成后内部调用一次设备列表并匹配每个设备的 device_id;如果匹配到多个设备,选择 id 最大的。

批量创建 Modbus 点位时传 points 数组,每个点位必须包含:

  • points[].device_id:所属设备 ID
  • points[].name:点位名称
  • points[].address:寄存器地址
  • points[].type:数据类型
  • points[].func_codepoints[].register_type:寄存器类型

批量创建 S7 设备时传 devices 数组,每个设备必须包含:

  • devices[].name:设备名称
  • devices[].ip:IP 地址
  • devices[].rock:机架号
  • devices[].slot:槽号

S7 设备可选默认值包括:port=102device_type=1tsap_conn_type=PGis_persistent=falsedevice_group_id=0timeout=3alarm_interval=90collect_interval=5device_type 使用数字枚举:1=S7-12002=S7-15003=S7-Smart200;如果来源是网关读取工具的字符串 S7-Smart200,创建设备时应转换为 device_type=3tsap_conn_type 不传时统一使用 PG,只有现场测试或扫描确认需要 OP/BASIC 时才显式传。

批量创建 S7 点位时传 points 数组,每个点位必须包含:

  • points[].device_id:所属设备 ID
  • points[].name:点位名称
  • points[].address:S7 地址
  • points[].data_typepoints[].type:数据类型
  • points[].register_typepoints[].register_area:寄存器区域

S7 点位创建使用汇采格式,不是网关读取格式;不要把网关点位的 area/start/bit 直接传给 collector.s7_point_create。常见点表类型映射:BOOL=>boolFLOAT/REAL=>float32SHORT/INT=>int16WORD=>uint16DWORD=>uint32DINT/LONG=>int32DOUBLE/LREAL=>float64。常见 CSV 区域映射:I=>IQ/QD=>QM/MD=>MVD/VW=>VDB/DBD/DBW/DBX=>DB。BOOL 点把地址列和位地址列合并为 address="byte.bit";DB BOOL 使用 address="db.byte.bit";非 BOOL 使用字节地址,DB 非 BOOL 使用 address="db.byte"

批量创建 BACnet 设备时传 devices 数组,每个设备必须包含:

  • devices[].name:设备名称
  • devices[].ip:BACnet/IP 设备地址
  • devices[].bacnet_device_id:BACnet 设备对象实例号,范围 0..4194303

BACnet 设备创建调用通用 {data_collector_base_url}/api/collector/device,MCP 固定传 type=bacnetdevice_type=1。可选默认值包括:port=47808bacnet_net=0asp_ip=""timeout=3is_persistent=falsegroup_id=0alarm_interval=90collect_interval=5

批量创建 BACnet 点位时传 points 数组,每个点位必须包含:

  • points[].device_id:所属设备 ID
  • points[].object_type:BACnet 对象类型,如 AnalogInput;也支持 analog-inputanalogInput 等常见写法,MCP 会在调用上游前规范为 AnalogInput 这类格式
  • points[].object_id:BACnet 对象实例号,范围 0..4194303
  • points[].namepoints[].object_name:点位名称或 BACnet 对象名

BACnet 点位创建调用 {data_collector_base_url}/api/collector/bacnet/point/add_collect_point。MCP 会将每个点位包装成汇采接口要求的 {device_id, points:[...]}。可选默认值包括:point_id=""priority=nullunits=""value_type=0group_id=0scale_ratio=1value_offset=0describe=""

常见点表数据类型映射:

点表类型 汇采 type
BOOL / BOOLEAN bool
SHORT int16
WORD uint16
LONG int32
DWORD uint32
FLOAT / REAL float32
DOUBLE float64
LONGLONG int64
QWORD uint64

register_type 可用:

register_type 转换为 func_code
coil 1
discrete_input 2
holding_register 3
input_register 4

BACnet 网关工具

bacnet.point_search 用于搜索 BACnet/IP 设备点位,调用 {base_url}/api/dc-gateway/bacnet/search_points。参数:

  • project_key:项目 key,先通过 project.list 获取
  • ip:BACnet/IP 设备地址
  • bacnet_device_id:BACnet 设备对象实例号,范围 0..4194303
  • port:BACnet/IP UDP 端口,默认 47808

bacnet.point_collect_test 用于读取指定 BACnet 点位的 present-value,调用 {base_url}/api/dc-gateway/bacnet/read_points。除设备字段外,还需要传 points 数组:

  • points[].object_type:BACnet 对象类型,如 AnalogInputanalog-inputanalogInput;MCP 会统一规范为 AnalogInput 这类格式后再读取
  • points[].object_id:BACnet 对象实例号,范围 0..4194303

bacnet.bbmd_whois 用于通过 BBMD 执行 BACnet/IP Who-Is 设备发现,调用 {base_url}/api/dc-gateway/bacnet/bbmd/whois。参数只有 project_key,MCP 不发送请求体。BBMD 地址、端口、TTL、Who-Is 等待超时、设备号范围和本机绑定地址由采集网关环境变量配置,包括 BACNET_BBMD_IPBACNET_BBMD_PORTBACNET_BBMD_TTLBACNET_BBMD_WHOIS_TIMEOUTBACNET_BBMD_LOW_LIMITBACNET_BBMD_HIGH_LIMITBACNET_BBMD_LOCAL_DEVICE_IDBACNET_LOCAL_IPBACNET_LOCAL_PORT。响应透传网关 JSON,code=0 表示成功,data.bbmd 为本次 BBMD 请求配置,data.devices[] 为发现的 I-Am 设备列表,常见字段包括 bacnet_device_idipportmax_apdusegmentationvendor_id

调用示例:

& ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool bacnet.point_search --args '{"project_key":"dev-01","ip":"192.168.75.240","bacnet_device_id":12345}'
& ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool bacnet.point_collect_test --args '{"project_key":"dev-01","ip":"192.168.75.240","bacnet_device_id":12345,"points":[{"object_type":"AnalogInput","object_id":1}]}'
& ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool bacnet.bbmd_whois --args '{"project_key":"dev-01"}'

调用其他 MCP URL:

& ".venv\Scripts\python.exe" tools\test_mcp_call.py --url "http://127.0.0.1:8501/mcp" --tool project.list