change:
forge-ai-hub-foundationstatus: done created: 2026-07-11
| 时间 | 阶段 | 事件 | 备注 |
|---|---|---|---|
| 2026-07-11 | Research | 读取 Forge AGENTS、code-copilot 规则、记忆、Proposal 模板和自动化测试标准 | 本轮遵循 No Spec No Code |
| 2026-07-11 | Research | 读取 AI 中枢战略方案、落地路线图和两个已归档 AI 变更 | 确定阶段 0 边界 |
| 2026-07-11 | Decision | 用户明确 MCP Server 只使用最新 Streamable HTTP | 禁止旧 SSE transport 和双端点兼容层 |
| 2026-07-11 | Research | 检查当前工程依赖与 Agent 页面 | 当前无 MCP/Capability;页面存在未实现高风险选项 |
| 2026-07-11 | Dependency Spike | 解析 Spring AI 1.1.2 三种 MCP Server starter | 通用/WebMVC/WebFlux 坐标均存在 |
| 2026-07-11 | Bytecode Research | 检查 MCP Server properties、WebMVC auto-config 和 MCP SDK 0.17.0 | Streamable provider 存在;默认协议 SSE;tools/list 静态且 nextCursor=null |
| 2026-07-11 | Proposal | 创建 spec/tasks/test-spec/execution-log | 未写业务代码、未改数据库、未启动服务 |
| 2026-07-11 | Apply HARD-GATE | 新建 Capability/MCP 插件并打通 Streamable HTTP | /mcp 完成 initialize/list/call;协议 2025-06-18 |
| 2026-07-11 | Apply Dependency | 消除 Spring Boot 3.2.9/3.5.13 版本漂移 | 最终 Boot 3.5.13、Spring AI 1.1.2、MCP SDK 0.17.0 |
| 2026-07-11 | Apply Security | 接入 transport context 身份解析和调用时二次授权 | 无 Resolver 启用即失败;arguments 不能覆盖调用方身份 |
| 2026-07-11 | Apply Validation | 完成后端、Admin、前端、依赖与静态扫描 | AI 84、Capability 9、MCP 8,均 0 失败 |
| 2026-07-11 | Review Fix | 修复协议外部覆盖、HTTP 身份边界、授权错误码、HMAC 游标防篡改、Schema 无损校验和安全审计 | 1 个 Critical 与 6 组 Important 问题完成修复 |
| 2026-07-11 | Review Fix Validation | Capability/MCP 26 tests、AI 84 tests、Admin 37 模块聚合与静态扫描通过 | 不访问公网、数据库、Nacos 或模型服务 |
| 2026-07-11 | Archive | 用户明确授权归档,复核四份文档、路线图、长期记忆和最终验证证据 | 状态更新为 done;未 commit/push,SDK 动态目录限制转入阶段 1 硬闸门 |
forge-plugin-ai 存在 spring-boot-starter-webflux,用于现有流式链路;agent.vue#mcpToolOptions 存在 database/http/file/web/code 等硬编码项,但后端没有实现。执行:
mvn -q dependency:get \
-Dartifact=org.springframework.ai:spring-ai-starter-mcp-server:1.1.2 \
-Dtransitive=false
mvn -q dependency:get \
-Dartifact=org.springframework.ai:spring-ai-starter-mcp-server-webmvc:1.1.2 \
-Dtransitive=false
mvn -q dependency:get \
-Dartifact=org.springframework.ai:spring-ai-starter-mcp-server-webflux:1.1.2 \
-Dtransitive=false
结果:三个坐标均解析成功。spring-ai-autoconfigure-mcp-server:1.1.2 不存在,实际自动配置模块按 common/webmvc/webflux 拆分,不能在实现中猜坐标。
本命令只更新用户本地 Maven 缓存,没有修改仓库 POM。
执行过的只读检查:
jar tf ~/.m2/repository/org/springframework/ai/spring-ai-autoconfigure-mcp-server-webmvc/1.1.2/spring-ai-autoconfigure-mcp-server-webmvc-1.1.2.jar
javap -classpath <mcp jars> -private -constants \
org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties \
org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties
javap -classpath <mcp jars> -c -p \
io.modelcontextprotocol.server.McpAsyncServer
确认结果:
McpServerProperties.CONFIG_PREFIX = spring.ai.mcp.server;ServerProtocol 枚举包含 SSE/STREAMABLE/STATELESS;spring.ai.mcp.server.protocol 默认值为 sse;McpServerStreamableHttpProperties.CONFIG_PREFIX = spring.ai.mcp.server.streamable-http;mcp-endpoint 默认 /mcp;WebMvcStreamableServerTransportProvider 和对应 RouterFunction;contextExtractor(...),并可把 McpTransportContext 传入 Tool exchange;0.17.0 的 tools/list handler 遍历全局 CopyOnWriteArrayList tools,构造 ListToolsResult(tools, null);当前实现不是按请求上下文过滤,也没有游标分页;docs/vendor/spring-ai-extensions-1.1.2.3-release/mcp/spring-ai-alibaba-mcp-common/src/main/java/com/alibaba/cloud/ai/mcp/common/transport/builder/WebFluxStreamableClientTransportBuilder.java 证明 Alibaba Extensions 有 Streamable HTTP 客户端路径;McpServerStreamableHttpProperties,说明上游扩展认识 streamable server 属性;| 决策 | 选择 | 放弃的方案 | 原因 |
|---|---|---|---|
| 能力架构 | 协议无关 capability + MCP adapter 两层 | Controller/Mapper 直接变 Tool | 保持复用、安全和演进边界 |
| MCP transport | Streamable HTTP /mcp |
旧 SSE 双端点、SSE 兼容层 | 用户明确要求且符合最新协议方向 |
| Server starter 候选 | WebMVC starter | 因存在 Flux 就选 WebFlux server | Forge 主容器是 Undertow/WebMVC |
| 协议配置 | 显式 STREAMABLE |
依赖默认值 | 1.1.2 默认仍是 SSE |
| Registry | 内存静态快照 | Nacos/数据库 | 阶段 0 先验证核心契约 |
| 初始 Tool | capability.ping |
database/http/file/code | 只读无副作用,适合验证协议 |
| 身份 | transport/security context resolver | arguments 或裸租户 Header | 防止跨租户与身份伪造 |
| Schema | Draft 2020-12 规范 + 公共子集投影 | 直接绑定 MCP SDK Schema | 内核协议无关且不静默丢语义 |
| 动态目录 | 内核支持;MCP 当前不足则限制为统一 ping | 反射 SDK/请求时全局增删工具 | 避免跨客户端竞态和虚假能力声明 |
由主 Agent 使用 fresh-reader checklist 复核;本轮没有创建新子 Agent。
| 问题 | 文档可独立回答的结论 | 位置 |
|---|---|---|
| 为什么不能从 Controller 直接生成 MCP Tool? | 会把协议、权限和业务耦合,无法供内部 Runtime 复用 | spec.md 2.4、4.1 |
| 阶段 0 是否接业务数据库? | 不接;无表、无 Flyway、只用静态 Registry | spec.md 3.2、7 |
| MCP transport 是什么,旧 SSE 是否允许? | 只允许 Streamable HTTP /mcp;旧 SSE 禁止 |
spec.md 5 |
| 当前版本不支持 Streamable 时怎么办? | 停止后续任务,升级或隔离;禁止回退 SSE | spec.md 5.2、10 |
| Capability 内核为什么不能依赖 MCP/AI? | 它要被 MCP、内部 Agent、HTTP/工作流共同复用 | spec.md 4.1 |
| 哪些身份字段客户端不能传? | machineClientId、tenantId、userId、activeOrgId、scopes | spec.md 6.1 |
| 当前 SDK 动态 tools/list 不足怎么办? | 只发布统一授权 ping,业务工具发布失败关闭 | spec.md 5.3 |
| 阶段 0 的退出闸门是什么? | transport、身份、Schema、ping、依赖与无 SSE 验证全部通过 | spec.md 1.1、10.5 |
| 下一阶段才建设什么? | 持久化目录、客户端授权、动态业务工具、Agent Runtime/Nacos 等 | spec.md 3.2、7 |
Reader Test 结论:范围和失败关闭条件明确;没有把 Streamable HTTP 内部流式响应误写成旧 SSE;没有把当前 SDK 静态 tools/list 描述为动态能力。
| 检查 | 命令 | 结果 |
|---|---|---|
| 目标目录唯一 | test ! -e code-copilot/changes/forge-ai-hub-foundation(创建前) |
通过,未覆盖已有变更 |
| 四份文档存在 | find code-copilot/changes/forge-ai-hub-foundation -maxdepth 1 -type f + 文件数断言 |
通过,恰好 4 份 Markdown |
| status/范围检查 | rg 检查 propose、Streamable、SSE 禁令、无 DB/Nacos |
通过 |
| Markdown/空白 | 对四份未跟踪文档逐一执行 git diff --no-index --check /dev/null <file>,并检查 EOF 换行与尾随空格 |
通过 |
| 业务代码/数据库 | git status --short 对比 |
本 Proposal 只应新增四份文档;工作区其它改动为用户既有改动 |
| 偏差点 | Spec 预期 | 实际情况 | 处理方式 |
|---|---|---|---|
| Proposal 阶段 | 只创建文档 | 已按用户 /apply 指令进入实现 |
状态更新为 apply |
| SDK 动态目录 | 希望按 caller 过滤与分页 | 本地 SDK 0.17.0 静态列表、cursor=null | 在 Spec 中设为异构业务工具发布闸门,不虚构支持 |
| Admin 默认关闭测试 | 希望验证“默认无 MCP transport” | 上游 Starter 在完全无配置时默认启用 SSE;Forge Admin 通过 YAML 显式 enabled=false 覆盖 |
测试验证 Admin 默认值关闭;同时保留显式 STREAMABLE 和缺 Resolver 失败关闭测试 |
| 计划中的细分测试类 | 每项能力可拆独立测试类 | 身份、Schema、动态目录限制等部分场景合并到 Registry/Adapter/Transport 测试 | 保持行为覆盖,避免为文件名机械拆分测试 |
V1.0.18__add_ai_model_routing_governance.sql 属于已完成的前序路由治理变更;text/event-stream 响应当成违规;CapabilityResult 不保存 Throwable,日志不打印 arguments/data;capability.ping 必须保持无业务依赖;forge-plugin-capability,包含 Definition、Caller、Invocation、Result、Query、Page、Cursor、Source、Executor、AuthorizationPolicy 和 Registry 契约;capabilityCode 使用小写点分编码并恒等映射到协议工具名,版本固定三段语义格式;CapabilityResult 不保存 Throwable,异常只映射安全错误码和通用信息。$ref、条件 Schema、动态关键字等未支持语义失败关闭;MCP SDK 无法无损表达 nullable 时拒绝发布;capability.ping@1.0.0,行为 READ_ONLY、风险 LOW,输入只允许空对象,输出仅 status/requestId/serverTime;forge-plugin-mcp,使用 spring-ai-starter-mcp-server-webmvc:1.1.2 和 Forge Undertow Web Starter;protocol=STREAMABLE、stdio=false、mcp-endpoint=/mcp,不提供旧 /sse 和消息回传双端点;ForgeMcpTransportContextExtractor 只接受 McpCallerContextResolver 产生的可信 caller;无 Resolver 时启用 MCP 会启动失败;capability.ping。SDK 0.17.0 的 tools/list 固定全量且 nextCursor=null,因此异构业务工具仍被发布闸门禁止;/mcp 上返回 text/event-stream 流式响应属于协议合法行为,不是旧独立 SSE transport。forge-plugin-mcp,默认 ${FORGE_MCP_ENABLED:false},显式锁定 STREAMABLE;extraConfig.mcpTools,不允许新增虚假配置,也不自动清空历史值;| 阶段 | Red/异常 | 修正与最终结果 |
|---|---|---|
| Transport 初始装配 | 缺模块和 MCP starter,Context 无法形成 Streamable provider | 新增 WebMVC MCP 插件并排除 starter 自带 Web 容器,Streamable provider Green |
| 版本装配 | 父层遗留 Boot 3.2.9 与 Spring AI BOM 3.5.x 漂移 | 移除局部 3.2.9 覆盖,Forge BOM 统一为 3.5.13;Admin 37 模块 package Green |
| 默认关闭用例 | 完全无配置时上游自动装配默认 SSE,新增用例首次失败 | 按 Admin 实际默认 enabled=false 验证无任何 transport;显式启用仍强制 STREAMABLE |
| Maven 测试命令 | 普通 mvn test 和仅 -DskipTests=false 仍被项目 forge.tests.skip/groups 跳过 |
使用 -Penable-tests,得到真实 Tests run 结果 |
| dependency:tree | 首次 zsh 未引用 * 导致 shell 展开失败;第二次未加 -am 尝试从仓库解析内部 capability 并失败 |
引用 includes 且加入 -am,依赖树 Green |
| Review Fix 接口演进 | CapabilityAuthorizationPolicy 从 boolean 扩展为结构化决策后,旧测试实现首次 testCompile 失败 |
更新测试策略实现和调用断言;最终 Capability 13、MCP 13 全绿 |
| 范围 | 命令摘要 | 结果 |
|---|---|---|
| AI 回归 | mvn -Penable-tests -pl forge-framework/forge-plugin-parent/forge-plugin-ai test |
Tests run: 84,Failures: 0,Errors: 0,Skipped: 0 |
| Capability + MCP(Review Fix) | Java 17 执行 mvn -Penable-tests -pl forge-framework/forge-plugin-parent/forge-plugin-mcp -am test |
Capability 13 + MCP 13,Failures: 0,Errors: 0,Skipped: 0;BUILD SUCCESS |
| Admin 聚合 | mvn -pl forge-admin-server -am package -DskipTests |
37/37 模块 SUCCESS,生成可执行 jar;仅原有 EmployeeServiceImpl deprecated API 提示 |
| 依赖树 | mvn -pl .../forge-plugin-mcp -am dependency:tree -Dverbose ... |
Spring AI 单一 1.1.2;MCP SDK 单一 0.17.0;Boot 单一 3.5.13;Web 容器为 Undertow |
| MCP 协议 | McpStreamableProtocolIntegrationTest |
/mcp initialize → initialized → tools/list → tools/call 全部通过,协议 2025-06-18,只返回 capability.ping |
| MCP 装配 | McpStreamableTransportCompatibilityTest |
Admin 默认值关闭;启用时只有 Streamable provider;无 Resolver 失败关闭;无 SSE provider |
| 前端 lint | pnpm exec eslint src/views/ai/agent.vue |
通过,无输出 |
| 前端 build | pnpm build |
通过,built in 2m 28s |
| 静态扫描 | rg 扫描 capability/mcp 生产代码与 Admin 配置 |
无旧 SSE、Nacos MCP、AgentScope、高风险工具实现;Capability 无 Spring AI/MCP/AI 插件引用 |
| 空白检查 | git diff --check |
通过 |
| Review Fix 静态安全检查 | rg 扫描两个插件生产代码的模块依赖、旧 SSE、Nacos MCP、AgentScope、高风险执行 API 和敏感日志字段 |
禁止项无输出;Projector 对外只接受 ValidatedCapabilitySchema |
依赖树中的 tomcat-embed-el:10.1.53 是 Validation/Undertow 使用的 EL 实现,不包含 Tomcat Servlet 容器核心;spring-boot-starter-tomcat、tomcat-embed-core 和 Tomcat Web Server 未进入 MCP 运行链。
UserSelectModal 命名冲突、若干模块同时动态/静态导入、CSS 中使用 // 注释;不由本变更引入且不阻断构建;git diff --cached --check 会命中用户已放入暂存区的两套 docs/vendor/spring-ai-* 上游源码原始尾随空格,因此未改写第三方 vendor 文件,也不将其误记为本变更失败;dist 产物。mcp -> capability 单向,Schema 与身份均失败关闭,错误结果不泄露 Throwable;tools/list 和稳定 nextCursor。正式业务 Tool 上线前必须升级/隔离 SDK 适配,当前只允许统一授权 capability.ping。结论:/apply forge-ai-hub-foundation 完成,可进入独立 /review forge-ai-hub-foundation;不应直接进入业务 Tool 或 Agent Runtime 实现。
/mcp 身份失败返回 HTTP 401;租户、组织、scope 决策使用稳定错误码传播;/mcp 与统一授权的 capability.ping,未引入 Nacos、业务工具、数据库或 Agent Runtime。结论:/fix forge-ai-hub-foundation 已完成,用户随后明确授权归档。变更状态更新为 done 并移动到 code-copilot/changes/archive/2026-07-11-forge-ai-hub-foundation/;下一阶段必须先解决动态工具目录与持久化控制面,不能直接开放业务写工具。