From 0081ad6e49232e70aa7e1f4e528258b39aef6ef4 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Fri, 8 May 2026 07:59:00 +0800 Subject: [PATCH] feat(mcp): TokenService.IssueSystemToken (with default scope + 24h TTL) --- internal/mcp/token_service.go | 58 ++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/internal/mcp/token_service.go b/internal/mcp/token_service.go index 7171524..ef949b4 100644 --- a/internal/mcp/token_service.go +++ b/internal/mcp/token_service.go @@ -121,8 +121,64 @@ func (s *tokenService) IssueAdmin(ctx context.Context, in IssueAdminInput) (Issu }, nil } +// IssueSystemToken 在 ACP supervisor 起 session 时调用。 +// +// 重要约束:调用必须在已经创建 acp_sessions row 的事务**之后或同一事务内**进行 —— +// 因为 mcp_tokens.acp_session_id 是 NOT NULL CHECK + FK,session row 不存在则 +// FK 校验失败。spec §6.1 明确建议同事务提交。本 service 不直接管事务边界(由 +// ACP SessionService 在 Create 流程内编排),但调用顺序由调用方保证。 +// +// 默认 ExpiresIn = 24h;默认 Tools 为内置 PM 工具白名单(spec §6.2)。 +// 写一条 audit `mcp.token.create_system`。 func (s *tokenService) IssueSystemToken(ctx context.Context, in IssueSystemTokenInput) (IssueResult, error) { - panic("not implemented: IssueSystemToken") + if in.ExpiresIn <= 0 { + in.ExpiresIn = 24 * time.Hour + } + tools := in.Tools + if tools == nil { + // 用 copy 避免共享 defaultSystemTools 给调用方修改 + tools = append([]string{}, defaultSystemTools...) + } + expires := time.Now().Add(in.ExpiresIn) + + plain, hash, err := NewToken() + if err != nil { + return IssueResult{}, errs.Wrap(err, errs.CodeInternal, "generate system token") + } + + id := uuid.New() + created, err := s.repo.Create(ctx, &MCPToken{ + ID: id, + TokenHash: hash, + UserID: in.UserID, + Name: "acp:" + in.ACPSessionID.String(), + Issuer: IssuerSystem, + Scope: Scope{Tools: tools, ProjectIDs: in.ProjectIDs}, + ACPSessionID: &in.ACPSessionID, + ExpiresAt: &expires, + CreatedBy: in.UserID, // system 签发时 created_by 即 owner(无 admin 操作者) + }) + if err != nil { + return IssueResult{}, err + } + + _ = s.audit.Record(ctx, audit.Entry{ + UserID: &in.UserID, + Action: "mcp.token.create_system", + TargetType: "mcp_token", + TargetID: created.ID.String(), + Metadata: map[string]any{ + "token_id": created.ID.String(), + "acp_session_id": in.ACPSessionID.String(), + "user_id": in.UserID.String(), + }, + }) + + return IssueResult{ + ID: created.ID, + Plaintext: plain, + ExpiresAt: created.ExpiresAt, + }, nil } func (s *tokenService) Authenticate(ctx context.Context, plaintext string) (*MCPToken, error) { panic("not implemented: Authenticate")