From 5c18f05d9404554ef0da0305ee4850ba65433226 Mon Sep 17 00:00:00 2001 From: Amolith Date: Sun, 11 May 2025 15:52:46 -0600 Subject: [PATCH] feat(task): implement task deletion capability This commit introduces the functionality to delete tasks. It adds a `DeleteTask` method to the Lunatask client, along with a `DeleteTaskResponse` struct, enabling interaction with the Lunatask API's task deletion endpoint. Additionally, a new `delete_task` tool and its corresponding `handleDeleteTask` handler are integrated into the MCP server, exposing this new capability. --- lunatask/tasks.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/lunatask/tasks.go b/lunatask/tasks.go index fb5cb0130c711c7052f3dbbbd40863717642950d..daa35329cd28282c3bda3cba5679c3a7016cccbc 100644 --- a/lunatask/tasks.go +++ b/lunatask/tasks.go @@ -85,6 +85,11 @@ type UpdateTaskResponse struct { Task Task `json:"task"` } +// DeleteTaskResponse represents the response from Lunatask API when deleting a task +type DeleteTaskResponse struct { + Task Task `json:"task"` +} + // ValidationError represents errors returned by the validator type ValidationError struct { Field string @@ -257,3 +262,57 @@ func (c *Client) UpdateTask(ctx context.Context, taskID string, task *CreateTask return &response, nil } + +// DeleteTask deletes a task in Lunatask +func (c *Client) DeleteTask(ctx context.Context, taskID string) (*DeleteTaskResponse, error) { + if taskID == "" { + return nil, errors.New("task ID cannot be empty") + } + + // Create the request + req, err := http.NewRequestWithContext( + ctx, + "DELETE", + fmt.Sprintf("%s/tasks/%s", c.BaseURL, taskID), + nil, + ) + if err != nil { + return nil, fmt.Errorf("failed to create HTTP request: %w", err) + } + + // Set headers + req.Header.Set("Authorization", "bearer "+c.AccessToken) + + // Send the request + resp, err := c.HTTPClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to send HTTP request: %w", err) + } + defer func() { + if resp.Body != nil { + if err := resp.Body.Close(); err != nil { + fmt.Printf("Error closing response body: %v\n", err) + } + } + }() + + // Handle error status codes + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + respBody, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(respBody)) + } + + // Read and parse the response + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + var response DeleteTaskResponse + err = json.Unmarshal(respBody, &response) + if err != nil { + return nil, fmt.Errorf("failed to parse response: %w", err) + } + + return &response, nil +} diff --git a/main.go b/main.go index 7a8312d0294cd461a97ba7e6a1c33873771464da..71b8d312e6897eefdf791f043189673032b88be2 100644 --- a/main.go +++ b/main.go @@ -297,6 +297,16 @@ func NewMCPServer(config *Config) *server.MCPServer { return handleUpdateTask(ctx, request, config) }) + mcpServer.AddTool(mcp.NewTool("delete_task", + mcp.WithDescription("Deletes an existing task"), + mcp.WithString("task_id", + mcp.Description("ID of the task to delete."), + mcp.Required(), + ), + ), func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return handleDeleteTask(ctx, request, config) + }) + return mcpServer } @@ -619,6 +629,37 @@ func handleUpdateTask( }, nil } +func handleDeleteTask( + ctx context.Context, + request mcp.CallToolRequest, + config *Config, +) (*mcp.CallToolResult, error) { + arguments := request.Params.Arguments + + taskID, ok := arguments["task_id"].(string) + if !ok || taskID == "" { + return reportMCPError("Missing or invalid required argument: task_id") + } + + // Create Lunatask client + client := lunatask.NewClient(config.AccessToken) + + // Call the client to delete the task + _, err := client.DeleteTask(ctx, taskID) + if err != nil { + return reportMCPError(fmt.Sprintf("Failed to delete task: %v", err)) + } + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + mcp.TextContent{ + Type: "text", + Text: "Task deleted successfully.", + }, + }, + }, nil +} + func createDefaultConfigFile(configPath string) { defaultConfig := Config{ Server: ServerConfig{