# 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`: ```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 设备时传 `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 设备创建调用通用 `{data_collector_base_url}/api/collector/device`,MCP 固定传 `type=bacnet`、`device_type=1`。可选默认值包括:`port=47808`、`bacnet_net=0`、`asp_ip=""`、`timeout=3`、`is_persistent=false`、`group_id=0`、`alarm_interval=90`、`collect_interval=5`。 批量创建 BACnet 点位时传 `points` 数组,每个点位必须包含: - `points[].device_id`:所属设备 ID - `points[].object_type`:BACnet 对象类型,如 `AnalogInput`;也支持 `analog-input`、`analogInput` 等常见写法,MCP 会在调用上游前规范为 `AnalogInput` 这类格式 - `points[].object_id`:BACnet 对象实例号,范围 `0..4194303` - `points[].name` 或 `points[].object_name`:点位名称或 BACnet 对象名 BACnet 点位创建调用 `{data_collector_base_url}/api/collector/bacnet/point/add_collect_point`。MCP 会将每个点位包装成汇采接口要求的 `{device_id, points:[...]}`。可选默认值包括:`point_id=""`、`priority=null`、`units=""`、`value_type=0`、`group_id=0`、`scale_ratio=1`、`value_offset=0`、`describe=""`。 常见点表数据类型映射: | 点表类型 | 汇采 `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 对象类型,如 `AnalogInput`、`analog-input`、`analogInput`;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_IP`、`BACNET_BBMD_PORT`、`BACNET_BBMD_TTL`、`BACNET_BBMD_WHOIS_TIMEOUT`、`BACNET_BBMD_LOW_LIMIT`、`BACNET_BBMD_HIGH_LIMIT`、`BACNET_BBMD_LOCAL_DEVICE_ID`、`BACNET_LOCAL_IP`、`BACNET_LOCAL_PORT`。响应透传网关 JSON,`code=0` 表示成功,`data.bbmd` 为本次 BBMD 请求配置,`data.devices[]` 为发现的 `I-Am` 设备列表,常见字段包括 `bacnet_device_id`、`ip`、`port`、`max_apdu`、`segmentation`、`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 ```