@@ -167,6 +167,7 @@ func NewMCPServer(config *Config) *server.MCPServer {
"Lunatask MCP Server",
"0.1.0",
server.WithHooks(hooks),
+ server.WithToolCapabilities(true),
)
mcpServer.AddTool(mcp.NewTool("get_task_timestamp",
@@ -225,11 +226,11 @@ func NewMCPServer(config *Config) *server.MCPServer {
mcpServer.AddTool(mcp.NewTool("create_task",
mcp.WithDescription("Creates a new task"),
mcp.WithString("area_id",
- mcp.Description("ID of the area in which to create the task"),
+ mcp.Description("Area ID in which to create the task"),
mcp.Required(),
),
mcp.WithString("goal_id",
- mcp.Description("ID of the goal, which must belong to the specified area, that the task should be associated with."),
+ mcp.Description("Goal ID, which must belong to the provided area, to associate the task with."),
),
mcp.WithString("name",
mcp.Description("Plain text task name using sentence case."),
@@ -239,10 +240,25 @@ func NewMCPServer(config *Config) *server.MCPServer {
mcp.Description("Note attached to the task, optionally Markdown-formatted"),
),
mcp.WithNumber("estimate",
- mcp.Description("Estimated time to completion in minutes"),
+ mcp.Description("Estimated time completion time in minutes"),
+ mcp.Min(0),
+ mcp.Max(1440),
+ ),
+ mcp.WithNumber("priority",
+ mcp.Description("Task priority, -2 being lowest, 0 being normal, and 2 being highest"),
+ mcp.Min(-2),
+ mcp.Max(2),
+ ),
+ mcp.WithString("motivation",
+ mcp.Description("Motivation driving task creation"),
+ mcp.Enum("must", "should", "want"),
+ ),
+ mcp.WithString("status",
+ mcp.Description("Task state, such as in progress, provided as 'started', already started, provided as 'started', soon, provided as 'next', blocked as waiting, omit unspecified, and so on. Intuit the task's status."),
+ mcp.Enum("later", "next", "started", "waiting", "completed"),
),
mcp.WithString("scheduled_on",
- mcp.Description("Formatted timestamp"),
+ mcp.Description("Formatted timestamp from get_task_timestamp tool"),
),
), func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return handleCreateTask(ctx, request, config)
@@ -322,6 +338,42 @@ func handleCreateTask(
}
}
+ if priorityVal, exists := arguments["priority"]; exists && priorityVal != nil {
+ if priority, ok := priorityVal.(float64); ok {
+ if priority < -2 || priority > 2 {
+ return reportMCPError("'priority' must be between -2 and 2 (inclusive)")
+ }
+ } else {
+ return reportMCPError("'priority' must be a number")
+ }
+ }
+
+ 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}
+ if !validMotivations[motivation] {
+ return reportMCPError("'motivation' must be one of 'must', 'should', or 'want'")
+ }
+ } else if ok {
+ // empty string is allowed
+ } else {
+ return reportMCPError("'motivation' must be a string")
+ }
+ }
+
+ if statusVal, exists := arguments["status"]; exists && statusVal != nil {
+ if status, ok := statusVal.(string); ok && status != "" {
+ validStatus := map[string]bool{"later": true, "next": true, "started": true, "waiting": true, "completed": true}
+ if !validStatus[status] {
+ return reportMCPError("'status' must be one of 'later', 'next', 'started', 'waiting', or 'completed'")
+ }
+ } else if ok {
+ // empty string is allowed
+ } else {
+ return reportMCPError("'status' must be a string")
+ }
+ }
+
// Validate scheduled_on format if provided
if scheduledOnArg, exists := arguments["scheduled_on"]; exists {
if scheduledOnStr, ok := scheduledOnArg.(string); ok && scheduledOnStr != "" {