feat: enhance MCP tool descriptions with comprehensive usage guidelines

Amolith created

- Add detailed workflow instructions for all tools with proper sequencing
- Document enum constraints and parameter limits in natural language
- Include system prompt requirements for task creation workflow
- Clarify when to include optional parameters vs when to omit them
- Add speech-to-text interpretation guidance for better user experience

Change summary

cmd/lunatask-mcp-server.go | 60 ++++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 30 deletions(-)

Detailed changes

cmd/lunatask-mcp-server.go 🔗

@@ -197,9 +197,9 @@ func NewMCPServer(appConfig *Config) *server.MCPServer {
 	toolHandlers := tools.NewHandlers(handlerCfg)
 
 	mcpServer.AddTool(mcp.NewTool("get_timestamp",
-		mcp.WithDescription("Retrieves the formatted timestamp for a task"),
+		mcp.WithDescription("Parses natural language dates into formatted timestamps for task scheduling. Use this tool when creating or updating tasks that include dates or times (after using list_areas_and_goals first). Supports relative dates (e.g., 'tomorrow', '1 week', 'next friday'), absolute dates (e.g., 'january 15', '2024-03-10'), and times (e.g., 'at 2pm', 'sunday at 19:00'). Also accepts 'now' for current timestamp."),
 		mcp.WithString("natural_language_date",
-			mcp.Description("Natural language date as described by the user, e.g. '1 week', 'tomorrow', 'sunday at 19:00', 'now', etc."),
+			mcp.Description("Natural language date expression. Examples: 'tomorrow', '1 week', 'sunday at 19:00', 'january 15 at 2pm', 'next friday', 'now'. The tool will parse this into a properly formatted timestamp for use with task scheduling."),
 			mcp.Required(),
 		),
 	), toolHandlers.HandleGetTimestamp)
@@ -207,94 +207,94 @@ func NewMCPServer(appConfig *Config) *server.MCPServer {
 	mcpServer.AddTool(
 		mcp.NewTool(
 			"list_areas_and_goals",
-			mcp.WithDescription("List areas and goals and their IDs."),
+			mcp.WithDescription("Lists all available areas and their associated goals with their IDs. Use this tool FIRST before creating or updating tasks to identify valid area_id and goal_id values. Areas represent broad categories of work, and goals are specific objectives within those areas. Each task must belong to an area and can optionally be associated with a goal within that area."),
 		),
 		toolHandlers.HandleListAreasAndGoals,
 	)
 
 	mcpServer.AddTool(mcp.NewTool("create_task",
-		mcp.WithDescription("Creates a new task"),
+		mcp.WithDescription("Creates a new task in Lunatask. WORKFLOW: First use list_areas_and_goals to identify valid area_id and goal_id values, then use get_timestamp if scheduling the task. Only include optional parameters if the user indicates or hints at them. Try to interpret speech-to-text input that may not be entirely accurate."),
 		mcp.WithString("area_id",
-			mcp.Description("Area ID in which to create the task"),
+			mcp.Description("Area ID in which to create the task. Must be a valid area_id from list_areas_and_goals tool."),
 			mcp.Required(),
 		),
 		mcp.WithString("goal_id",
-			mcp.Description("Goal ID, which must belong to the provided area, to associate the task with."),
+			mcp.Description("Optional goal ID to associate the task with. Must be a valid goal_id from list_areas_and_goals that belongs to the specified area. Only include if the task relates to a specific goal."),
 		),
 		mcp.WithString("name",
 			mcp.Description("Plain text task name using sentence case."),
 			mcp.Required(),
 		),
 		mcp.WithString("note",
-			mcp.Description("Note attached to the task, optionally Markdown-formatted"),
+			mcp.Description("Additional details or notes for the task, using Markdown formatting. Include any extra context, requirements, or information provided by the user that doesn't fit in the task name."),
 		),
 		mcp.WithNumber("estimate",
-			mcp.Description("Estimated time completion time in minutes"),
+			mcp.Description("Estimated completion time in minutes (0-1440, max 24 hours). Only include if user mentions a time estimate like '30 minutes' (pass 30) or '2 hours' (pass 120). Omit if no estimate is provided."),
 			mcp.Min(0),
 			mcp.Max(1440),
 		),
 		mcp.WithString("priority",
-			mcp.Description("Task priority, omit unless priority is mentioned"),
+			mcp.Description("Task priority level. Valid values: 'lowest', 'low', 'neutral', 'high', 'highest'. Only include if user explicitly mentions priority or urgency. Omit for normal tasks."),
 			mcp.Enum("lowest", "low", "neutral", "high", "highest"),
 		),
 		mcp.WithString("motivation",
-			mcp.Description("Motivation driving task creation"),
+			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("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.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"),
 		),
 		mcp.WithString("scheduled_on",
-			mcp.Description("Formatted timestamp from get_task_timestamp tool"),
+			mcp.Description("Scheduled date/time for the task. Must use the formatted timestamp returned by get_timestamp tool. Only include if user specifies when the task should be done."),
 		),
 	), toolHandlers.HandleCreateTask)
 
 	mcpServer.AddTool(mcp.NewTool("update_task",
-		mcp.WithDescription("Updates an existing task. Only provided fields will be targeted for update."),
+		mcp.WithDescription("Updates an existing task. Only provided fields will be updated. WORKFLOW: Use list_areas_and_goals first if changing area/goal, then get_timestamp if changing schedule. Only include parameters that are being changed. Empty strings will clear existing values for text fields."),
 		mcp.WithString("task_id",
 			mcp.Description("ID of the task to update."),
 			mcp.Required(),
 		),
 		mcp.WithString("area_id",
-			mcp.Description("New Area ID for the task. Must be a valid Area ID from 'list_areas_and_goals'."),
+			mcp.Description("New Area ID for the task. Must be a valid area_id from list_areas_and_goals tool. Only include if moving the task to a different area."),
 		),
 		mcp.WithString("goal_id",
-			mcp.Description("New Goal ID for the task. Must be a valid Goal ID from 'list_areas_and_goals'."),
+			mcp.Description("New Goal ID for the task. Must be a valid goal_id from list_areas_and_goals that belongs to the task's area (current or new). Only include if changing the goal association."),
 		),
 		mcp.WithString("name",
 			mcp.Description("New plain text task name using sentence case. Sending an empty string WILL clear the name."),
 			mcp.Required(),
 		),
 		mcp.WithString("note",
-			mcp.Description("New note attached to the task, optionally Markdown-formatted. Sending an empty string WILL clear the note."),
+			mcp.Description("New note for the task, using Markdown formatting. Sending an empty string WILL clear the existing note. Only include if changing the task notes."),
 		),
 		mcp.WithNumber("estimate",
-			mcp.Description("New estimated time completion time in minutes."),
+			mcp.Description("New estimated completion time in minutes (0-720, max 12 hours). Only include if user mentions changing the time estimate. Note: update_task has a lower maximum than create_task."),
 			mcp.Min(0),
-			mcp.Max(720), // Aligned with CreateTaskRequest validation tag
+			mcp.Max(720),
 		),
 		mcp.WithString("priority",
-			mcp.Description("Task priority, omit unless priority is mentioned"),
+			mcp.Description("New task priority level. Valid values: 'lowest', 'low', 'neutral', 'high', 'highest'. Only include if user wants to change the priority."),
 			mcp.Enum("lowest", "low", "neutral", "high", "highest"),
 		),
 		mcp.WithString("motivation",
-			mcp.Description("New motivation driving the task."),
-			mcp.Enum("must", "should", "want", ""), // Allow empty string to potentially clear/unset
+			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("status",
-			mcp.Description("New task state."),
-			mcp.Enum("later", "next", "started", "waiting", "completed", ""), // Allow empty string
+			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", ""),
 		),
 		mcp.WithString("scheduled_on",
-			mcp.Description("New scheduled date/time as a formatted timestamp from get_task_timestamp tool. Sending an empty string might clear the scheduled date."),
+			mcp.Description("New scheduled date/time for the task. Must use the formatted timestamp returned by get_timestamp tool. Sending an empty string might clear the scheduled date. Only include if changing the schedule."),
 		),
 	), toolHandlers.HandleUpdateTask)
 
 	mcpServer.AddTool(mcp.NewTool("delete_task",
-		mcp.WithDescription("Deletes an existing task"),
+		mcp.WithDescription("Permanently deletes an existing task from Lunatask. This action cannot be undone."),
 		mcp.WithString("task_id",
-			mcp.Description("ID of the task to delete."),
+			mcp.Description("ID of the task to delete. This must be a valid task ID from an existing task in Lunatask."),
 			mcp.Required(),
 		),
 	), toolHandlers.HandleDeleteTask)
@@ -302,19 +302,19 @@ func NewMCPServer(appConfig *Config) *server.MCPServer {
 	mcpServer.AddTool(
 		mcp.NewTool(
 			"list_habits_and_activities",
-			mcp.WithDescription("List habits and their IDs for tracking or marking complete with tracking_habit_activity"),
+			mcp.WithDescription("Lists all configured habits and their IDs for habit tracking. Use this tool FIRST before track_habit_activity to identify valid habit_id values. Shows habit names, descriptions, and unique identifiers needed for tracking activities."),
 		),
 		toolHandlers.HandleListHabitsAndActivities,
 	)
 
 	mcpServer.AddTool(mcp.NewTool("track_habit_activity",
-		mcp.WithDescription("Tracks an activity or a habit in Lunatask"),
+		mcp.WithDescription("Records completion of a habit activity in Lunatask. WORKFLOW: First use list_habits_and_activities to get valid habit_id, then use get_timestamp to format the performed_on date."),
 		mcp.WithString("habit_id",
-			mcp.Description("ID of the habit to track activity for."),
+			mcp.Description("ID of the habit to track activity for. Must be a valid habit_id from list_habits_and_activities tool."),
 			mcp.Required(),
 		),
 		mcp.WithString("performed_on",
-			mcp.Description("The timestamp the habit was performed, first obtained with get_timestamp."),
+			mcp.Description("Timestamp when the habit was performed. Must use the formatted timestamp returned by get_timestamp tool. Examples: if user says 'I did this yesterday', use get_timestamp with 'yesterday'."),
 			mcp.Required(),
 		),
 	), toolHandlers.HandleTrackHabitActivity)