From 28b2b0e3ebb11bf7d68bf085289d337141aad8e5 Mon Sep 17 00:00:00 2001 From: Amolith Date: Thu, 25 Dec 2025 12:35:56 -0700 Subject: [PATCH] fix(mcp/task): require area_id in create_task The Lunatask API requires an area_id when creating tasks, but the MCP tool incorrectly documented and typed it as optional. Assisted-by: Claude Opus 4.5 via Crush --- internal/mcp/tools/task/create.go | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/internal/mcp/tools/task/create.go b/internal/mcp/tools/task/create.go index ddf47c6f943cc2c2ce689647439b322e924bf328..e0e517d325ad17746ad6b9347b67fa0a12291133 100644 --- a/internal/mcp/tools/task/create.go +++ b/internal/mcp/tools/task/create.go @@ -24,9 +24,9 @@ const CreateToolDescription = `Creates a new task in Lunatask. Required: - name: Task title +- area_id: Area UUID, lunatask:// deep link, or config key Optional: -- area_id: Area UUID, lunatask:// deep link, or config key - goal_id: Goal UUID, lunatask:// deep link, or config key (requires area_id) - status: later, next, started, waiting (default: later) - note: Markdown note/description for the task @@ -42,7 +42,7 @@ Returns the created task's ID and deep link.` // CreateInput is the input schema for creating a task. type CreateInput struct { Name string `json:"name" jsonschema:"required"` - AreaID *string `json:"area_id,omitempty"` + AreaID string `json:"area_id" jsonschema:"required"` GoalID *string `json:"goal_id,omitempty"` Status *string `json:"status,omitempty"` Note *string `json:"note,omitempty"` @@ -62,7 +62,7 @@ type CreateOutput struct { // parsedCreateInput holds validated and parsed create input fields. type parsedCreateInput struct { Name string - AreaID *string + AreaID string GoalID *string Status *lunatask.TaskStatus Note *string @@ -128,22 +128,15 @@ func parseCreateInput(cfg *config.Config, input CreateInput) (*parsedCreateInput Urgent: input.Urgent, } - if input.AreaID != nil { - areaID, err := validate.AreaRef(cfg, *input.AreaID) - if err != nil { - return nil, shared.ErrorResult(err.Error()) - } - - parsed.AreaID = &areaID + areaID, err := validate.AreaRef(cfg, input.AreaID) + if err != nil { + return nil, shared.ErrorResult(err.Error()) } - if input.GoalID != nil { - areaID := "" - if parsed.AreaID != nil { - areaID = *parsed.AreaID - } + parsed.AreaID = areaID - goalID, err := validate.GoalRef(cfg, areaID, *input.GoalID) + if input.GoalID != nil { + goalID, err := validate.GoalRef(cfg, parsed.AreaID, *input.GoalID) if err != nil { return nil, shared.ErrorResult(err.Error()) } @@ -198,9 +191,7 @@ func parseCreateInput(cfg *config.Config, input CreateInput) (*parsedCreateInput //nolint:cyclop func applyToTaskBuilder(builder *lunatask.TaskBuilder, parsed *parsedCreateInput) { - if parsed.AreaID != nil { - builder.InArea(*parsed.AreaID) - } + builder.InArea(parsed.AreaID) if parsed.GoalID != nil { builder.InGoal(*parsed.GoalID)