# Data Collector MCP 基于 FastMCP 的采集器 MCP 服务。 首期提供: - `project.list` - `modbus.raw_read` - `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`: ```sql 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 自动创建表,但数据库用户需要有建表权限。 ```json [ { "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`。 ## 启动 ```powershell 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`、工具名、入参、开始时间、结束时间和耗时。`password`、`token`、`authorization`、`secret` 等敏感字段会自动脱敏。 ## 测试 ```powershell python -m unittest discover -s tests ``` ## MCP 连通性测试 先启动 MCP 服务: ```powershell $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: ```powershell & ".venv\Scripts\python.exe" tools\test_mcp_call.py --list-tools ``` 调用 `project.list`: ```powershell & ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool project.list ``` 调用 `collector.device_list`: ```powershell & ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool collector.device_list --args '{"project_key":"dev-01","num_points":false}' ``` 测试脚本会先打印本次 MCP tool 请求 payload,例如: ```json { "request": { "url": "http://127.0.0.1:8501/mcp", "tool": "collector.device_list", "arguments": { "project_key": "dev-01", "num_points": false } } } ``` ## Modbus 网关工具 `modbus.raw_read` 用于执行原始 Modbus TCP 读取,调用 `{base_url}/api/dc-gateway/modbus/read`。参数包括 `project_key`、`ip`、`port`、`slave_id`、`read`;可选默认值包括 `device_type=ModbusTCP`、`word_byte_order=ABCD`、`address_base=0`。`read` 必须包含 `function_code`、`address`、`quantity`。该工具不解析业务值,只返回 `data.communication[]` 中的 Tx/Rx 原始报文;如需转换后的点位值,请使用 `modbus.point_collect_test`。 调用示例: ```powershell & ".venv\Scripts\python.exe" tools\test_mcp_call.py --tool modbus.raw_read --args '{"project_key":"dev-01","ip":"192.168.75.240","port":502,"slave_id":1,"read":{"function_code":3,"address":0,"quantity":4}}' ``` 批量创建 Modbus 设备时传 `devices` 数组,每个设备必须包含: - `devices[].device_type`:协议类型,`1=TCP`、`2=RTU`、`3=UDP`、`4=RTU OVER TCP`、`5=RTU OVER UDP` - `devices[].ip`:IP 地址 - `devices[].port`:端口号 - `devices[].name`:设备名称 - `devices[].slave_id`:Modbus 从站 ID - `devices[].word_order`:字顺序,`1=Big Endian`、`2=Small Endian` - `devices[].byte_order`:字节顺序,`1=Big Endian`、`2=Small Endian` - `devices[].address_base`:地址基准,会转换为汇采接口的 `address_offset` 设备创建工具会依次调用汇采创建设备接口,全部创建调用完成后内部调用一次设备列表并匹配每个设备的 `device_id`;如果匹配到多个设备,选择 `id` 最大的。 批量创建 Modbus 点位时传 `points` 数组,每个点位必须包含: - `points[].device_id`:所属设备 ID - `points[].name`:点位名称 - `points[].address`:寄存器地址 - `points[].type`:数据类型 - `points[].func_code` 或 `points[].register_type`:寄存器类型 批量创建 S7 设备时传 `devices` 数组,每个设备必须包含: - `devices[].name`:设备名称 - `devices[].ip`:IP 地址 - `devices[].rock`:机架号 - `devices[].slot`:槽号 S7 设备可选默认值包括:`port=102`、`device_type=1`、`tsap_conn_type=PG`、`is_persistent=false`、`device_group_id=0`、`timeout=3`、`alarm_interval=90`、`collect_interval=5`。`device_type` 使用数字枚举:`1=S7-1200`、`2=S7-1500`、`3=S7-Smart200`;如果来源是网关读取工具的字符串 `S7-Smart200`,创建设备时应转换为 `device_type=3`。`tsap_conn_type` 不传时统一使用 `PG`,只有现场测试或扫描确认需要 `OP`/`BASIC` 时才显式传。 批量创建 S7 点位时传 `points` 数组,每个点位必须包含: - `points[].device_id`:所属设备 ID - `points[].name`:点位名称 - `points[].address`:S7 地址 - `points[].data_type` 或 `points[].type`:数据类型 - `points[].register_type` 或 `points[].register_area`:寄存器区域 S7 点位创建使用汇采格式,不是网关读取格式;不要把网关点位的 `area/start/bit` 直接传给 `collector.s7_point_create`。常见点表类型映射:`BOOL=>bool`、`FLOAT/REAL=>float32`、`SHORT/INT=>int16`、`WORD=>uint16`、`DWORD=>uint32`、`DINT/LONG=>int32`、`DOUBLE/LREAL=>float64`。常见 CSV 区域映射:`I=>I`、`Q/QD=>Q`、`M/MD=>M`、`VD/VW=>V`、`DB/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 设备创建可选传 `port`、`bacnet_net`、`asp_ip` 等连接参数;不传时使用采集器默认值。创建结果会返回匹配到的设备 ID。 批量创建 BACnet 点位时传 `points` 数组,每个点位必须包含: - `points[].device_id`:所属设备 ID - `points[].object_type`:BACnet 对象类型,如 `AnalogInput`;也支持 `analog-input`、`analogInput` 等常见写法并会自动规范化 - `points[].object_id`:BACnet 对象实例号,范围 `0..4194303` - `points[].name` 或 `points[].object_name`:点位名称或 BACnet 对象名 BACnet 点位创建可选传 `point_id`、`priority`、`units`、`value_type`、`group_id`、`scale_ratio`、`value_offset`、`describe` 等字段。常见 `value_type`:`1=Boolean`、`2=Unsigned`、`3=Signed`、`4=Real`、`5=Double`、`6=Enumerated`。 常见点表数据类型映射: | 点表类型 | 汇采 `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 设备点位。参数: - `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`。除设备字段外,还需要传 `points` 数组: - `points[].object_type`:BACnet 对象类型,如 `AnalogInput`、`analog-input`、`analogInput`,会自动规范化 - `points[].object_id`:BACnet 对象实例号,范围 `0..4194303` `bacnet.bbmd_whois` 用于通过 BBMD 执行 BACnet/IP Who-Is 设备发现。参数只有 `project_key`;BBMD 连接参数由采集网关配置。响应透传网关 JSON,`code=0` 表示成功,`data.devices[]` 为发现的 BACnet 设备列表,常见字段包括 `bacnet_device_id`、`ip`、`port`、`vendor_id`。 调用示例: ```powershell & ".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: ```powershell & ".venv\Scripts\python.exe" tools\test_mcp_call.py --url "http://127.0.0.1:8501/mcp" --tool project.list ```