Implement add-subtask MCP command for adding subtasks to existing tasks
This commit is contained in:
@@ -11,4 +11,5 @@
|
||||
- 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
|
||||
- Implement add-subtask MCP command for adding subtasks to existing tasks
|
||||
- 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)
|
||||
|
||||
113
mcp-server/src/core/direct-functions/add-subtask.js
Normal file
113
mcp-server/src/core/direct-functions/add-subtask.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Direct function wrapper for addSubtask
|
||||
*/
|
||||
|
||||
import { addSubtask } from '../../../../scripts/modules/task-manager.js';
|
||||
import { findTasksJsonPath } from '../utils/path-utils.js';
|
||||
|
||||
/**
|
||||
* Add a subtask to an existing task
|
||||
* @param {Object} args - Function arguments
|
||||
* @param {string} args.id - Parent task ID
|
||||
* @param {string} [args.taskId] - Existing task ID to convert to subtask (optional)
|
||||
* @param {string} [args.title] - Title for new subtask (when creating a new subtask)
|
||||
* @param {string} [args.description] - Description for new subtask
|
||||
* @param {string} [args.details] - Implementation details for new subtask
|
||||
* @param {string} [args.status] - Status for new subtask (default: 'pending')
|
||||
* @param {string} [args.dependencies] - Comma-separated list of dependency IDs
|
||||
* @param {string} [args.file] - Path to the tasks file
|
||||
* @param {boolean} [args.skipGenerate] - Skip regenerating task files
|
||||
* @param {string} [args.projectRoot] - Project root directory
|
||||
* @param {Object} log - Logger object
|
||||
* @returns {Promise<{success: boolean, data?: Object, error?: string}>}
|
||||
*/
|
||||
export async function addSubtaskDirect(args, log) {
|
||||
try {
|
||||
log.info(`Adding subtask with args: ${JSON.stringify(args)}`);
|
||||
|
||||
if (!args.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INPUT_VALIDATION_ERROR',
|
||||
message: 'Parent task ID is required'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Either taskId or title must be provided
|
||||
if (!args.taskId && !args.title) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INPUT_VALIDATION_ERROR',
|
||||
message: 'Either taskId or title must be provided'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Find the tasks.json path
|
||||
const tasksPath = findTasksJsonPath(args.file, args.projectRoot);
|
||||
|
||||
// Parse dependencies if provided
|
||||
let dependencies = [];
|
||||
if (args.dependencies) {
|
||||
dependencies = args.dependencies.split(',').map(id => {
|
||||
// Handle both regular IDs and dot notation
|
||||
return id.includes('.') ? id.trim() : parseInt(id.trim(), 10);
|
||||
});
|
||||
}
|
||||
|
||||
// Convert existingTaskId to a number if provided
|
||||
const existingTaskId = args.taskId ? parseInt(args.taskId, 10) : null;
|
||||
|
||||
// Convert parent ID to a number
|
||||
const parentId = parseInt(args.id, 10);
|
||||
|
||||
// Determine if we should generate files
|
||||
const generateFiles = !args.skipGenerate;
|
||||
|
||||
// Case 1: Convert existing task to subtask
|
||||
if (existingTaskId) {
|
||||
log.info(`Converting task ${existingTaskId} to a subtask of ${parentId}`);
|
||||
const result = await addSubtask(tasksPath, parentId, existingTaskId, null, generateFiles);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
message: `Task ${existingTaskId} successfully converted to a subtask of task ${parentId}`,
|
||||
subtask: result
|
||||
}
|
||||
};
|
||||
}
|
||||
// Case 2: Create new subtask
|
||||
else {
|
||||
log.info(`Creating new subtask for parent task ${parentId}`);
|
||||
|
||||
const newSubtaskData = {
|
||||
title: args.title,
|
||||
description: args.description || '',
|
||||
details: args.details || '',
|
||||
status: args.status || 'pending',
|
||||
dependencies: dependencies
|
||||
};
|
||||
|
||||
const result = await addSubtask(tasksPath, parentId, null, newSubtaskData, generateFiles);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
message: `New subtask ${parentId}.${result.id} successfully created`,
|
||||
subtask: result
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Error in addSubtaskDirect: ${error.message}`);
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'CORE_FUNCTION_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ 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';
|
||||
import { addSubtaskDirect } from './direct-functions/add-subtask.js';
|
||||
|
||||
// Re-export utility functions
|
||||
export { findTasksJsonPath } from './utils/path-utils.js';
|
||||
@@ -34,7 +35,8 @@ export const directFunctions = new Map([
|
||||
['showTaskDirect', showTaskDirect],
|
||||
['nextTaskDirect', nextTaskDirect],
|
||||
['expandTaskDirect', expandTaskDirect],
|
||||
['addTaskDirect', addTaskDirect]
|
||||
['addTaskDirect', addTaskDirect],
|
||||
['addSubtaskDirect', addSubtaskDirect]
|
||||
]);
|
||||
|
||||
// Re-export all direct function implementations
|
||||
@@ -50,5 +52,6 @@ export {
|
||||
showTaskDirect,
|
||||
nextTaskDirect,
|
||||
expandTaskDirect,
|
||||
addTaskDirect
|
||||
addTaskDirect,
|
||||
addSubtaskDirect
|
||||
};
|
||||
55
mcp-server/src/tools/add-subtask.js
Normal file
55
mcp-server/src/tools/add-subtask.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* tools/add-subtask.js
|
||||
* Tool for adding subtasks to existing tasks
|
||||
*/
|
||||
|
||||
import { z } from "zod";
|
||||
import {
|
||||
handleApiResult,
|
||||
createErrorResponse
|
||||
} from "./utils.js";
|
||||
import { addSubtaskDirect } from "../core/task-master-core.js";
|
||||
|
||||
/**
|
||||
* Register the addSubtask tool with the MCP server
|
||||
* @param {Object} server - FastMCP server instance
|
||||
*/
|
||||
export function registerAddSubtaskTool(server) {
|
||||
server.addTool({
|
||||
name: "add_subtask",
|
||||
description: "Add a subtask to an existing task",
|
||||
parameters: z.object({
|
||||
id: z.string().describe("Parent task ID (required)"),
|
||||
taskId: z.string().optional().describe("Existing task ID to convert to subtask"),
|
||||
title: z.string().optional().describe("Title for the new subtask (when creating a new subtask)"),
|
||||
description: z.string().optional().describe("Description for the new subtask"),
|
||||
details: z.string().optional().describe("Implementation details for the new subtask"),
|
||||
status: z.string().optional().describe("Status for the new subtask (default: 'pending')"),
|
||||
dependencies: z.string().optional().describe("Comma-separated list of dependency IDs for the new subtask"),
|
||||
file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"),
|
||||
skipGenerate: z.boolean().optional().describe("Skip regenerating task files"),
|
||||
projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)")
|
||||
}),
|
||||
execute: async (args, { log }) => {
|
||||
try {
|
||||
log.info(`Adding subtask with args: ${JSON.stringify(args)}`);
|
||||
|
||||
// Call the direct function wrapper
|
||||
const result = await addSubtaskDirect(args, log);
|
||||
|
||||
// Log result
|
||||
if (result.success) {
|
||||
log.info(`Subtask added successfully: ${result.data.message}`);
|
||||
} else {
|
||||
log.error(`Failed to add subtask: ${result.error.message}`);
|
||||
}
|
||||
|
||||
// Use handleApiResult to format the response
|
||||
return handleApiResult(result, log, 'Error adding subtask');
|
||||
} catch (error) {
|
||||
log.error(`Error in addSubtask tool: ${error.message}`);
|
||||
return createErrorResponse(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { registerShowTaskTool } from "./show-task.js";
|
||||
import { registerNextTaskTool } from "./next-task.js";
|
||||
import { registerExpandTaskTool } from "./expand-task.js";
|
||||
import { registerAddTaskTool } from "./add-task.js";
|
||||
import { registerAddSubtaskTool } from "./add-subtask.js";
|
||||
|
||||
/**
|
||||
* Register all Task Master tools with the MCP server
|
||||
@@ -32,6 +33,7 @@ export function registerTaskMasterTools(server) {
|
||||
registerNextTaskTool(server);
|
||||
registerExpandTaskTool(server);
|
||||
registerAddTaskTool(server);
|
||||
registerAddSubtaskTool(server);
|
||||
|
||||
logger.info("Registered all Task Master tools with MCP server");
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ Following MCP implementation standards:
|
||||
- Unit test for addTaskDirect.js
|
||||
- Integration test for MCP tool
|
||||
|
||||
## 26. Implement add-subtask MCP command [pending]
|
||||
## 26. Implement add-subtask MCP command [done]
|
||||
### Dependencies: None
|
||||
### Description: Create direct function wrapper and MCP tool for adding subtasks to existing tasks.
|
||||
### Details:
|
||||
@@ -802,7 +802,7 @@ Following MCP implementation standards:
|
||||
- Unit test for expandAllTasksDirect.js
|
||||
- Integration test for MCP tool
|
||||
|
||||
## 31. Create Core Direct Function Structure [pending]
|
||||
## 31. Create Core Direct Function Structure [done]
|
||||
### Dependencies: None
|
||||
### Description: Set up the modular directory structure for direct functions and update task-master-core.js to act as an import/export hub.
|
||||
### Details:
|
||||
@@ -815,7 +815,7 @@ Following MCP implementation standards:
|
||||
7. Create unit tests for the import/export hub functionality
|
||||
8. Ensure backward compatibility with any existing code using the old structure
|
||||
|
||||
## 32. Refactor Existing Direct Functions to Modular Structure [pending]
|
||||
## 32. Refactor Existing Direct Functions to Modular Structure [done]
|
||||
### Dependencies: 23.31
|
||||
### Description: Move existing direct function implementations from task-master-core.js to individual files in the new directory structure.
|
||||
### Details:
|
||||
@@ -828,7 +828,7 @@ Following MCP implementation standards:
|
||||
7. Ensure all MCP tools reference the functions through task-master-core.js
|
||||
8. Verify backward compatibility with existing code
|
||||
|
||||
## 33. Implement Naming Convention Standards [pending]
|
||||
## 33. Implement Naming Convention Standards [done]
|
||||
### Dependencies: None
|
||||
### Description: Update all MCP server components to follow the standardized naming conventions for files, functions, and tools.
|
||||
### Details:
|
||||
|
||||
@@ -1582,7 +1582,7 @@
|
||||
"title": "Implement add-subtask MCP command",
|
||||
"description": "Create direct function wrapper and MCP tool for adding subtasks to existing tasks.",
|
||||
"details": "Following MCP implementation standards:\n\n1. Create addSubtaskDirect.js in mcp-server/src/core/direct-functions/:\n - Import addSubtask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: parentTaskId, title, description, details\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-subtask.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import addSubtaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerAddSubtaskTool(server) with server.addTool\n - Use executeMCPToolAction in execute method\n\n4. Register in tools/index.js with tool name 'add_subtask'\n\n5. Add to .cursor/mcp.json with appropriate schema\n\n6. Write tests following testing guidelines:\n - Unit test for addSubtaskDirect.js\n - Integration test for MCP tool",
|
||||
"status": "pending",
|
||||
"status": "done",
|
||||
"dependencies": [],
|
||||
"parentTaskId": 23
|
||||
},
|
||||
@@ -1627,7 +1627,7 @@
|
||||
"title": "Create Core Direct Function Structure",
|
||||
"description": "Set up the modular directory structure for direct functions and update task-master-core.js to act as an import/export hub.",
|
||||
"details": "1. Create the mcp-server/src/core/direct-functions/ directory structure\n2. Update task-master-core.js to import and re-export functions from individual files\n3. Create a utils directory for shared utility functions\n4. Implement a standard template for direct function files\n5. Create documentation for the new modular structure\n6. Update existing imports in MCP tools to use the new structure\n7. Create unit tests for the import/export hub functionality\n8. Ensure backward compatibility with any existing code using the old structure",
|
||||
"status": "pending",
|
||||
"status": "done",
|
||||
"dependencies": [],
|
||||
"parentTaskId": 23
|
||||
},
|
||||
@@ -1636,7 +1636,7 @@
|
||||
"title": "Refactor Existing Direct Functions to Modular Structure",
|
||||
"description": "Move existing direct function implementations from task-master-core.js to individual files in the new directory structure.",
|
||||
"details": "1. Identify all existing direct functions in task-master-core.js\n2. Create individual files for each function in mcp-server/src/core/direct-functions/\n3. Move the implementation to the new files, ensuring consistent error handling\n4. Update imports/exports in task-master-core.js\n5. Create unit tests for each individual function file\n6. Update documentation to reflect the new structure\n7. Ensure all MCP tools reference the functions through task-master-core.js\n8. Verify backward compatibility with existing code",
|
||||
"status": "pending",
|
||||
"status": "done",
|
||||
"dependencies": [
|
||||
"23.31"
|
||||
],
|
||||
@@ -1647,7 +1647,7 @@
|
||||
"title": "Implement Naming Convention Standards",
|
||||
"description": "Update all MCP server components to follow the standardized naming conventions for files, functions, and tools.",
|
||||
"details": "1. Audit all existing MCP server files and update file names to use kebab-case (like-this.js)\n2. Refactor direct function names to use camelCase with Direct suffix (functionNameDirect)\n3. Update tool registration functions to use camelCase with Tool suffix (registerToolNameTool)\n4. Ensure all MCP tool names exposed to clients use snake_case (tool_name)\n5. Create a naming convention documentation file for future reference\n6. Update imports/exports in all files to reflect the new naming conventions\n7. Verify that all tools are properly registered with the correct naming pattern\n8. Update tests to reflect the new naming conventions\n9. Create a linting rule to enforce naming conventions in future development",
|
||||
"status": "pending",
|
||||
"status": "done",
|
||||
"dependencies": [],
|
||||
"parentTaskId": 23
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user