status: done created: 2026-07-11 complexity: 🔴复杂 parent-stage: Forge AI 中枢阶段 1 — 能力内核 + 只读 MCP MVP
forge-ai-hub-foundation 已归档,阶段 0 已提供协议无关 Capability 内核、Streamable HTTP /mcp、可信身份接口、Schema 校验、HMAC 游标和静态 capability.ping。当前 Registry 仍是进程内静态快照,没有能力目录、版本、机器客户端、授权和调用日志的数据库权威来源。
阶段 1 包含控制面、机器认证、动态目录、低代码只读执行器和管理端,不能在一个变更中同时完成。本变更交付阶段 1 的第一个独立纵向切片:持久化控制面和安全领域服务,为后续 capability.search/describe/invoke 与低代码只读能力提供稳定事实来源。
ai_capability、ai_capability_version、ai_capability_client、ai_capability_grant、ai_capability_invocation_log;del_flag=0;keyId + 256 bit Secret,只在创建/轮换时返回一次;数据库只保存 keyId、前缀与 HMAC-SHA-256(secret, serverPepper);capability.ping,Admin 组合根通过控制面机器凭据建立可信调用上下文,不把未完成动态目录的持久化能力注册为顶层 Tool;CapabilitySource、Schema Builder 或 DynamicCrudReadExecutor;capability.search/describe/invoke MCP 工具;userId、tenantId、activeOrgId Header 均不可信;本变更将持久化控制面放入独立模块 forge-plugin-capability-control-plane,避免核心协议和 MCP 适配层传递依赖 ORM、认证、Redis 与管理 Web:
forge-admin-server ─┬─> forge-plugin-capability-control-plane ─> forge-plugin-capability
└─> forge-plugin-mcp ──────────────────────> forge-plugin-capability
forge-plugin-capability 只保留协议无关模型、Registry、Schema、授权 SPI 和执行 SPI;forge-plugin-mcp 不依赖控制面,不扫描或静态发布持久化业务能力;forge-plugin-capability-control-plane 承载实体、Mapper XML、管理 API、机器凭据、grant 和审计;CapabilityMcpCallerContextResolver 完成 Bearer 机器凭据到 MCP 调用上下文的接线;协议模块之间不形成反向依赖。ai_capability保存租户内稳定能力标识与当前发布指针。关键字段:
capability_code / protocol_tool_name / capability_name / description
source_type / source_key / source_version
current_version / schema_checksum
behavior / risk_level / visibility / publish_status / enabled
del_flag / logic_delete_active / 标准审计字段
唯一约束:(tenant_id, capability_code, logic_delete_active) 与 (tenant_id, protocol_tool_name, logic_delete_active)。
ai_capability_version保存不可变版本快照:capability_id/version/input_schema/output_schema/source_type/source_key/source_version/behavior/risk_level/visibility/policy_snapshot/schema_checksum/status。发布后禁止更新执行语义或 Schema;修正必须创建新版本。
ai_capability_client保存机器客户端:client_code/client_name/key_id/key_prefix/key_hash/credential_version/service_user_id/active_org_id/status/expires_at/last_used_at。key_id 全局唯一并用于认证前定位权威租户,key_hash 固定 64 位小写十六进制,不保存原始密钥。
ai_capability_grant保存 client_id -> capability_id 显式授权,支持 PINNED 固定版本和 FOLLOW_MAJOR 跟随同主版本。阶段 1 第一切片只允许读能力授权,ACTION/FLOW/MESSAGE/EXTERNAL 拒绝创建 grant。
ai_capability_invocation_log保存调用安全元数据,包括 actor_type/actor_user_id/service_user_id 双身份审计。request_id 在租户内唯一;普通删除逻辑删除,后续留存任务才允许物理清理超期日志。
public interface CapabilityCatalogService {
Page<CapabilityCatalogVO> page(PageQuery pageQuery, CapabilityCatalogQuery query);
CapabilityCatalogVO getById(Long id);
Long publish(CapabilityPublishCommand command);
void disable(Long id);
}
public interface CapabilityClientCredentialService {
CapabilityClientSecret create(CapabilityClientCreateCommand command);
CapabilityClientSecret rotate(Long clientId);
CapabilityClientPrincipal authenticate(String rawSecret);
void revoke(Long clientId);
}
public interface CapabilityGrantService {
Long grant(CapabilityGrantCommand command);
void revoke(Long grantId);
CapabilityGrantDecision evaluate(Long clientId, String capabilityCode, String requestedVersion);
}
public interface CapabilityInvocationAuditService {
void record(CapabilityInvocationAuditEvent event);
Page<CapabilityInvocationLogVO> page(PageQuery pageQuery, CapabilityInvocationLogQuery query);
}
forge.capability.client-pepper 无默认值;仅创建、轮换和验证密钥时要求非空;fcp_<22位Base64URL keyId>_<43位Base64URL随机串>;只允许用不可猜测 keyId 跨租户定位凭据,日志和异常禁止出现完整值;MessageDigest.isEqual;客户端不存在时也计算一次哑 HMAC,降低明显时序差异;actorUserId 固定等于客户端绑定的 serviceUserId;后续用户委托模式必须由 Forge 登录/OAuth 签发短期令牌证明实际人员,禁止信任调用方自报用户 Header;keyPrefix,Secret 只出现在创建/轮换响应;CapabilitySchemaValidator,checksum 使用规范化 JSON 的 SHA-256;credential_version CAS 原子更新;认证只更新 last_used_at,旧认证快照不得恢复已轮换或吊销状态。| 模块 | 路径 | 方法 | 权限 |
|---|---|---|---|
| 能力目录 | /ai/capability/page |
GET | ai:capability:query |
| 能力目录 | /ai/capability/getById |
POST | ai:capability:query |
| 能力发布 | /ai/capability/publish |
POST | ai:capability:publish |
| 能力停用 | /ai/capability/disable/{id} |
POST | ai:capability:publish |
| 客户端 | /ai/capability/client/page |
GET | ai:capability:client:query |
| 客户端 | /ai/capability/client/add |
POST | ai:capability:client:add |
| 客户端 | /ai/capability/client/rotate/{id} |
POST | ai:capability:client:rotate |
| 客户端 | /ai/capability/client/revoke/{id} |
POST | ai:capability:client:revoke |
| 授权 | /ai/capability/grant/page |
GET | ai:capability:grant:query |
| 授权 | /ai/capability/grant/add |
POST | ai:capability:grant:add |
| 授权 | /ai/capability/grant/revoke/{id} |
POST | ai:capability:grant:revoke |
| 调用日志 | /ai/capability/invocation/page |
GET | ai:capability:invocation:query |
写接口使用 @ApiDecrypt;包含一次性 Secret 的创建/轮换响应使用 @ApiEncrypt。
本地 SDK 0.17.0 与 Maven Central 2.0.0 的公开 API/字节码检查均显示 tools/list 仍读取进程级静态 Tool 集合,没有请求级目录 provider。升级 SDK 不能自动解决动态目录,且会破坏 Spring AI 1.1.2 的受控依赖组合。
因此本变更不升级 SDK、不 fork SDK、不反射私有字段。下一变更采用所有客户端统一可见的元工具 capability.search/describe/invoke,真实能力目录由控制面按 caller/grant 动态返回;顶层业务 Tool 投影继续关闭。该设计保持 Streamable HTTP 和调用级授权,不泄露未授权能力。
V1.0.21__add_ai_capability_control_plane.sql;CREATE TABLE IF NOT EXISTS,字典和资源使用 NOT EXISTS;@TableLogic 与 Mapper XML 条件一致;last_used_at 被租户插件追加 NULL 条件;review-ready,不自动归档;机器模式可归因到绑定服务账号。具体人员 A 的可信委托仍需独立变更,不能用可伪造 Header 代替;之后再建设统一静态元工具和调用级动态授权目录。code-copilot/changes/archive/2026-07-12-forge-ai-hub-control-plane/;done;mcp-user-delegation-identity,在可信用户委托身份完成前禁止开放人员责任写入、流程发起和流程办理能力。