diff --git a/.changeset/two-bats-smoke.md b/.changeset/two-bats-smoke.md index 2c40b9eb..efa5aa98 100644 --- a/.changeset/two-bats-smoke.md +++ b/.changeset/two-bats-smoke.md @@ -10,4 +10,5 @@ - Implement show-task MCP command for displaying detailed task information - Implement next-task MCP command for finding the next task to work on - Implement expand-task MCP command for breaking down tasks into subtasks +- Implement add-task MCP command for creating new tasks using AI assistance - Document MCP server naming conventions in architecture.mdc and mcp.mdc files (file names use kebab-case, direct functions use camelCase with Direct suffix, tool registration functions use camelCase with Tool suffix, and MCP tool names use snake_case) diff --git a/mcp-server/src/core/direct-functions/add-task.js b/mcp-server/src/core/direct-functions/add-task.js new file mode 100644 index 00000000..b8ecd71b --- /dev/null +++ b/mcp-server/src/core/direct-functions/add-task.js @@ -0,0 +1,67 @@ +/** + * add-task.js + * Direct function implementation for adding a new task + */ + +import { addTask } from '../../../../scripts/modules/task-manager.js'; +import { findTasksJsonPath } from '../utils/path-utils.js'; + +/** + * Direct function wrapper for adding a new task with error handling. + * + * @param {Object} args - Command arguments + * @param {string} args.prompt - Description of the task to add + * @param {Array} [args.dependencies=[]] - Task dependencies as array of IDs + * @param {string} [args.priority='medium'] - Task priority (high, medium, low) + * @param {string} [args.file] - Path to the tasks file + * @param {string} [args.projectRoot] - Project root directory + * @param {Object} log - Logger object + * @returns {Promise} - Result object { success: boolean, data?: any, error?: { code: string, message: string } } + */ +export async function addTaskDirect(args, log) { + try { + // Resolve the tasks file path + const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + + // Check required parameters + if (!args.prompt) { + log.error('Missing required parameter: prompt'); + return { + success: false, + error: { + code: 'MISSING_PARAMETER', + message: 'The prompt parameter is required for adding a task' + } + }; + } + + // Extract and prepare parameters + const prompt = args.prompt; + const dependencies = Array.isArray(args.dependencies) + ? args.dependencies + : (args.dependencies ? String(args.dependencies).split(',').map(id => parseInt(id.trim(), 10)) : []); + const priority = args.priority || 'medium'; + + log.info(`Adding new task with prompt: "${prompt}", dependencies: [${dependencies.join(', ')}], priority: ${priority}`); + + // Call the addTask function + const newTaskId = await addTask(tasksPath, prompt, dependencies, priority); + + return { + success: true, + data: { + taskId: newTaskId, + message: `Successfully added new task #${newTaskId}` + } + }; + } catch (error) { + log.error(`Error in addTaskDirect: ${error.message}`); + return { + success: false, + error: { + code: 'ADD_TASK_ERROR', + message: error.message + } + }; + } +} \ No newline at end of file diff --git a/mcp-server/src/core/task-master-core.js b/mcp-server/src/core/task-master-core.js index 5ba4a812..3c28df8e 100644 --- a/mcp-server/src/core/task-master-core.js +++ b/mcp-server/src/core/task-master-core.js @@ -16,11 +16,28 @@ import { setTaskStatusDirect } from './direct-functions/set-task-status.js'; import { showTaskDirect } from './direct-functions/show-task.js'; import { nextTaskDirect } from './direct-functions/next-task.js'; import { expandTaskDirect } from './direct-functions/expand-task.js'; +import { addTaskDirect } from './direct-functions/add-task.js'; // Re-export utility functions export { findTasksJsonPath } from './utils/path-utils.js'; -// Re-export all direct functions +// Use Map for potential future enhancements like introspection or dynamic dispatch +export const directFunctions = new Map([ + ['listTasksDirect', listTasksDirect], + ['getCacheStatsDirect', getCacheStatsDirect], + ['parsePRDDirect', parsePRDDirect], + ['updateTasksDirect', updateTasksDirect], + ['updateTaskByIdDirect', updateTaskByIdDirect], + ['updateSubtaskByIdDirect', updateSubtaskByIdDirect], + ['generateTaskFilesDirect', generateTaskFilesDirect], + ['setTaskStatusDirect', setTaskStatusDirect], + ['showTaskDirect', showTaskDirect], + ['nextTaskDirect', nextTaskDirect], + ['expandTaskDirect', expandTaskDirect], + ['addTaskDirect', addTaskDirect] +]); + +// Re-export all direct function implementations export { listTasksDirect, getCacheStatsDirect, @@ -33,23 +50,5 @@ export { showTaskDirect, nextTaskDirect, expandTaskDirect, -}; - -/** - * Maps Task Master functions to their direct implementation - * This map is used by tools to look up the appropriate function by name - */ -export const directFunctions = { - list: listTasksDirect, - cacheStats: getCacheStatsDirect, - parsePRD: parsePRDDirect, - update: updateTasksDirect, - updateTask: updateTaskByIdDirect, - updateSubtask: updateSubtaskByIdDirect, - generate: generateTaskFilesDirect, - setStatus: setTaskStatusDirect, - showTask: showTaskDirect, - nextTask: nextTaskDirect, - expandTask: expandTaskDirect, - // Add more functions as we implement them + addTaskDirect }; \ No newline at end of file diff --git a/mcp-server/src/tools/add-task.js b/mcp-server/src/tools/add-task.js new file mode 100644 index 00000000..4ea8c9cd --- /dev/null +++ b/mcp-server/src/tools/add-task.js @@ -0,0 +1,47 @@ +/** + * tools/add-task.js + * Tool to add a new task using AI + */ + +import { z } from "zod"; +import { + handleApiResult, + createErrorResponse +} from "./utils.js"; +import { addTaskDirect } from "../core/task-master-core.js"; + +/** + * Register the add-task tool with the MCP server + * @param {Object} server - FastMCP server instance + */ +export function registerAddTaskTool(server) { + server.addTool({ + name: "add_task", + description: "Add a new task using AI", + parameters: z.object({ + prompt: z.string().describe("Description of the task to add"), + dependencies: z.string().optional().describe("Comma-separated list of task IDs this task depends on"), + priority: z.string().optional().describe("Task priority (high, medium, low)"), + file: z.string().optional().describe("Path to the tasks file"), + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") + }), + execute: async ({ prompt, dependencies, priority, file, projectRoot }, log) => { + try { + log.info(`MCP add_task called with prompt: "${prompt}"`); + + const result = await addTaskDirect({ + prompt, + dependencies, + priority, + file, + projectRoot + }, log); + + return handleApiResult(result); + } catch (error) { + log.error(`Error in add_task MCP tool: ${error.message}`); + return createErrorResponse(error.message, "ADD_TASK_ERROR"); + } + } + }); +} \ No newline at end of file diff --git a/mcp-server/src/tools/index.js b/mcp-server/src/tools/index.js index de7c0cb2..7f777c0b 100644 --- a/mcp-server/src/tools/index.js +++ b/mcp-server/src/tools/index.js @@ -14,6 +14,7 @@ import { registerGenerateTool } from "./generate.js"; import { registerShowTaskTool } from "./show-task.js"; import { registerNextTaskTool } from "./next-task.js"; import { registerExpandTaskTool } from "./expand-task.js"; +import { registerAddTaskTool } from "./add-task.js"; /** * Register all Task Master tools with the MCP server @@ -30,6 +31,9 @@ export function registerTaskMasterTools(server) { registerShowTaskTool(server); registerNextTaskTool(server); registerExpandTaskTool(server); + registerAddTaskTool(server); + + logger.info("Registered all Task Master tools with MCP server"); } export default { diff --git a/tasks/task_023.txt b/tasks/task_023.txt index 9d9309af..5a094fbe 100644 --- a/tasks/task_023.txt +++ b/tasks/task_023.txt @@ -604,7 +604,7 @@ Following MCP implementation standards: - Unit test for expandTaskDirect.js - Integration test for MCP tool -## 25. Implement add-task MCP command [in-progress] +## 25. Implement add-task MCP command [done] ### Dependencies: None ### Description: Create direct function wrapper and MCP tool for adding new tasks. ### Details: diff --git a/tasks/tasks.json b/tasks/tasks.json index 47fb7aa4..b8c4b5b8 100644 --- a/tasks/tasks.json +++ b/tasks/tasks.json @@ -1573,7 +1573,7 @@ "title": "Implement add-task MCP command", "description": "Create direct function wrapper and MCP tool for adding new tasks.", "details": "Following MCP implementation standards:\n\n1. Create addTaskDirect.js in mcp-server/src/core/direct-functions/:\n - Import addTask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: prompt, priority, dependencies\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n\n2. Export from task-master-core.js:\n - Import the function from its file\n - Add to directFunctions map\n\n3. Create add-task.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import addTaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerAddTaskTool(server) with server.addTool\n - Use executeMCPToolAction in execute method\n\n4. Register in tools/index.js with tool name 'add_task'\n\n5. Add to .cursor/mcp.json with appropriate schema\n\n6. Write tests following testing guidelines:\n - Unit test for addTaskDirect.js\n - Integration test for MCP tool", - "status": "in-progress", + "status": "done", "dependencies": [], "parentTaskId": 23 },