初始化第一版
This commit is contained in:
commit
8a6c31c14d
83 files changed
+14302
No files matched your search
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"format": "fire-safety-ymd-superagent-mcp-client/v1",
|
||||
"mcpServers": {
|
||||
"fire-safety-ymd-spatial-readonly": {
|
||||
"transport": "http",
|
||||
"protocolVersion": "2025-06-18",
|
||||
"url": "https://<fire-safety-server-domain>/mcp",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${FIRE_SAFETY_MCP_AUTH_TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
},
|
||||
"tools": {
|
||||
"allow": [
|
||||
"fire_safety_search_place_candidates",
|
||||
"fire_safety_resolve_incident_context",
|
||||
"fire_safety_find_nearby_water_sources",
|
||||
"fire_safety_find_command_post_candidates",
|
||||
"fire_safety_list_nearby_access_lines",
|
||||
"fire_safety_get_responsible_units",
|
||||
"fire_safety_find_nearby_risk_areas"
|
||||
],
|
||||
"writeTools": []
|
||||
},
|
||||
"runtimeNotes": {
|
||||
"authTokenSource": "Use a separate per-environment high-entropy secret; never reuse the SuperAgent Open API Key.",
|
||||
"scopeSource": "The all or town-allowlist data scope is configured on the fire-safety-ymd server and is never supplied by tool arguments.",
|
||||
"safety": "Results are planning evidence only. Invalid source geometries are excluded, so results may be incomplete. Availability, passability, command-post suitability, live team positions and assembly sites require field confirmation."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
# SuperAgent 空间只读 MCP 接入指南
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 状态 | 代码已实现;实库严格 readiness 与本地 7 工具冒烟已通过,公网/SuperAgent 联调待执行 |
|
||||
| Endpoint | `POST /mcp` |
|
||||
| MCP 版本 | `2025-06-18` |
|
||||
| 传输 | 单 JSON 请求/响应;不提供服务端 SSE |
|
||||
| 数据源 | PostgreSQL/PostGIS,固定只读查询 |
|
||||
|
||||
## 调用边界
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
SA["SuperAgent"] -->|"独立 MCP Bearer Token"| MCP["fire-safety-ymd /mcp"]
|
||||
MCP -->|"schema 校验、超时、可信数据范围"| SVC["SpatialService"]
|
||||
SVC -->|"固定参数化 SQL"| PG["PostgreSQL/PostGIS 只读角色"]
|
||||
PG --> SVC --> MCP --> SA
|
||||
```
|
||||
|
||||
SuperAgent Open API Key 用于本服务调用 SuperAgent;MCP Token 用于 SuperAgent 回调本服务。两者方向、权限和生命周期不同,必须使用不同 Secret。
|
||||
|
||||
## 首版工具
|
||||
|
||||
| 工具 | 数据表 | 能回答 | 不能回答 |
|
||||
| --- | --- | --- | --- |
|
||||
| `fire_safety_search_place_candidates` | 现有 8 张空间表 | 按名称、镇街或村庄搜索有界地点候选 | 任意地址地理编码、自动确定演练点 |
|
||||
| `fire_safety_resolve_incident_context` | 防火网格 | 点位所在网格、镇街、区域标签 | 实时火情、负责人电话 |
|
||||
| `fire_safety_find_nearby_water_sources` | 水源地、蓄水池 | 候选水源、距离、容量/源状态(有值时) | 当前可用、取水道路可达 |
|
||||
| `fire_safety_find_command_post_candidates` | 检查站、瞭望哨 | 附近候选设施 | 自动确定指挥部、安全性/容量结论 |
|
||||
| `fire_safety_list_nearby_access_lines` | 防火通道 | 附近已绘制通道、最近接入点 | 路线规划、车辆可通行、实时封路 |
|
||||
| `fire_safety_get_responsible_units` | 防火网格 | 责任中队名称 | 队伍实时位置、战备状态、集结点 |
|
||||
| `fire_safety_find_nearby_risk_areas` | 墓地坟区、林区工矿企业 | 周边风险区域与距离 | 实时危险程度 |
|
||||
|
||||
工具不会返回负责人、书记、队长、值班人员、电话或图片字段。
|
||||
|
||||
## 地名输入的最小流程
|
||||
|
||||
`fire_safety_search_place_candidates` 接受 `place_name` 和可选 `limit`,名称长度为 2 至 100 字符,默认返回 10 条、最多 20 条。它对现有业务记录的名称、镇街和村庄字段做不区分大小写的包含匹配,不是完整地名库,也不调用外部地图服务。
|
||||
|
||||
返回值包含:
|
||||
|
||||
- `matched_field`:命中了名称、镇街还是村庄。
|
||||
- `match_kind`:`exact` 或 `partial`。
|
||||
- `location_kind=recorded_point`:源记录本身是点。
|
||||
- `location_kind=representative_point`:源记录是线或面,只返回只读计算的代表点。
|
||||
|
||||
SuperAgent Profile 应遵循:
|
||||
|
||||
1. 用户只给地名时,先调用该工具,不直接猜测坐标。
|
||||
2. 无结果时,请用户补充“镇街 + 村庄 + 具体地标”或在地图上选点。
|
||||
3. 多个候选时按名称、类型、镇街和村庄列出,让用户选择;不能静默使用第一条。
|
||||
4. 即使只有一个候选,也先回显给用户确认,再把确认后的 WGS84 坐标交给其他空间工具。
|
||||
5. `representative_point` 不能描述为地点中心、入口或真实演练点。
|
||||
6. 工具返回 `source_records_with_invalid_geometries_are_excluded` 时,必须说明结果可能不完整;无结果只能表示在有效记录中没有找到。
|
||||
|
||||
可加入 SuperAgent 系统提示词的最小片段:
|
||||
|
||||
```text
|
||||
当用户没有经纬度但提供了地名时,先调用 fire_safety_search_place_candidates。
|
||||
搜索结果只是地点候选:无结果时请用户补充地名或地图选点;多结果时列出候选并请用户选择;不得静默选择第一条。
|
||||
任何候选都要先回显名称、类型、镇街、村庄和坐标供用户确认。location_kind=representative_point 时必须说明它只是线面记录的代表点,不能当作真实演练点。
|
||||
只有用户确认坐标后,才调用网格、水源、指挥部候选、防火通道、责任中队和风险区域工具。
|
||||
所有空间工具都会排除无效几何。看到 source_records_with_invalid_geometries_are_excluded 时,要说明结果可能不完整;不得把无结果解释为原始数据库确认不存在。
|
||||
```
|
||||
|
||||
## 配置顺序
|
||||
|
||||
1. 为数据库创建只授予所需表 `SELECT` 的独立角色。
|
||||
2. 在本地未提交的 `.env` 中填写 `.env.example` 新增的 `FIRE_SAFETY_POSTGIS_*` 配置,先保持 `FIRE_SAFETY_MCP_ENABLED=false`。
|
||||
3. 加载环境并执行只读 readiness probe:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
go run ./cmd/postgis-probe
|
||||
```
|
||||
|
||||
probe 只输出 PostGIS 版本、表行数、空/无效/越界几何计数、几何类型、SRID 和 GiST 索引状态,不输出业务记录、联系人、DSN 或 SQL。无效/空几何作为明确 warning 并从工具查询中排除,不阻塞 MCP;非 4326 SRID、异常类型或越界坐标仍阻塞启动。
|
||||
|
||||
4. 只有数据所有者确认所有几何确为 WGS84,且数据库通过单独、经审查的数据变更把非空几何元数据补充为 `SRID=4326` 后,才设置:
|
||||
|
||||
```text
|
||||
FIRE_SAFETY_POSTGIS_EXPECTED_SRID=4326
|
||||
```
|
||||
|
||||
如果 probe 显示 `SRID=0`,不要让应用在查询时静默 `ST_SetSRID`。本项目的数据提供方已确认源数据为 EPSG:4326 且无偏移;2026-09-05 已按 [`../operations/postgis-srid-4326.md`](../operations/postgis-srid-4326.md) 完成受控元数据迁移,迁移未改变坐标数值或丢弃 Z。重新导入原始 SQL 后仍需重新执行该迁移,不得假设导入文件自带 SRID。
|
||||
|
||||
5. 配置至少 32 个可打印 ASCII 字符的独立 MCP Token,并选择一种可信数据范围,最后启用 MCP。
|
||||
|
||||
若该 MCP 凭证获准读取当前数据库中 MCP 固定查询表的全部记录,使用显式全范围模式:
|
||||
|
||||
```text
|
||||
FIRE_SAFETY_MCP_AUTH_TOKEN=<独立高熵 Secret>
|
||||
FIRE_SAFETY_MCP_SCOPE_MODE=all
|
||||
FIRE_SAFETY_MCP_ALLOWED_TOWNS=
|
||||
FIRE_SAFETY_MCP_ENABLED=true
|
||||
```
|
||||
|
||||
若只获准读取部分镇街,保留默认白名单模式:
|
||||
|
||||
```text
|
||||
FIRE_SAFETY_MCP_AUTH_TOKEN=<独立高熵 Secret>
|
||||
FIRE_SAFETY_MCP_SCOPE_MODE=town_allowlist
|
||||
FIRE_SAFETY_MCP_ALLOWED_TOWNS=莒格庄镇,高陵镇
|
||||
FIRE_SAFETY_MCP_ENABLED=true
|
||||
```
|
||||
|
||||
`all` 表示当前配置数据库中 MCP 固定查询表的所有记录,包括镇街字段为空的记录;它不表示最终用户已获得动态授权。`all` 模式不能同时保留镇街列表,模型和 MCP 工具参数均不能改变服务端选择的范围。
|
||||
|
||||
6. 启动服务。启用 MCP 时,服务会在监听 HTTP 前执行 readiness:SRID、类型或坐标范围不符合要求时拒绝启动;无效/空几何会输出 warning 并由查询排除。
|
||||
|
||||
## 协议探测
|
||||
|
||||
真实 Token 只放环境变量,不写命令历史或文档:
|
||||
|
||||
```bash
|
||||
curl -sS http://127.0.0.1:8080/mcp \
|
||||
-H "Authorization: Bearer ${FIRE_SAFETY_MCP_AUTH_TOKEN}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"manual-probe","version":"1"}}}'
|
||||
```
|
||||
|
||||
随后发送 `notifications/initialized`、`tools/list` 和受控测试地名/坐标的 `tools/call`。联调不得使用真实火情或未授权精确坐标。
|
||||
|
||||
SuperAgent 侧配置模板见 [`superagent-mcp-client.example.json`](superagent-mcp-client.example.json)。
|
||||
|
||||
## 运行与安全说明
|
||||
|
||||
- `/mcp` 默认不注册;`GET /mcp` 返回 405,不提供 SSE stream。
|
||||
- 浏览器携带 `Origin` 的请求被拒绝,首版只支持服务到服务调用。
|
||||
- 数据范围由服务端配置注入;默认镇街白名单,数据库全范围必须显式选择,工具参数不能提供或扩大权限范围。
|
||||
- 数据库连接设置只读事务默认值和 statement/lock timeout;工具另有总超时、半径与数量限制。
|
||||
- 普通日志只记录 request ID、方法/工具名、耗时和结果类别,不记录坐标、参数或结果正文。
|
||||
- 所有工具结果包含 `source_records_with_invalid_geometries_are_excluded`;SuperAgent 必须把无结果表述为“有效记录中未找到”,不能据此断言原始数据库不存在相关记录。
|
||||
- HTTP 服务本身不终止 TLS;部署时必须通过受控网关或反向代理提供 HTTPS、网络白名单、限流和 Secret 轮换。
|
||||
|
||||
## 当前联调门禁
|
||||
|
||||
- 样例 SQL 不可执行,也不可提交;其中包含破坏性 DDL 和受限联系人数据。
|
||||
- 2026-09-05 已完成受控 SRID 元数据迁移和严格 audit:8 表共 4,055 条记录,4,048 条非空几何均为 SRID 4326,SRID/类型/范围硬门禁通过。7 条空几何、35 条无效面几何以及 7 张缺 GiST 索引表仍按预期告警;真实 `tools/call` 尚未执行,因此当前仍不能宣称 MCP 的业务结果已经联调验证。
|
||||
- 缺少适用于距离表达式的 GiST 索引时可做小数据开发联调,但生产前必须补齐并验证查询计划。
|
||||
- 地名包含匹配当前没有专用名称索引;真实数据量下先验证查询耗时,后续再决定标准地名表、别名词典或 `pg_trgm` 索引。
|
||||
- 用户身份、动态区域授权和持久审计仍是后续 checkpoint;当前一个 MCP Token 只对应一个静态数据库全范围或镇街白名单。
|
||||
|
||||
## 2026-09-05 本地实库冒烟结果
|
||||
|
||||
服务仅监听 `127.0.0.1:18080`,使用运行时只读 PostGIS 账号和显式 `all` 数据范围完成测试;未输出联系人、完整业务记录或测试坐标。
|
||||
|
||||
- `GET /health` 返回 200;无 Token 的 `POST /mcp` 返回 401。
|
||||
- `initialize` 协商 MCP `2025-06-18`;initialized notification 返回 202;`tools/list` 返回全部 7 个工具。
|
||||
- 使用“观水镇”得到 10 个地点候选,并选取一个精确匹配的 `recorded_point` 蓄水池记录,仅作为获授权测试坐标。
|
||||
- 网格上下文返回 1 条;水源、指挥部候选和通道各返回 10 条;责任中队返回 1 条;风险区域返回 9 条。
|
||||
- 7 个响应的 `structuredContent` 与文本 JSON 投影一致,空间参考均为 EPSG:4326,计数与数据数组一致,不包含已禁止的联系人类字段键。
|
||||
- 所有工具均保留 `source_records_with_invalid_geometries_are_excluded` 以及各自能力限制 warning。
|
||||
- 第二轮 7 个数据库工具调用分别约耗时 0.35 至 0.99 秒,均低于 5 秒工具超时;这只是当前小数据本地结果,不替代生产索引和并发验证。
|
||||
- 不存在的地名稳定返回 `no_results`;越界经度返回 `INVALID_ARGUMENT`;不可信 Origin 返回 403;`GET /mcp` 返回 405。
|
||||
- 运行日志只记录 request ID、工具名、结果类别和耗时,未记录坐标、请求参数或结果正文。
|
||||
@@ -0,0 +1,125 @@
|
||||
# SuperAgent Open API 项目接入指南
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 项目 | `fire-safety-ymd` |
|
||||
| 协议基线 | TH Hotel 仓库保存的 2026-07-12 Open Agent API 资料 |
|
||||
| 当前状态 | Go Adapter、默认关闭的原生用户对话 API 与可选兼容入口已完成模拟联调;上线前必须与当前 SuperAgent 环境重新联调 |
|
||||
|
||||
## 1. 项目调用边界
|
||||
|
||||
```text
|
||||
用户侧应用
|
||||
-> fire-safety-ymd POST /api/chat
|
||||
或 /api/v1/apps/{app_id}/completion
|
||||
-> 内存会话与并发 Run 控制
|
||||
-> SuperAgent Client Port
|
||||
-> SuperAgent Open API Adapter(本 checkpoint)
|
||||
-> 已发布的消防 SuperAgent Profile
|
||||
```
|
||||
|
||||
前端不得持有 Open API Key 或直接调用 SuperAgent。Adapter 只负责 Provider 协议,消防业务 Service 不直接解析 SSE 或依赖 Provider DTO。
|
||||
|
||||
## 2. Profile 与 Session
|
||||
|
||||
Open API 请求不直接提交 `profile_id`。平台通过 `df_open_*` 外部应用 Key 对应的策略选择已发布 Profile,因此消防项目必须创建独立外部应用并绑定消防 Profile,不能复用 TH Hotel 的 Profile 或 Key。
|
||||
|
||||
`external_subject_id` 表示外部主体,不是 Profile ID。首版对话 API 使用服务端固定的非真实测试主体,并在单进程内存中保存:
|
||||
|
||||
```text
|
||||
本地用户 + 本地会话
|
||||
-> SuperAgent external_subject_id
|
||||
-> SuperAgent session_id
|
||||
```
|
||||
|
||||
同一多轮对话复用同一 Session;同一 Session 有 active Run 时返回 `409`,不能并发重发。该映射尚未持久化,重启和多实例切换后旧对话不可恢复;真实用户阶段必须改用经验证且假名化的主体,并补共享/持久会话存储。
|
||||
|
||||
## 3. Open API 流程
|
||||
|
||||
1. 创建 Session:`POST /api/open/agent-sessions`。
|
||||
2. 流式发送消息:`POST /api/open/agent-sessions/{session_id}/messages/stream?include_trace=true`。
|
||||
3. 初始流断开时查询 `GET {Content-Location}`。
|
||||
4. 使用 `GET {Content-Location}/events` 和 `Last-Event-ID` 恢复。
|
||||
5. 只有最终内容、成功 `run.completed` 和顶层 `end` 同时存在时返回成功。
|
||||
|
||||
如果未来需要主动取消,平台资料中的接口为:
|
||||
|
||||
```text
|
||||
POST /api/open/agent-sessions/{session_id}/runs/{run_id}/cancel
|
||||
```
|
||||
|
||||
取消能力不属于本 checkpoint。
|
||||
|
||||
## 4. 外部应用要求
|
||||
|
||||
平台管理员需要为本项目确认:
|
||||
|
||||
- 独立消防 Profile 已发布且 API exposure 已开启。
|
||||
- 外部应用 Key 已绑定目标 Profile。
|
||||
- 至少具备 `agent_sessions:create`、`agent_sessions:message` 和 `agent_sessions:read` scope。
|
||||
- 后续需要取消 Run 时增加 `agent_sessions:cancel`。
|
||||
- 需要公开 Trace 时,应用策略的 `trace_policy.enabled=true`。
|
||||
- 工具输入、输出和步骤信息默认只暴露 summary,不开放模型原始思考过程。
|
||||
|
||||
## 5. 本地配置
|
||||
|
||||
复制 `.env.example` 中的占位配置到本地 Secret 管理方式,不提交真实值。
|
||||
|
||||
主要变量:
|
||||
|
||||
```text
|
||||
FIRE_SAFETY_SUPERAGENT_ENABLED=true
|
||||
FIRE_SAFETY_SUPERAGENT_BASE_URL=https://<superagent-domain>
|
||||
FIRE_SAFETY_SUPERAGENT_OPEN_API_KEY=<secret>
|
||||
|
||||
FIRE_SAFETY_CHAT_ENABLED=true
|
||||
FIRE_SAFETY_CHAT_AUTH_TOKEN=<another-secret-at-least-32-printable-ascii-characters>
|
||||
FIRE_SAFETY_CHAT_ALLOWED_ORIGINS=http://localhost:5173
|
||||
```
|
||||
|
||||
fire-safety-ymd 不读取通用 `DEERFLOW_OPEN_API_KEY`,避免开发机上其他项目的凭证被意外复用。
|
||||
|
||||
## 6. CLI 连通性探针
|
||||
|
||||
配置测试环境后执行:
|
||||
|
||||
```bash
|
||||
go run ./cmd/superagent-probe
|
||||
```
|
||||
|
||||
探针只发送代码内固定的无敏感信息消息,输出最终回答和必要的安全元数据。它不启动业务聊天、不查询消防数据库、不写业务状态。
|
||||
|
||||
探针不会自动读取 TH Hotel 的 `DEERFLOW_*` 或其他项目变量。至少需要显式设置本项目的启用开关、Base URL 和 Open API Key;未配置时命令会在任何网络请求前退出。
|
||||
|
||||
禁止把真实火情、联系人、电话、精确受限位置、生产凭证或客户数据放进探针消息和 metadata。
|
||||
|
||||
## 7. 用户对话 API
|
||||
|
||||
原生接口为 `POST /api/chat`,请求体只接受 `message` 和可选的本地 `conversation_id`,响应是 SSE。首次请求由服务端创建 SuperAgent Session 并返回随机对话 ID,后续轮次使用该 ID 复用上下文。客户端不能提交 Provider Session、主体、角色、区域或 metadata。
|
||||
|
||||
配置 `FIRE_SAFETY_CHAT_COMPAT_APP_ID` 后,同一 Chat Service 还提供 DashScope 风格受限兼容路径。它把 `input.prompt` / `input.session_id` 映射到上述本地会话语义,以 `event: result` 和最终 `finish_reason=stop` 返回严格完成的正文。该入口不是 DashScope 全量代理,也不会把 URL App ID 或客户端 session ID直接传给 Provider。
|
||||
|
||||
详细事件、失败语义和 curl 示例见:
|
||||
|
||||
- [`../../architecture/chat-api-v1.md`](../../architecture/chat-api-v1.md)
|
||||
- [`../../workflows/user-chat.md`](../../workflows/user-chat.md)
|
||||
- [`../../specs/fire-safety-ymd-chat-api-v1.md`](../../specs/fire-safety-ymd-chat-api-v1.md)
|
||||
|
||||
`FIRE_SAFETY_CHAT_AUTH_TOKEN` 是独立的首版联调凭证:原生接口将其作为 Bearer,兼容入口将其作为 `xtoken`。它不是最终用户登录;浏览器会暴露静态 Token,因此公网真实用户入口仍必须接入身份提供方、动态授权、限流和审计。
|
||||
|
||||
## 8. 与 MCP 的关系
|
||||
|
||||
Open API 与 MCP 是两条独立连接:
|
||||
|
||||
- fire-safety-ymd -> SuperAgent:使用 Open API Key。
|
||||
- SuperAgent -> fire-safety-ymd `/mcp`:使用独立 MCP 凭证。
|
||||
|
||||
本文件记录第一条 Open API 接入。仓库现已另外实现默认关闭的只读空间 MCP 基线;两条系统连接仍使用不同凭证,不能把 Open API Key 当作 MCP Token。用户侧原生/兼容对话使用第三个独立联调凭证,三个值都不得复用。MCP 的部署与工具契约见 `superagent-mcp-spatial.md`;兼容入站契约见 [`../../specs/fire-safety-ymd-dashscope-compatible-chat-v1.md`](../../specs/fire-safety-ymd-dashscope-compatible-chat-v1.md)。
|
||||
|
||||
## 9. 当前限制
|
||||
|
||||
- 用户聊天 HTTP API 和单进程并发 Run 控制已实现,但默认关闭,只有静态测试 Bearer,没有最终用户认证或动态授权。
|
||||
- 本地会话未持久化;重启、多实例切换和上游失败后不能恢复旧 `conversation_id`,也尚无主动取消。
|
||||
- MCP/PostGIS 已完成本地实库冒烟,但尚未完成 SuperAgent 到公网 MCP 的联调。
|
||||
- 真实 Profile、Key、scope、Trace 策略和网络连通性必须在目标环境验证。
|
||||
- Provider 协议可能在 2026-07-12 资料后变化;出现差异时更新 Spec 和契约,不在 Adapter 中静默猜测。
|
||||
Reference in new issue
Block a user