diff --git a/cmd/lunatask-mcp-server.go b/cmd/lunatask-mcp-server.go index 942a203469d259b60d5d5b4a0389aebeda696caf..ee981b5b8417c2b80eaa81ef341b0f4133ecff37 100644 --- a/cmd/lunatask-mcp-server.go +++ b/cmd/lunatask-mcp-server.go @@ -241,6 +241,10 @@ func NewMCPServer(appConfig *Config) *server.MCPServer { mcp.Description("Level of importance for the task. Valid values: 'must' (critical/required), 'should' (important), 'want' (nice-to-have). Only include if the user's language suggests strong obligation ('I need to', 'I have to') vs preference ('I'd like to', 'I want to')."), mcp.Enum("must", "should", "want"), ), + mcp.WithString("eisenhower", + mcp.Description("Eisenhower Matrix quadrant for task prioritization. Valid values: 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important', 'uncategorised'. Only include for areas which the user has indicated follow the Eisenhower workflow."), + mcp.Enum("both urgent and important", "urgent, but not important", "important, but not urgent", "neither urgent nor important", "uncategorised"), + ), mcp.WithString("status", mcp.Description("Initial task status. Valid values: 'later' (someday/backlog), 'next' (upcoming/soon), 'started' (in progress), 'waiting' (blocked), 'completed' (finished). Infer from context: 'working on' = 'started', 'soon'/'upcoming' = 'next', 'blocked'/'waiting for' = 'waiting'. Omit for normal new tasks (defaults to appropriate status)."), mcp.Enum("later", "next", "started", "waiting", "completed"), @@ -282,6 +286,10 @@ func NewMCPServer(appConfig *Config) *server.MCPServer { mcp.Description("New level of importance for the task. Valid values: 'must' (critical/required), 'should' (important), 'want' (nice-to-have), or empty string to clear. Only include if changing the motivation level."), mcp.Enum("must", "should", "want", ""), ), + mcp.WithString("eisenhower", + mcp.Description("New Eisenhower Matrix quadrant for task prioritization. Valid values: 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important', 'uncategorised' (clears the field). Only include for areas which the user has indicated follow the Eisenhower workflow."), + mcp.Enum("both urgent and important", "urgent, but not important", "important, but not urgent", "neither urgent nor important", "uncategorised"), + ), mcp.WithString("status", mcp.Description("New task status. Valid values: 'later' (someday/backlog), 'next' (upcoming/soon), 'started' (in progress), 'waiting' (blocked), 'completed' (finished), or empty string to clear. Only include if changing the task status."), mcp.Enum("later", "next", "started", "waiting", "completed", ""), diff --git a/lunatask/tasks.go b/lunatask/tasks.go index c87b077fbc7ee13795ee76da41241304d7ffb431..9f29fea860d4305d053933690609e00b1433b04f 100644 --- a/lunatask/tasks.go +++ b/lunatask/tasks.go @@ -52,6 +52,7 @@ type CreateTaskRequest struct { Motivation string `json:"motivation,omitempty" validate:"omitempty,oneof=must should want unknown"` Estimate int `json:"estimate,omitempty" validate:"omitempty,min=0,max=720"` Priority int `json:"priority,omitempty" validate:"omitempty,min=-2,max=2"` + Eisenhower int `json:"eisenhower,omitempty" validate:"omitempty,min=0,max=4"` ScheduledOn string `json:"scheduled_on,omitempty" validate:"omitempty"` CompletedAt string `json:"completed_at,omitempty" validate:"omitempty"` Source string `json:"source,omitempty" validate:"omitempty"` diff --git a/tools/tasks.go b/tools/tasks.go index 043c56d7da168e604c04709731770f12eba18092..edab3872d6ffb40f5b3dca78593418b915418d06 100644 --- a/tools/tasks.go +++ b/tools/tasks.go @@ -72,6 +72,26 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq arguments["priority"] = translatedPriority } + eisenhowerMap := map[string]int{ + "uncategorised": 0, + "both urgent and important": 1, + "urgent, but not important": 2, + "important, but not urgent": 3, + "neither urgent nor important": 4, + } + + if eisenhowerArg, exists := arguments["eisenhower"]; exists && eisenhowerArg != nil { + eisenhowerStr, ok := eisenhowerArg.(string) + if !ok { + return reportMCPError("Invalid type for 'eisenhower' argument: expected string.") + } + translatedEisenhower, isValid := eisenhowerMap[strings.ToLower(eisenhowerStr)] + if !isValid { + return reportMCPError(fmt.Sprintf("Invalid 'eisenhower' value: '%s'. Must be one of 'uncategorised', 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important'.", eisenhowerStr)) + } + arguments["eisenhower"] = translatedEisenhower + } + if motivationVal, exists := arguments["motivation"]; exists && motivationVal != nil { if motivation, ok := motivationVal.(string); ok && motivation != "" { validMotivations := map[string]bool{"must": true, "should": true, "want": true} @@ -246,6 +266,25 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq updatePayload.Priority = translatedPriority } + if eisenhowerArg, exists := arguments["eisenhower"]; exists && eisenhowerArg != nil { + eisenhowerStr, ok := eisenhowerArg.(string) + if !ok { + return reportMCPError("Invalid type for 'eisenhower' argument: expected string.") + } + eisenhowerMap := map[string]int{ + "uncategorised": 0, + "both urgent and important": 1, + "urgent, but not important": 2, + "important, but not urgent": 3, + "neither urgent nor important": 4, + } + translatedEisenhower, isValid := eisenhowerMap[strings.ToLower(eisenhowerStr)] + if !isValid { + return reportMCPError(fmt.Sprintf("Invalid 'eisenhower' value: '%s'. Must be one of 'uncategorised', 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important'.", eisenhowerStr)) + } + updatePayload.Eisenhower = translatedEisenhower + } + if motivationArg, exists := arguments["motivation"]; exists { if motivationStr, ok := motivationArg.(string); ok { if motivationStr != "" {