feat(mcp): Implement update-subtask MCP command for appending information to subtasks
This commit is contained in:
@@ -2,4 +2,6 @@
|
|||||||
"task-master-ai": patch
|
"task-master-ai": patch
|
||||||
---
|
---
|
||||||
|
|
||||||
Split monolithic task-master-core.js into separate function files within direct-functions directory and implement update-task MCP command for updating a single task by ID
|
- Split monolithic task-master-core.js into separate function files within direct-functions directory
|
||||||
|
- Implement update-task MCP command for updating a single task by ID
|
||||||
|
- Implement update-subtask MCP command for appending information to specific subtasks
|
||||||
|
|||||||
@@ -342,4 +342,4 @@ alwaysApply: true
|
|||||||
- Start by mapping all functions in the source file
|
- Start by mapping all functions in the source file
|
||||||
- Create target module files based on function grouping
|
- Create target module files based on function grouping
|
||||||
- Verify all functions were properly migrated
|
- Verify all functions were properly migrated
|
||||||
- Check for any unintentional duplications or omissions
|
- Check for any unintentional duplications or omissions
|
||||||
107
mcp-server/src/core/direct-functions/update-subtask-by-id.js
Normal file
107
mcp-server/src/core/direct-functions/update-subtask-by-id.js
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* update-subtask-by-id.js
|
||||||
|
* Direct function implementation for appending information to a specific subtask
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { updateSubtaskById } from '../../../../scripts/modules/task-manager.js';
|
||||||
|
import { findTasksJsonPath } from '../utils/path-utils.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct function wrapper for updateSubtaskById with error handling.
|
||||||
|
*
|
||||||
|
* @param {Object} args - Command arguments containing id, prompt, useResearch and file path options.
|
||||||
|
* @param {Object} log - Logger object.
|
||||||
|
* @returns {Promise<Object>} - Result object with success status and data/error information.
|
||||||
|
*/
|
||||||
|
export async function updateSubtaskByIdDirect(args, log) {
|
||||||
|
try {
|
||||||
|
log.info(`Updating subtask with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
|
// Check required parameters
|
||||||
|
if (!args.id) {
|
||||||
|
const errorMessage = 'No subtask ID specified. Please provide a subtask ID to update.';
|
||||||
|
log.error(errorMessage);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: { code: 'MISSING_SUBTASK_ID', message: errorMessage },
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.prompt) {
|
||||||
|
const errorMessage = 'No prompt specified. Please provide a prompt with information to add to the subtask.';
|
||||||
|
log.error(errorMessage);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: { code: 'MISSING_PROMPT', message: errorMessage },
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate subtask ID format
|
||||||
|
const subtaskId = args.id;
|
||||||
|
if (typeof subtaskId !== 'string' || !subtaskId.includes('.')) {
|
||||||
|
const errorMessage = `Invalid subtask ID format: ${subtaskId}. Subtask ID must be in format "parentId.subtaskId" (e.g., "5.2").`;
|
||||||
|
log.error(errorMessage);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: { code: 'INVALID_SUBTASK_ID_FORMAT', message: errorMessage },
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tasks file path
|
||||||
|
let tasksPath;
|
||||||
|
try {
|
||||||
|
tasksPath = findTasksJsonPath(args, log);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(`Error finding tasks file: ${error.message}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: { code: 'TASKS_FILE_ERROR', message: error.message },
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get research flag
|
||||||
|
const useResearch = args.research === true;
|
||||||
|
|
||||||
|
log.info(`Updating subtask with ID ${subtaskId} with prompt "${args.prompt}" and research: ${useResearch}`);
|
||||||
|
|
||||||
|
// Execute core updateSubtaskById function
|
||||||
|
const updatedSubtask = await updateSubtaskById(tasksPath, subtaskId, args.prompt, useResearch);
|
||||||
|
|
||||||
|
// Handle the case where the subtask couldn't be updated (e.g., already marked as done)
|
||||||
|
if (!updatedSubtask) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: {
|
||||||
|
code: 'SUBTASK_UPDATE_FAILED',
|
||||||
|
message: 'Failed to update subtask. It may be marked as completed, or another error occurred.'
|
||||||
|
},
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the updated subtask information
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
message: `Successfully updated subtask with ID ${subtaskId}`,
|
||||||
|
subtaskId,
|
||||||
|
parentId: subtaskId.split('.')[0],
|
||||||
|
subtask: updatedSubtask,
|
||||||
|
tasksPath,
|
||||||
|
useResearch
|
||||||
|
},
|
||||||
|
fromCache: false // This operation always modifies state and should never be cached
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
log.error(`Error updating subtask by ID: ${error.message}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: { code: 'UPDATE_SUBTASK_ERROR', message: error.message || 'Unknown error updating subtask' },
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import { getCacheStatsDirect } from './direct-functions/cache-stats.js';
|
|||||||
import { parsePRDDirect } from './direct-functions/parse-prd.js';
|
import { parsePRDDirect } from './direct-functions/parse-prd.js';
|
||||||
import { updateTasksDirect } from './direct-functions/update-tasks.js';
|
import { updateTasksDirect } from './direct-functions/update-tasks.js';
|
||||||
import { updateTaskByIdDirect } from './direct-functions/update-task-by-id.js';
|
import { updateTaskByIdDirect } from './direct-functions/update-task-by-id.js';
|
||||||
|
import { updateSubtaskByIdDirect } from './direct-functions/update-subtask-by-id.js';
|
||||||
|
|
||||||
// Re-export utility functions
|
// Re-export utility functions
|
||||||
export { findTasksJsonPath } from './utils/path-utils.js';
|
export { findTasksJsonPath } from './utils/path-utils.js';
|
||||||
@@ -21,6 +22,7 @@ export {
|
|||||||
parsePRDDirect,
|
parsePRDDirect,
|
||||||
updateTasksDirect,
|
updateTasksDirect,
|
||||||
updateTaskByIdDirect,
|
updateTaskByIdDirect,
|
||||||
|
updateSubtaskByIdDirect,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,5 +35,6 @@ export const directFunctions = {
|
|||||||
parsePRD: parsePRDDirect,
|
parsePRD: parsePRDDirect,
|
||||||
update: updateTasksDirect,
|
update: updateTasksDirect,
|
||||||
updateTask: updateTaskByIdDirect,
|
updateTask: updateTaskByIdDirect,
|
||||||
|
updateSubtask: updateSubtaskByIdDirect,
|
||||||
// Add more functions as we implement them
|
// Add more functions as we implement them
|
||||||
};
|
};
|
||||||
@@ -13,6 +13,7 @@ import { registerAddTaskTool } from "./addTask.js";
|
|||||||
import { registerParsePRDTool } from "./parsePRD.js";
|
import { registerParsePRDTool } from "./parsePRD.js";
|
||||||
import { registerUpdateTool } from "./update.js";
|
import { registerUpdateTool } from "./update.js";
|
||||||
import { registerUpdateTaskTool } from "./update-task.js";
|
import { registerUpdateTaskTool } from "./update-task.js";
|
||||||
|
import { registerUpdateSubtaskTool } from "./update-subtask.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register all Task Master tools with the MCP server
|
* Register all Task Master tools with the MCP server
|
||||||
@@ -28,6 +29,7 @@ export function registerTaskMasterTools(server) {
|
|||||||
registerParsePRDTool(server);
|
registerParsePRDTool(server);
|
||||||
registerUpdateTool(server);
|
registerUpdateTool(server);
|
||||||
registerUpdateTaskTool(server);
|
registerUpdateTaskTool(server);
|
||||||
|
registerUpdateSubtaskTool(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
51
mcp-server/src/tools/update-subtask.js
Normal file
51
mcp-server/src/tools/update-subtask.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* tools/update-subtask.js
|
||||||
|
* Tool to append additional information to a specific subtask
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
import {
|
||||||
|
handleApiResult,
|
||||||
|
createErrorResponse
|
||||||
|
} from "./utils.js";
|
||||||
|
import { updateSubtaskByIdDirect } from "../core/task-master-core.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the update-subtask tool with the MCP server
|
||||||
|
* @param {Object} server - FastMCP server instance
|
||||||
|
*/
|
||||||
|
export function registerUpdateSubtaskTool(server) {
|
||||||
|
server.addTool({
|
||||||
|
name: "update-subtask",
|
||||||
|
description: "Appends additional information to a specific subtask without replacing existing content",
|
||||||
|
parameters: z.object({
|
||||||
|
id: z.string().describe("ID of the subtask to update in format \"parentId.subtaskId\" (e.g., \"5.2\")"),
|
||||||
|
prompt: z.string().describe("Information to add to the subtask"),
|
||||||
|
research: z.boolean().optional().describe("Use Perplexity AI for research-backed updates"),
|
||||||
|
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 (args, { log }) => {
|
||||||
|
try {
|
||||||
|
log.info(`Updating subtask with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
|
// Call the direct function wrapper
|
||||||
|
const result = await updateSubtaskByIdDirect(args, log);
|
||||||
|
|
||||||
|
// Log result
|
||||||
|
log.info(`${result.success ? `Successfully updated subtask with ID ${args.id}` : 'Failed to update subtask'}`);
|
||||||
|
|
||||||
|
// Use handleApiResult to format the response
|
||||||
|
return handleApiResult(result, log, 'Error updating subtask');
|
||||||
|
} catch (error) {
|
||||||
|
log.error(`Error in update-subtask tool: ${error.message}`);
|
||||||
|
return createErrorResponse(error.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -405,7 +405,7 @@ Following MCP implementation standards:
|
|||||||
- Unit test for updateTaskByIdDirect.js
|
- Unit test for updateTaskByIdDirect.js
|
||||||
- Integration test for MCP tool
|
- Integration test for MCP tool
|
||||||
|
|
||||||
## 19. Implement update-subtask MCP command [pending]
|
## 19. Implement update-subtask MCP command [done]
|
||||||
### Dependencies: None
|
### Dependencies: None
|
||||||
### Description: Create direct function wrapper and MCP tool for appending information to a specific subtask.
|
### Description: Create direct function wrapper and MCP tool for appending information to a specific subtask.
|
||||||
### Details:
|
### Details:
|
||||||
|
|||||||
@@ -1519,7 +1519,7 @@
|
|||||||
"title": "Implement update-subtask MCP command",
|
"title": "Implement update-subtask MCP command",
|
||||||
"description": "Create direct function wrapper and MCP tool for appending information to a specific subtask.",
|
"description": "Create direct function wrapper and MCP tool for appending information to a specific subtask.",
|
||||||
"details": "Following MCP implementation standards:\n\n1. Create updateSubtaskByIdDirect.js in mcp-server/src/core/direct-functions/:\n - Import updateSubtaskById from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: subtaskId, prompt, useResearch\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 update-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 updateSubtaskByIdDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerUpdateSubtaskTool(server) with server.addTool\n - Use executeMCPToolAction in execute method\n\n4. Register in tools/index.js\n\n5. Add to .cursor/mcp.json with appropriate schema\n\n6. Write tests following testing guidelines:\n - Unit test for updateSubtaskByIdDirect.js\n - Integration test for MCP tool",
|
"details": "Following MCP implementation standards:\n\n1. Create updateSubtaskByIdDirect.js in mcp-server/src/core/direct-functions/:\n - Import updateSubtaskById from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: subtaskId, prompt, useResearch\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 update-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 updateSubtaskByIdDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerUpdateSubtaskTool(server) with server.addTool\n - Use executeMCPToolAction in execute method\n\n4. Register in tools/index.js\n\n5. Add to .cursor/mcp.json with appropriate schema\n\n6. Write tests following testing guidelines:\n - Unit test for updateSubtaskByIdDirect.js\n - Integration test for MCP tool",
|
||||||
"status": "pending",
|
"status": "done",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"parentTaskId": 23
|
"parentTaskId": 23
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user