Refactor MCP integration to use structured handlers with snake_case
This commit is contained in:
165
mcp.go
165
mcp.go
@@ -2,22 +2,73 @@ package taskcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
)
|
||||
|
||||
func RegisterMCPTools(s *server.MCPServer, service *Service) error {
|
||||
s.AddTool(
|
||||
type setTaskSuccessArgs struct {
|
||||
ProjectID string `json:"project_id"`
|
||||
TaskID string `json:"task_id"`
|
||||
Result string `json:"result"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
type setTaskFailureArgs struct {
|
||||
ProjectID string `json:"project_id"`
|
||||
TaskID string `json:"task_id"`
|
||||
Error string `json:"error"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
type taskResponse struct {
|
||||
TaskID string `json:"task_id"`
|
||||
Message string `json:"message"`
|
||||
NextTask *Task `json:"next_task,omitempty"`
|
||||
}
|
||||
|
||||
type errorResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type ServiceHandlerFunc[TArgs any, TResponse any] func(s *Service, ctx context.Context, args TArgs) (*TResponse, error)
|
||||
|
||||
func wrapServiceHandler[TArgs any, TResponse any](s *Service, handler ServiceHandlerFunc[TArgs, TResponse]) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var args TArgs
|
||||
if err := request.BindArguments(&args); err != nil {
|
||||
errorJSON, _ := json.Marshal(errorResponse{Error: err.Error()})
|
||||
return mcp.NewToolResultText(string(errorJSON)), nil
|
||||
}
|
||||
|
||||
response, err := handler(s, ctx, args)
|
||||
if err != nil {
|
||||
errorJSON, _ := json.Marshal(errorResponse{Error: err.Error()})
|
||||
return mcp.NewToolResultText(string(errorJSON)), nil
|
||||
}
|
||||
|
||||
resultJSON, err := json.MarshalIndent(response, "", " ")
|
||||
if err != nil {
|
||||
errorJSON, _ := json.Marshal(errorResponse{Error: err.Error()})
|
||||
return mcp.NewToolResultText(string(errorJSON)), nil
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText(string(resultJSON)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) RegisterMCPTools(mcpServer *server.MCPServer) error {
|
||||
mcpServer.AddTool(
|
||||
mcp.NewTool(
|
||||
"SetTaskSuccess",
|
||||
"set_task_success",
|
||||
mcp.WithDescription("Mark a task as successfully completed"),
|
||||
mcp.WithString("projectId",
|
||||
mcp.WithString("project_id",
|
||||
mcp.Required(),
|
||||
mcp.Description("The project ID"),
|
||||
),
|
||||
mcp.WithString("taskId",
|
||||
mcp.WithString("task_id",
|
||||
mcp.Required(),
|
||||
mcp.Description("The task ID to mark as successful"),
|
||||
),
|
||||
@@ -29,18 +80,18 @@ func RegisterMCPTools(s *server.MCPServer, service *Service) error {
|
||||
mcp.Description("Additional notes about the task completion"),
|
||||
),
|
||||
),
|
||||
handleSetTaskSuccess(service),
|
||||
wrapServiceHandler(s, handleSetTaskSuccess),
|
||||
)
|
||||
|
||||
s.AddTool(
|
||||
mcpServer.AddTool(
|
||||
mcp.NewTool(
|
||||
"SetTaskFailure",
|
||||
"set_task_failure",
|
||||
mcp.WithDescription("Mark a task as failed"),
|
||||
mcp.WithString("projectId",
|
||||
mcp.WithString("project_id",
|
||||
mcp.Required(),
|
||||
mcp.Description("The project ID"),
|
||||
),
|
||||
mcp.WithString("taskId",
|
||||
mcp.WithString("task_id",
|
||||
mcp.Required(),
|
||||
mcp.Description("The task ID to mark as failed"),
|
||||
),
|
||||
@@ -52,78 +103,42 @@ func RegisterMCPTools(s *server.MCPServer, service *Service) error {
|
||||
mcp.Description("Additional notes about the task failure"),
|
||||
),
|
||||
),
|
||||
handleSetTaskFailure(service),
|
||||
wrapServiceHandler(s, handleSetTaskFailure),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSetTaskSuccess(service *Service) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
projectId, err := request.RequireString("projectId")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get projectId: %w", err)
|
||||
}
|
||||
|
||||
taskId, err := request.RequireString("taskId")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get taskId: %w", err)
|
||||
}
|
||||
|
||||
result, err := request.RequireString("result")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get result: %w", err)
|
||||
}
|
||||
|
||||
notes := request.GetString("notes", "")
|
||||
|
||||
project, err := service.GetProject(projectId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get project: %w", err)
|
||||
}
|
||||
|
||||
nextTask := project.SetTaskSuccess(taskId, result, notes)
|
||||
|
||||
message := fmt.Sprintf("Task %s marked as successful", taskId)
|
||||
if nextTask != nil {
|
||||
message += fmt.Sprintf("\nNext task: %s (ID: %s)", nextTask.Instructions, nextTask.ID)
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText(message), nil
|
||||
func handleSetTaskSuccess(s *Service, ctx context.Context, args setTaskSuccessArgs) (*taskResponse, error) {
|
||||
project, err := s.GetProject(args.ProjectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get project: %w", err)
|
||||
}
|
||||
|
||||
nextTask := project.SetTaskSuccess(args.TaskID, args.Result, args.Notes)
|
||||
|
||||
response := &taskResponse{
|
||||
TaskID: args.TaskID,
|
||||
Message: fmt.Sprintf("Task %s marked as successful", args.TaskID),
|
||||
NextTask: nextTask,
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func handleSetTaskFailure(service *Service) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
projectId, err := request.RequireString("projectId")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get projectId: %w", err)
|
||||
}
|
||||
|
||||
taskId, err := request.RequireString("taskId")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get taskId: %w", err)
|
||||
}
|
||||
|
||||
errorMsg, err := request.RequireString("error")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get error: %w", err)
|
||||
}
|
||||
|
||||
notes := request.GetString("notes", "")
|
||||
|
||||
project, err := service.GetProject(projectId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get project: %w", err)
|
||||
}
|
||||
|
||||
nextTask := project.SetTaskFailure(taskId, errorMsg, notes)
|
||||
|
||||
message := fmt.Sprintf("Task %s marked as failed", taskId)
|
||||
if nextTask != nil {
|
||||
message += fmt.Sprintf("\nNext task: %s (ID: %s)", nextTask.Instructions, nextTask.ID)
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText(message), nil
|
||||
func handleSetTaskFailure(s *Service, ctx context.Context, args setTaskFailureArgs) (*taskResponse, error) {
|
||||
project, err := s.GetProject(args.ProjectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get project: %w", err)
|
||||
}
|
||||
|
||||
nextTask := project.SetTaskFailure(args.TaskID, args.Error, args.Notes)
|
||||
|
||||
response := &taskResponse{
|
||||
TaskID: args.TaskID,
|
||||
Message: fmt.Sprintf("Task %s marked as failed", args.TaskID),
|
||||
NextTask: nextTask,
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user