fix: align MCP tool parameters and JSON tags with backend (#329)
This commit is contained in:
@@ -10,9 +10,10 @@ import (
|
||||
)
|
||||
|
||||
// MCP action constants for backend WS requests
|
||||
// These must match the actions registered in pkg/websocket/actions.go
|
||||
const (
|
||||
ActionMCPListWorkspaces = "mcp.list_workspaces"
|
||||
ActionMCPListBoards = "mcp.list_boards"
|
||||
ActionMCPListWorkflows = "mcp.list_workflows"
|
||||
ActionMCPListWorkflowSteps = "mcp.list_workflow_steps"
|
||||
ActionMCPListTasks = "mcp.list_tasks"
|
||||
ActionMCPCreateTask = "mcp.create_task"
|
||||
@@ -26,7 +27,8 @@ const (
|
||||
|
||||
func (s *Server) listWorkspacesHandler() server.ToolHandlerFunc {
|
||||
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var result []map[string]interface{}
|
||||
// Backend returns {workspaces: [...], total: N}
|
||||
var result map[string]interface{}
|
||||
if err := s.backend.RequestPayload(ctx, ActionMCPListWorkspaces, nil, &result); err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
@@ -35,15 +37,16 @@ func (s *Server) listWorkspacesHandler() server.ToolHandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) listBoardsHandler() server.ToolHandlerFunc {
|
||||
func (s *Server) listWorkflowsHandler() server.ToolHandlerFunc {
|
||||
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
workspaceID, err := req.RequireString("workspace_id")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError("workspace_id is required"), nil
|
||||
}
|
||||
payload := map[string]string{"workspace_id": workspaceID}
|
||||
var result []map[string]interface{}
|
||||
if err := s.backend.RequestPayload(ctx, ActionMCPListBoards, payload, &result); err != nil {
|
||||
// Backend returns {workflows: [...], total: N}
|
||||
var result map[string]interface{}
|
||||
if err := s.backend.RequestPayload(ctx, ActionMCPListWorkflows, payload, &result); err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
data, _ := json.MarshalIndent(result, "", " ")
|
||||
@@ -53,12 +56,13 @@ func (s *Server) listBoardsHandler() server.ToolHandlerFunc {
|
||||
|
||||
func (s *Server) listWorkflowStepsHandler() server.ToolHandlerFunc {
|
||||
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
boardID, err := req.RequireString("board_id")
|
||||
workflowID, err := req.RequireString("workflow_id")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError("board_id is required"), nil
|
||||
return mcp.NewToolResultError("workflow_id is required"), nil
|
||||
}
|
||||
payload := map[string]string{"board_id": boardID}
|
||||
var result []map[string]interface{}
|
||||
payload := map[string]string{"workflow_id": workflowID}
|
||||
// Backend returns {workflow_steps: [...], total: N}
|
||||
var result map[string]interface{}
|
||||
if err := s.backend.RequestPayload(ctx, ActionMCPListWorkflowSteps, payload, &result); err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
@@ -69,12 +73,13 @@ func (s *Server) listWorkflowStepsHandler() server.ToolHandlerFunc {
|
||||
|
||||
func (s *Server) listTasksHandler() server.ToolHandlerFunc {
|
||||
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
boardID, err := req.RequireString("board_id")
|
||||
workflowID, err := req.RequireString("workflow_id")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError("board_id is required"), nil
|
||||
return mcp.NewToolResultError("workflow_id is required"), nil
|
||||
}
|
||||
payload := map[string]string{"board_id": boardID}
|
||||
var result []map[string]interface{}
|
||||
payload := map[string]string{"workflow_id": workflowID}
|
||||
// Backend returns {tasks: [...], total: N}
|
||||
var result map[string]interface{}
|
||||
if err := s.backend.RequestPayload(ctx, ActionMCPListTasks, payload, &result); err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
@@ -89,9 +94,9 @@ func (s *Server) createTaskHandler() server.ToolHandlerFunc {
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError("workspace_id is required"), nil
|
||||
}
|
||||
boardID, err := req.RequireString("board_id")
|
||||
workflowID, err := req.RequireString("workflow_id")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError("board_id is required"), nil
|
||||
return mcp.NewToolResultError("workflow_id is required"), nil
|
||||
}
|
||||
workflowStepID, err := req.RequireString("workflow_step_id")
|
||||
if err != nil {
|
||||
@@ -105,7 +110,7 @@ func (s *Server) createTaskHandler() server.ToolHandlerFunc {
|
||||
|
||||
payload := map[string]string{
|
||||
"workspace_id": workspaceID,
|
||||
"board_id": boardID,
|
||||
"workflow_id": workflowID,
|
||||
"workflow_step_id": workflowStepID,
|
||||
"title": title,
|
||||
"description": description,
|
||||
|
||||
@@ -206,31 +206,31 @@ func (s *Server) registerKanbanTools() {
|
||||
s.wrapHandler("list_workspaces", s.listWorkspacesHandler()),
|
||||
)
|
||||
s.mcpServer.AddTool(
|
||||
mcp.NewTool("list_boards",
|
||||
mcp.WithDescription("List all boards in a workspace."),
|
||||
mcp.NewTool("list_workflows",
|
||||
mcp.WithDescription("List all workflows in a workspace."),
|
||||
mcp.WithString("workspace_id", mcp.Required(), mcp.Description("The workspace ID")),
|
||||
),
|
||||
s.wrapHandler("list_boards", s.listBoardsHandler()),
|
||||
s.wrapHandler("list_workflows", s.listWorkflowsHandler()),
|
||||
)
|
||||
s.mcpServer.AddTool(
|
||||
mcp.NewTool("list_workflow_steps",
|
||||
mcp.WithDescription("List all workflow steps in a board."),
|
||||
mcp.WithString("board_id", mcp.Required(), mcp.Description("The board ID")),
|
||||
mcp.WithDescription("List all workflow steps in a workflow."),
|
||||
mcp.WithString("workflow_id", mcp.Required(), mcp.Description("The workflow ID")),
|
||||
),
|
||||
s.wrapHandler("list_workflow_steps", s.listWorkflowStepsHandler()),
|
||||
)
|
||||
s.mcpServer.AddTool(
|
||||
mcp.NewTool("list_tasks",
|
||||
mcp.WithDescription("List all tasks on a board."),
|
||||
mcp.WithString("board_id", mcp.Required(), mcp.Description("The board ID")),
|
||||
mcp.WithDescription("List all tasks in a workflow."),
|
||||
mcp.WithString("workflow_id", mcp.Required(), mcp.Description("The workflow ID")),
|
||||
),
|
||||
s.wrapHandler("list_tasks", s.listTasksHandler()),
|
||||
)
|
||||
s.mcpServer.AddTool(
|
||||
mcp.NewTool("create_task",
|
||||
mcp.WithDescription("Create a new task on a board."),
|
||||
mcp.WithDescription("Create a new task in a workflow."),
|
||||
mcp.WithString("workspace_id", mcp.Required(), mcp.Description("The workspace ID")),
|
||||
mcp.WithString("board_id", mcp.Required(), mcp.Description("The board ID")),
|
||||
mcp.WithString("workflow_id", mcp.Required(), mcp.Description("The workflow ID")),
|
||||
mcp.WithString("workflow_step_id", mcp.Required(), mcp.Description("The workflow step ID")),
|
||||
mcp.WithString("title", mcp.Required(), mcp.Description("The task title")),
|
||||
mcp.WithString("description", mcp.Description("The task description")),
|
||||
|
||||
@@ -188,7 +188,14 @@ func (h *Handlers) handleListTasks(ctx context.Context, msg *ws.Message) (*ws.Me
|
||||
|
||||
// handleCreateTask creates a new task.
|
||||
func (h *Handlers) handleCreateTask(ctx context.Context, msg *ws.Message) (*ws.Message, error) {
|
||||
var req dto.CreateTaskRequest
|
||||
// Use local struct with JSON tags since dto.CreateTaskRequest lacks them
|
||||
var req struct {
|
||||
WorkspaceID string `json:"workspace_id"`
|
||||
WorkflowID string `json:"workflow_id"`
|
||||
WorkflowStepID string `json:"workflow_step_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
if err := json.Unmarshal(msg.Payload, &req); err != nil {
|
||||
return ws.NewError(msg.ID, msg.Action, ws.ErrorCodeBadRequest, "Invalid payload: "+err.Error(), nil)
|
||||
}
|
||||
@@ -205,28 +212,12 @@ func (h *Handlers) handleCreateTask(ctx context.Context, msg *ws.Message) (*ws.M
|
||||
return ws.NewError(msg.ID, msg.Action, ws.ErrorCodeValidation, "title is required", nil)
|
||||
}
|
||||
|
||||
var repos []service.TaskRepositoryInput
|
||||
for _, r := range req.Repositories {
|
||||
repos = append(repos, service.TaskRepositoryInput{
|
||||
RepositoryID: r.RepositoryID,
|
||||
BaseBranch: r.BaseBranch,
|
||||
LocalPath: r.LocalPath,
|
||||
Name: r.Name,
|
||||
DefaultBranch: r.DefaultBranch,
|
||||
})
|
||||
}
|
||||
|
||||
task, err := h.taskSvc.CreateTask(ctx, &service.CreateTaskRequest{
|
||||
WorkspaceID: req.WorkspaceID,
|
||||
WorkflowID: req.WorkflowID,
|
||||
WorkflowStepID: req.WorkflowStepID,
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
Priority: req.Priority,
|
||||
State: req.State,
|
||||
Repositories: repos,
|
||||
Position: req.Position,
|
||||
Metadata: req.Metadata,
|
||||
})
|
||||
if err != nil {
|
||||
h.logger.Error("failed to create task", zap.Error(err))
|
||||
@@ -238,33 +229,23 @@ func (h *Handlers) handleCreateTask(ctx context.Context, msg *ws.Message) (*ws.M
|
||||
|
||||
// handleUpdateTask updates an existing task.
|
||||
func (h *Handlers) handleUpdateTask(ctx context.Context, msg *ws.Message) (*ws.Message, error) {
|
||||
var req dto.UpdateTaskRequest
|
||||
// Use local struct with JSON tags since dto.UpdateTaskRequest lacks them
|
||||
var req struct {
|
||||
TaskID string `json:"task_id"`
|
||||
Title *string `json:"title"`
|
||||
Description *string `json:"description"`
|
||||
State *string `json:"state"`
|
||||
}
|
||||
if err := json.Unmarshal(msg.Payload, &req); err != nil {
|
||||
return ws.NewError(msg.ID, msg.Action, ws.ErrorCodeBadRequest, "Invalid payload: "+err.Error(), nil)
|
||||
}
|
||||
if req.ID == "" {
|
||||
return ws.NewError(msg.ID, msg.Action, ws.ErrorCodeValidation, "id is required", nil)
|
||||
if req.TaskID == "" {
|
||||
return ws.NewError(msg.ID, msg.Action, ws.ErrorCodeValidation, "task_id is required", nil)
|
||||
}
|
||||
|
||||
var repos []service.TaskRepositoryInput
|
||||
for _, r := range req.Repositories {
|
||||
repos = append(repos, service.TaskRepositoryInput{
|
||||
RepositoryID: r.RepositoryID,
|
||||
BaseBranch: r.BaseBranch,
|
||||
LocalPath: r.LocalPath,
|
||||
Name: r.Name,
|
||||
DefaultBranch: r.DefaultBranch,
|
||||
})
|
||||
}
|
||||
|
||||
task, err := h.taskSvc.UpdateTask(ctx, req.ID, &service.UpdateTaskRequest{
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
Priority: req.Priority,
|
||||
State: req.State,
|
||||
Repositories: repos,
|
||||
Position: req.Position,
|
||||
Metadata: req.Metadata,
|
||||
task, err := h.taskSvc.UpdateTask(ctx, req.TaskID, &service.UpdateTaskRequest{
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
})
|
||||
if err != nil {
|
||||
h.logger.Error("failed to update task", zap.Error(err))
|
||||
|
||||
Reference in New Issue
Block a user