6.2 KiB
空间只读 MCP v1 架构
决策摘要
首版 MCP 内嵌在现有 Go 服务中,使用标准库实现 HTTP/JSON-RPC 协议层,使用 pgx/v5 原生连接池访问 PostgreSQL/PostGIS。没有引入 MCP SDK、Web 框架或 ORM。
采用这一边界是因为当前只需要与不能配置协议版本的 SuperAgent 客户端协作:服务端实际提供 2025-06-18 版本标识、四个方法和同步 JSON 响应;版本字段和 Header 按已稳定接通的 SuperAgent 兼容档案处理,不作为拒绝门禁。业务复杂度位于固定空间查询、权限范围和安全语义,而不是协议框架。
SuperAgent 兼容档案
同一 SuperAgent 中已稳定启用的 th-hotel-simple-superagent 服务不会读取 initialize.params.protocolVersion,也不会读取或校验 MCP-Protocol-Version Header;它固定返回 2025-06-18,并正常处理 notifications/initialized、tools/list 与 tools/call。本项目对齐这一已验证的接入方式,目标是让 SuperAgent 能调用消防 MCP,而不是追求最新 MCP 版本。
initialize.params.protocolVersion 的缺失、空值、非字符串或其他值,不单独触发版本拒绝;可解析的 JSON-RPC initialize 始终返回 result.protocolVersion: "2025-06-18"。MCP-Protocol-Version Header 同样不作为拒绝门禁,SuperAgent 配置中无需增加版本或 Header 项。服务端并不因此实现或声明支持客户端填写的任意版本,也不把 2025-03-26、2025-11-25 等版本列为实现目标;固定返回 2025-06-18 是兼容响应。
上述兼容仅针对版本元数据。HTTP 方法、JSON-RPC 结构、独立 Bearer、Content-Type、非空 Origin、工具 schema、只读查询、服务端数据范围和结果脱敏等安全及业务边界仍由 Handler、Service 和 Repository 强制执行。initialize 结果可按实际字段记录 direct_success(值为 2025-06-18)或 compatibility_success(缺失或其他值被兼容处理),不得记录原始版本值。
模块关系
flowchart TD
APP["internal/app\n依赖装配与 readiness"]
H["internal/handler\nBearer、JSON-RPC、握手协商、schema、限流边界"]
S["internal/service\n查询边界、超时、结果语义"]
D["internal/domain\n稳定空间领域对象"]
R["internal/repository\npgxpool、固定参数化 PostGIS SQL"]
DB["8 张既有 PostGIS 表"]
APP --> H
APP --> S
APP --> R
H --> S
S --> D
S --> R
R --> D
R --> DB
Handler 不知道物理表名,Repository 不组织自然语言回答,Domain 不依赖 MCP 或 pgx。可信数据范围在应用装配时由配置传入 Service,并由 Repository 在 SQL 中应用:默认 town_allowlist 使用参数化镇街数组过滤;显式 all 使用服务端布尔参数放开镇街过滤。范围选择不进入工具 schema,模型无法扩大权限。
数据映射
| 领域结果 | 物理表 |
|---|---|
| 地名候选 | 以下 8 张表的名称、镇街、村庄和几何字段 |
| 网格上下文、责任中队 | st_2_fanghuowangge |
| 水源候选 | st_2_mpslfh_t_slfh_syd、st_2_xianyouxushuichiguan |
| 指挥部候选设施 | st_2_fanghuojianchazhan、st_2_fanghuoliaowangshao |
| 通道候选 | st_2_xianyoufanghuotongdao |
| 风险区域 | st_2_mudifenqu_mian、st_2_linqugongkuangqiye |
姓名、联系电话和值班人员字段不进入领域结果,也没有出现在查询 SELECT 列表中。
空间约束
- MCP 入参固定为 WGS84 经纬度。
- 地名搜索是坐标查询前的候选发现:记录点直接返回二维坐标;线使用首个组成线的起点,面使用
ST_PointOnSurface产生代表点,并以location_kind明确区分。代表点不得自动升级为用户确认的演练点。 - 防火通道原始
geom已确认混合二维与 Z 维度,导入层必须使用不限定 typmod 的geometry保存原始事实。距离/最近点等 MCP v1 运算按二维地表语义解释;若底层函数需要降维,只能在只读查询或派生层显式处理,不得回写或静默修改原始几何。 - 启用前要求实库所有非空几何 SRID 为 4326、类型符合表用途且坐标位于 WGS84 合法范围;这些属于硬门禁。
- 点到点、点到线、点到面距离使用 PostGIS
geography米制计算。 - 面覆盖使用
ST_Covers,边界上的点也视为位于网格/风险区内。 - SQL 同时检查 SRID、类型和有效性。无效或空几何不自动修复、不改写原始事实,而是从全部 MCP 查询中排除;readiness 和工具结果明确告警结果可能不完整。readiness 发现异常类型、非 4326 SRID 或越界坐标时仍拒绝启用。
- 2026-09-05 实库 audit 发现防火网格 4 条、林区工矿企业 4 条、墓地坟区 27 条无效面几何。用户选择首版排除这 35 条记录,后续如需修复必须在派生副本中审查,不覆盖原始
geom。 - 距离结果只是地理邻近,不包含地形、路网、火势、天气和实时通行信息。
依赖决策
github.com/jackc/pgx/v5 v5.10.0 是当前唯一新增的直接依赖。项目只面向 PostgreSQL,并需要明确的连接池、context 和 PostgreSQL 参数行为,因此使用原生 pgxpool;空间计算仍全部由参数化 SQL/PostGIS 完成。
后续演进边界
- 动态用户/组织授权到位后,用可信身份解析器替换当前每 Token 的静态数据库全范围/镇街白名单,工具 schema 不增加可伪造的授权字段。
- 路线规划必须新增专门的图网络/地形数据和高风险 Spec,不能扩写当前通道候选工具的描述来冒充路线能力。
- 联系人字段如确需开放,必须有字段级权限、脱敏、审计和单独工具,不直接扩展当前结果。
- 写入、派遣或状态变更工具需要人工确认、幂等、审计和独立安全评审。