You've already forked agentic-coding-workflow
ACP / MCP 完善
This commit is contained in:
+41
-18
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user