ACP / MCP 完善

This commit is contained in:
2026-06-11 12:43:18 +08:00
parent 1415d3b43b
commit 0561e126cd
22 changed files with 786 additions and 219 deletions
+41 -18
View File
@@ -2,7 +2,6 @@ package mcp
import (
"context"
"fmt"
"github.com/google/uuid"
mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
@@ -126,6 +125,27 @@ func resolveMountRefs(ctx context.Context, deps ServerDeps, c project.Caller,
return refs, nil
}
// scopedConversation 解析 conversation_id、取会话(service 层含 ownership 校验)
// 并做项目 scope 校验:ProjectID 为 nil 的个人会话不受 project scope 约束。
// limit 控制随会话返回的最近消息条数,仅 get_conversation 需要,其余入口传 1。
func scopedConversation(ctx context.Context, deps ServerDeps, userID uuid.UUID,
conversationID string, limit int) (*chat.Conversation, []chat.Message, error) {
convID, err := uuid.Parse(conversationID)
if err != nil {
return nil, nil, errs.Wrap(err, errs.CodeInvalidInput, "conversation_id parse")
}
cv, msgs, err := deps.Conversations.Get(ctx, userID, convID, limit)
if err != nil {
return nil, nil, err
}
if cv.ProjectID != nil {
if err := CheckProjectFromCtx(ctx, *cv.ProjectID); err != nil {
return nil, nil, err
}
}
return cv, msgs, nil
}
// ===== list_recent_messages =====
type listRecentMessagesIn struct {
@@ -166,9 +186,9 @@ func registerListRecentMessages(srv *mcpsdk.Server, deps ServerDeps) {
return nil, listRecentMessagesOut{}, err
}
convID, err := uuid.Parse(in.ConversationID)
cv, _, err := scopedConversation(ctx, deps, c.UserID, in.ConversationID, 1)
if err != nil {
return nil, listRecentMessagesOut{}, fmt.Errorf("invalid conversation_id: %w", err)
return nil, listRecentMessagesOut{}, err
}
limit := in.Limit
@@ -179,7 +199,7 @@ func registerListRecentMessages(srv *mcpsdk.Server, deps ServerDeps) {
limit = 200
}
msgs, err := deps.Messages.ListMessages(ctx, c.UserID, convID, in.BeforeID, limit)
msgs, err := deps.Messages.ListMessages(ctx, c.UserID, cv.ID, in.BeforeID, limit)
if err != nil {
return nil, listRecentMessagesOut{}, err
}
@@ -248,6 +268,13 @@ func registerListConversations(srv *mcpsdk.Server, deps ServerDeps) {
}
out := listConversationsOut{Conversations: make([]conversationDetail, 0, len(cvs))}
for i := range cvs {
// 与 list_acp_sessions 一致:scope 外项目挂载的会话静默跳过;
// ProjectID 为 nil 的个人会话不受 project scope 约束。
if cvs[i].ProjectID != nil {
if err := CheckProjectFromCtx(ctx, *cvs[i].ProjectID); err != nil {
continue
}
}
out.Conversations = append(out.Conversations, conversationDetailFrom(&cvs[i]))
}
return nil, out, nil
@@ -276,10 +303,6 @@ func registerGetConversation(srv *mcpsdk.Server, deps ServerDeps) {
if err != nil {
return nil, getConversationOut{}, err
}
convID, err := uuid.Parse(in.ConversationID)
if err != nil {
return nil, getConversationOut{}, errs.Wrap(err, errs.CodeInvalidInput, "conversation_id parse")
}
limit := in.Limit
if limit <= 0 {
limit = 50
@@ -287,7 +310,7 @@ func registerGetConversation(srv *mcpsdk.Server, deps ServerDeps) {
if limit > 200 {
limit = 200
}
cv, msgs, err := deps.Conversations.Get(ctx, c.UserID, convID, limit)
cv, msgs, err := scopedConversation(ctx, deps, c.UserID, in.ConversationID, limit)
if err != nil {
return nil, getConversationOut{}, err
}
@@ -378,11 +401,11 @@ func registerUpdateConversationTitle(srv *mcpsdk.Server, deps ServerDeps) {
if err != nil {
return nil, okOut{}, err
}
convID, err := uuid.Parse(in.ConversationID)
cv, _, err := scopedConversation(ctx, deps, c.UserID, in.ConversationID, 1)
if err != nil {
return nil, okOut{}, errs.Wrap(err, errs.CodeInvalidInput, "conversation_id parse")
return nil, okOut{}, err
}
if err := deps.Conversations.UpdateTitle(ctx, c.UserID, convID, in.Title); err != nil {
if err := deps.Conversations.UpdateTitle(ctx, c.UserID, cv.ID, in.Title); err != nil {
return nil, okOut{}, err
}
return nil, okOut{OK: true}, nil
@@ -406,11 +429,11 @@ func registerDeleteConversation(srv *mcpsdk.Server, deps ServerDeps) {
if err != nil {
return nil, okOut{}, err
}
convID, err := uuid.Parse(in.ConversationID)
cv, _, err := scopedConversation(ctx, deps, c.UserID, in.ConversationID, 1)
if err != nil {
return nil, okOut{}, errs.Wrap(err, errs.CodeInvalidInput, "conversation_id parse")
return nil, okOut{}, err
}
if err := deps.Conversations.SoftDelete(ctx, c.UserID, convID); err != nil {
if err := deps.Conversations.SoftDelete(ctx, c.UserID, cv.ID); err != nil {
return nil, okOut{}, err
}
return nil, okOut{OK: true}, nil
@@ -440,11 +463,11 @@ func registerSendMessage(srv *mcpsdk.Server, deps ServerDeps) {
if err != nil {
return nil, sendMessageOut{}, err
}
convID, err := uuid.Parse(in.ConversationID)
cv, _, err := scopedConversation(ctx, deps, c.UserID, in.ConversationID, 1)
if err != nil {
return nil, sendMessageOut{}, errs.Wrap(err, errs.CodeInvalidInput, "conversation_id parse")
return nil, sendMessageOut{}, err
}
userMsgID, assistantMsgID, err := deps.Messages.Send(ctx, c.UserID, convID, in.Content, nil)
userMsgID, assistantMsgID, err := deps.Messages.Send(ctx, c.UserID, cv.ID, in.Content, nil)
if err != nil {
return nil, sendMessageOut{}, err
}