mcp-design.md 16 KB

Instrument Config MCP Design

1. 目标

基于现有配置接口,使用 FastMCP 构建一个面向大模型的查询型 MCP 服务。

第一版目标:

  • 提供位置、系统、设备类型、仪表类型的查询能力
  • 提供设备、仪表的正式搜索能力
  • 支持通过 project_key 选择项目环境
  • 保持接口原有分页行为,默认请求 page_size=100
  • id 作为正式查询参数,避免名称重名带来的歧义

第一版不做的事情:

  • 不做名称到 id 的自动猜测
  • 不做复杂缓存失效策略
  • 不做写接口
  • 不做额外的业务推断型工具

2. 设计原则

2.1 查询参数以 ID 为准

正式搜索工具统一使用 id 参数,而不是名称参数。

所有业务工具还必须显式传入 project_key,用于定位项目配置和认证信息。

原因:

  • 名称可能重名
  • 树结构下可能出现同名节点
  • 大模型如果基于名称做自动选择,容易产生静默误查
  • 接口本身的正式过滤条件也是以 id 为主

因此第一版采用两层结构:

  • 列表工具:返回候选项和 id
  • 搜索工具:使用 id 发起正式查询

2.2 列表工具负责“给 ID”

第一版不单独提供 find_locationsfind_systems 这类解析工具。

原因:

  • 已有列表接口足够支撑“先查候选,再拿 id”流程
  • 减少工具数量,避免能力重复
  • 保持 MCP 工具边界清晰

2.3 分页保持后端原样

所有分页接口都保留后端原有分页行为:

  • 默认请求 page_size=100
  • 由调用方显式传入 page_num
  • MCP 不自动翻页

这样可以避免一次调用返回过大数据,也更符合后端原始接口行为。

当某一页没有找到目标结果时,MCP 应明确提示:

  • 当前只查询了指定页
  • 如需继续查找,可以继续传更大的 page_num

2.4 返回结构尽量保持后端原样

第一版不对树结构或接口返回结果做额外整理:

  • 不做扁平化
  • 不做去重
  • 不做额外路径拼接
  • 不做字段重命名

MCP 以“尽量接近后端返回”的方式对外暴露结果,只补充必要的工具层说明。

3. 接口分析

3.0 项目配置与认证

项目配置来自 sys_config 中的 mcp_project_data_projects

单个项目配置至少包含:

  • project_key
  • project_name
  • base_url
  • username
  • password
  • enabled

业务请求流程:

  1. 通过 project_key 找到项目配置
  2. 从项目配置读取 base_urlusernamepassword
  3. 先读取当前项目的 token 缓存
  4. 如缓存不存在或已过期,则调用登录接口重新获取 token
  5. 使用获取到的 token 访问配置接口

登录接口:

  • POST {base_url}/api/ai/auth/password_login

登录成功条件:

  • 返回 JSON
  • errcode00.0
  • 响应中包含 token

业务请求认证方式:

  • 请求头使用 Authorization
  • header 的值直接使用 token 原文
  • 不额外拼接 Bearer 前缀

token 缓存策略:

  • project_key 单独缓存
  • 缓存内容存储在 sys_config
  • expire_at 仍未过期时直接复用
  • 当缓存失效时重新登录并回写缓存

3.1 位置搜索

接口:POST /api/configapi/location/list

用途:

  • 按关键字搜索位置
  • keyword 为空时可全量拉取

输入特点:

  • 支持分页
  • 返回树结构

输出特点:

  • 节点包含 children
  • 节点包含 idcodefull_codenameparent_idlevel

MCP 处理建议:

  • 默认请求 page_size=100
  • 保持树结构原样返回
  • id 作为后续设备/仪表查询参数

3.2 仪表搜索

接口:POST /api/configapi/meter/list

用途:

  • 按安装位置、仪表类型、状态、测量对象关联维度搜索仪表
  • keyword 为空时可全量拉取

主要过滤字段:

  • location_id
  • show_below
  • keyword
  • meter_type_id
  • measurement_location_ids
  • measurement_system_ids
  • measurement_device_type_ids
  • status

字段语义:

  • location_id:仪表安装位置
  • measurement_location_ids:仪表关联的测量位置
  • measurement_system_ids:仪表关联的测量系统
  • measurement_device_type_ids:仪表关联的测量设备类型

注意:

  • 安装位置和测量位置不是一个概念
  • 返回中存在父子仪表关系:parent_idparent_name
  • keyword 更适合定义为“模糊匹配名称、编号等文本字段”

关于 measurement_flag 的当前工作假设:

  • 0:无
  • 1:设备
  • 2:其他非设备对象

该语义来自现有页面文案和样例数据,但后续若后端给出正式定义,应以正式定义为准。

3.3 系统树

接口:POST /api/configapi/system/tree

用途:

  • 获取系统类型树和系统节点

结构特点:

  • type=1:系统类型
  • type=2:系统

MCP 处理建议:

  • 保持树结构原样返回
  • 不额外补充扁平节点列表

3.4 系统列表

接口:POST /api/configapi/system/list

用途:

  • 按系统类型查询系统列表
  • 可作为系统全量列表接口使用

主要过滤字段:

  • system_type_id
  • show_below

MCP 处理建议:

  • 默认请求 page_size=100
  • 用于给设备搜索或其他工具提供系统 id

3.5 设备类型列表

接口:POST /api/configapi/devicetype/list

用途:

  • 返回设备类型字典

特点:

  • 当前支持 page_size=-1 全量返回
  • 非分页核心接口

3.6 设备搜索

接口:POST /api/configapi/device/list

用途:

  • 按位置、系统、设备类型、关键字查询设备
  • keyword 为空时可全量拉取

主要过滤字段:

  • location_id
  • show_below
  • keyword
  • system_ids
  • device_type_ids

MCP 处理建议:

  • 默认请求 page_size=100
  • 使用 id 过滤
  • 返回结构尽量保持后端原样

3.7 仪表类型列表

接口:POST /api/configapi/metertype/list

用途:

  • 返回仪表类型字典

特点:

  • 当前支持 page_size=-1 全量返回
  • 供仪表搜索使用

3.8 拓扑详情与节点数据

接口:

  • POST /api/configapi/topo/get
  • POST /api/configapi/topo/get_data

用途:

  • topo/get:读取单张拓扑结构、data_optionsdimension_config
  • topo/get_data:读取单张拓扑在某个展示维度和单个时间点下的节点数据

关键约束:

  • topo/get_data 一次只支持一个拓扑、一个 display、一个时间点
  • display=instant 不带时间参数
  • display=accu 需要显式传 accu_stepts
  • 不能直接返回时间范围数据,需要由 MCP 层做多次调用聚合

当前 MCP 处理:

  • topology.get_node 查询时实时调用 1 次 instant
  • 再调用 12 次小时累计和 7 次日累计
  • 节点值按 node_id 直接匹配

3.9 拓扑分组配置

来源字段:

  • topo/get 返回中的 dimension_config

适用范围:

  • topology_type=2 的拓扑图

结构特点:

  • dimension_config.dimensions 表示分组配置
  • dimension_config.filter 表示筛选配置
  • filter.conditions[].fields 存储业务对象 ID 列表,需要额外解析名称

枚举语义:

  • order: 1=顺序2=逆序
  • filter_type: 1=所有2=任一
  • match_type: 1=等于2=不等于3=包含4=不包含

对象类型语义:

  • 11=位置
  • 12=系统类型
  • 13=系统
  • 14=设备类型
  • 15=设备
  • 16=仪表类型
  • 17=仪表型号
  • 18=仪表
  • 19=拓扑图分组
  • 20=拓扑图

名称解析来源:

  • 11 -> list_locations
  • 12 -> list_system_tree
  • 13 -> list_systems
  • 14 -> list_device_types
  • 15 -> search_devices
  • 16 -> list_meter_types
  • 18 -> search_meters
  • 19 -> 本地拓扑分组缓存
  • 20 -> 本地拓扑注册缓存

当前限制:

  • 17(仪表型号)暂未实现名称解析,需要后续补接口或规则

4. 业务关系梳理

4.1 位置

  • 位置是树结构
  • 设备安装在位置上
  • 仪表也安装在位置上

4.2 系统

  • 系统存在系统类型和具体系统两层
  • 设备可归属某系统
  • 仪表可关联某系统作为测量对象

4.3 设备

  • 设备有设备类型
  • 设备属于位置和系统

4.4 仪表

  • 仪表有仪表类型
  • 仪表存在父子层级
  • 仪表安装在某位置
  • 仪表可以关联位置、系统、设备类型等测量对象维度

5. 第一版 MCP 工具清单

第一版只保留必要工具,不做额外封装工具。

5.1 list_locations

用途:

  • 查询位置候选项
  • 为后续正式搜索提供 location_id

建议入参:

  • project_key: str
  • keyword: str | None = None

内部调用:

  • /api/configapi/location/list

返回字段:

  • id
  • name
  • code
  • full_code
  • parent_id
  • level

备注:

  • keyword 为空时全量拉取
  • 返回后端原始树结构

5.2 list_system_tree

用途:

  • 获取系统类型和系统的树结构信息

建议入参:

  • project_key: str

内部调用:

  • /api/configapi/system/tree

返回字段:

  • 保持后端原始字段结构

5.3 list_systems

用途:

  • 获取系统列表
  • 为设备或其他查询提供 system_id

建议入参:

  • project_key: str
  • page_size: int = 100
  • page_num: int = 1
  • system_type_id: int = 0
  • show_below: bool = True

内部调用:

  • /api/configapi/system/list

返回字段:

  • id
  • name
  • code
  • system_type_id
  • system_type_name

5.4 list_device_types

用途:

  • 获取设备类型列表

建议入参:

  • project_key: str

内部调用:

  • /api/configapi/devicetype/list

返回字段:

  • id
  • name
  • code

5.5 list_meter_types

用途:

  • 获取仪表类型列表

建议入参:

  • project_key: str

内部调用:

  • /api/configapi/metertype/list

返回字段:

  • id
  • name
  • code

5.6 search_devices

用途:

  • 按正式过滤条件查询设备

建议入参:

  • project_key: str
  • page_size: int = 100
  • page_num: int = 1
  • keyword: str | None = None
  • location_id: int = 0
  • show_below: bool = True
  • system_ids: list[int] | None = None
  • device_type_ids: list[int] | None = None

内部调用:

  • /api/configapi/device/list

返回字段:

  • id
  • name
  • code
  • device_type_id
  • device_type_name
  • location_id
  • location_name
  • system_id
  • system_name
  • parent_id
  • is_group
  • location_full_code

备注:

  • keyword 为空时表示不按关键字过滤
  • 若当前页未找到目标结果,可继续传更大的 page_num

5.7 search_meters

用途:

  • 按正式过滤条件查询仪表

建议入参:

  • project_key: str
  • page_size: int = 100
  • page_num: int = 1
  • keyword: str | None = None
  • location_id: int = 0
  • show_below: bool = True
  • meter_type_id: int = 0
  • measurement_location_ids: list[int] | None = None
  • measurement_system_ids: list[int] | None = None
  • measurement_device_type_ids: list[int] | None = None
  • status: int | None = None

内部调用:

  • /api/configapi/meter/list

返回字段:

  • id
  • name
  • code
  • meter_type_id
  • meter_type_name
  • location_id
  • location_name
  • parent_id
  • parent_name
  • measurement_flag
  • measurement_device_id
  • measurement_device_name
  • measurement_location_id
  • measurement_location_name
  • measurement_system_id
  • measurement_system_name
  • measurement_device_type_id
  • measurement_device_type_name
  • status
  • meter_model_id
  • meter_model_name
  • meter_model_brand
  • code_prefix

备注:

  • keyword 为空时表示不按关键字过滤
  • 若当前页未找到目标结果,可继续传更大的 page_num
  • 第一版不对 measurement_flag 做强校验,只透传查询条件

5.8 topology.group_list

用途:

  • 返回缓存中的拓扑分组树

建议入参:

  • project_key: str

5.9 topology.list

用途:

  • 返回缓存中的拓扑列表
  • 可按分组或对象类型过滤

建议入参:

  • project_key: str
  • group_id: int | None = None
  • object_type_code: int | None = None

5.10 topology.get_node

用途:

  • 获取一个节点及其直接邻域
  • 同时返回当前拓扑的节点实时值和累计值窗口

建议入参:

  • project_key: str
  • topology_id: int
  • node_id: str = 'root'
  • include_siblings: bool = True
  • include_children: bool = True

返回结构:

  • data_window
  • topology
  • node
  • parents
  • children
  • siblings

说明:

  • topology 中包含 data_optionsmetric_definitionsdimension_config
  • node.data.instant 为实时值
  • node.data.accu.hourly 为最近 12 个整点小时累计值
  • node.data.accu.daily 为最近 7 个日零点累计值

5.11 topology.get_group_config

用途:

  • 返回 type=2 拓扑图的分组配置和筛选配置

建议入参:

  • project_key: str
  • topology_id: int

返回结构:

  • supported
  • raw_dimension_config
  • groupings
  • filter

说明:

  • groupingsdimension_config.dimensions 派生
  • filterdimension_config.filter 派生
  • filter.conditions[].field_items 为解析后的 id + name

5.12 topology.find_context

用途:

  • 按实体快速反查命中的拓扑节点上下文

建议入参:

  • project_key: str
  • entity_type: str
  • entity_id: int
  • topology_id: int | None = None
  • include_siblings: bool = True
  • ancestor_depth: int = 5
  • descendant_depth: int = 2

6. MCP 调用流程建议

6.1 按位置查仪表

步骤:

  1. 调用 list_locations(keyword=...) 需要传入 project_key
  2. 从返回结果中选择目标 location_id
  3. 调用 search_meters(project_key=..., location_id=..., show_below=...)

6.2 按系统查设备

步骤:

  1. 调用 list_systems(project_key=..., ...)list_system_tree(project_key=...)
  2. 从返回结果中选择目标 system_id
  3. 调用 search_devices(project_key=..., system_ids=[...])

6.3 按设备类型和系统查仪表

步骤:

  1. 调用 list_device_types(project_key=...) 获取 device_type_id
  2. 调用 list_systems(project_key=..., ...) 获取 system_id
  3. 调用 search_meters(project_key=..., measurement_device_type_ids=[...], measurement_system_ids=[...])

7. 分页设计

第一版不做自动翻页。

约定:

  • 如果接口支持分页,则默认使用 page_size=100
  • 由调用方显式指定 page_num
  • MCP 返回当前页原始结果

适用接口:

  • location/list
  • system/list
  • device/list
  • meter/list

不涉及分页控制的接口:

  • system/tree
  • devicetype/list
  • metertype/list

8. 返回结果规范

第一版建议尽量保持后端接口的返回结构:

  • 保留 state
  • 保留 state_info
  • 保留 data
  • 不重组为统一的 items 结构

这样可以降低实现复杂度,也便于和后端接口文档直接对照。

9. 错误处理策略

第一版建议采用简单直接的错误策略。

9.1 HTTP 错误

  • 请求失败时直接抛出错误
  • 错误信息包含接口路径、状态码、响应体摘要

9.2 业务错误

  • 当返回 state != 0 时视为业务失败
  • 错误中包含 statestate_info

9.3 空结果

  • 空结果不视为错误
  • 保持后端原始返回结构,只是结果列表为空

10. FastMCP 实现建议

建议采用三层结构。

10.1 HTTP Client 层

职责:

  • 发送 HTTP 请求
  • 注入公共参数,如 operator
  • 根据 project_key 定位项目配置
  • 处理登录和 token 获取
  • 处理响应状态和业务状态
  • 透传分页参数

建议模块:

  • client.py

10.2 Service 层

职责:

  • 封装接口调用
  • 保持后端返回结构
  • 只做必要的参数组织

建议模块:

  • services/location.py
  • services/system.py
  • services/device.py
  • services/meter.py

10.3 MCP Tool 层

职责:

  • 暴露 FastMCP 工具
  • 定义工具参数和返回结果

建议模块:

  • server.py

11. 第一版暂不处理的问题

以下能力可在后续版本再补:

  • 按名称自动解析 id
  • 仪表型号列表及按型号查询
  • 本地缓存和缓存刷新机制
  • 更细的参数校验
  • 返回结果裁剪和排序策略

12. 建议的下一步

实现顺序建议如下:

  1. 搭建 FastMCP 基础服务
  2. 实现通用 HTTP Client 和分页参数透传
  3. 实现 list_locationslist_systemslist_device_typeslist_meter_types
  4. 实现 search_devicessearch_meters
  5. 增加少量联调脚本或示例调用