refactor(mcp): Remove unused executeMCPToolAction utility
The function aimed to abstract the common flow within MCP tool methods (logging, calling direct function, handling result). However, the established pattern (e.g., in ) involves the method directly calling the function (which handles its own caching via ) and then passing the result to . This pattern is clear, functional, and leverages the core utilities effectively. Removing the unused simplifies , eliminates a redundant abstraction layer, and clarifies the standard implementation pattern for MCP tools.
This commit is contained in:
@@ -18,6 +18,7 @@ const __dirname = dirname(__filename);
|
|||||||
// Import Task Master modules
|
// Import Task Master modules
|
||||||
import {
|
import {
|
||||||
listTasks,
|
listTasks,
|
||||||
|
parsePRD,
|
||||||
// We'll import more functions as we continue implementation
|
// We'll import more functions as we continue implementation
|
||||||
} from '../../../scripts/modules/task-manager.js';
|
} from '../../../scripts/modules/task-manager.js';
|
||||||
|
|
||||||
@@ -157,11 +158,72 @@ export async function getCacheStatsDirect(args, log) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct function wrapper for parsePRD with error handling.
|
||||||
|
*
|
||||||
|
* @param {Object} args - Command arguments (input file path, output path, numTasks).
|
||||||
|
* @param {Object} log - Logger object.
|
||||||
|
* @returns {Promise<Object>} - Result object { success: boolean, data?: any, error?: { code: string, message: string }, fromCache: boolean }.
|
||||||
|
*/
|
||||||
|
export async function parsePRDDirect(args, log) {
|
||||||
|
try {
|
||||||
|
// Normalize paths based on projectRoot
|
||||||
|
const projectRoot = args.projectRoot || process.cwd();
|
||||||
|
|
||||||
|
// Get the input file path (PRD file)
|
||||||
|
const inputPath = args.input
|
||||||
|
? path.resolve(projectRoot, args.input)
|
||||||
|
: path.resolve(projectRoot, 'sample-prd.txt');
|
||||||
|
|
||||||
|
log.info(`Using PRD file: ${inputPath}`);
|
||||||
|
|
||||||
|
// Determine tasks output path
|
||||||
|
let tasksPath;
|
||||||
|
try {
|
||||||
|
// Try to find existing tasks.json first
|
||||||
|
tasksPath = findTasksJsonPath(args, log);
|
||||||
|
} catch (error) {
|
||||||
|
// If not found, use default path
|
||||||
|
tasksPath = path.resolve(projectRoot, 'tasks', 'tasks.json');
|
||||||
|
log.info(`No existing tasks.json found, will create at: ${tasksPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get number of tasks to generate
|
||||||
|
const numTasks = args.numTasks ? parseInt(args.numTasks, 10) : undefined;
|
||||||
|
|
||||||
|
log.info(`Parsing PRD file ${inputPath} to generate tasks in ${tasksPath}`);
|
||||||
|
|
||||||
|
// Call the core parsePRD function
|
||||||
|
await parsePRD(inputPath, tasksPath, numTasks);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
message: `Successfully parsed PRD and generated tasks in ${tasksPath}`,
|
||||||
|
inputFile: inputPath,
|
||||||
|
outputFile: tasksPath
|
||||||
|
},
|
||||||
|
fromCache: false // PRD parsing is never cached
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
log.error(`Error parsing PRD: ${error.message}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: {
|
||||||
|
code: 'PARSE_PRD_ERROR',
|
||||||
|
message: error.message
|
||||||
|
},
|
||||||
|
fromCache: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps Task Master functions to their direct implementation
|
* Maps Task Master functions to their direct implementation
|
||||||
*/
|
*/
|
||||||
export const directFunctions = {
|
export const directFunctions = {
|
||||||
list: listTasksDirect,
|
list: listTasksDirect,
|
||||||
cacheStats: getCacheStatsDirect,
|
cacheStats: getCacheStatsDirect,
|
||||||
|
parsePRD: parsePRDDirect,
|
||||||
// Add more functions as we implement them
|
// Add more functions as we implement them
|
||||||
};
|
};
|
||||||
@@ -10,6 +10,7 @@ import { registerSetTaskStatusTool } from "./setTaskStatus.js";
|
|||||||
import { registerExpandTaskTool } from "./expandTask.js";
|
import { registerExpandTaskTool } from "./expandTask.js";
|
||||||
import { registerNextTaskTool } from "./nextTask.js";
|
import { registerNextTaskTool } from "./nextTask.js";
|
||||||
import { registerAddTaskTool } from "./addTask.js";
|
import { registerAddTaskTool } from "./addTask.js";
|
||||||
|
import { registerParsePRDTool } from "./parsePRD.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register all Task Master tools with the MCP server
|
* Register all Task Master tools with the MCP server
|
||||||
@@ -22,6 +23,7 @@ export function registerTaskMasterTools(server) {
|
|||||||
registerExpandTaskTool(server);
|
registerExpandTaskTool(server);
|
||||||
registerNextTaskTool(server);
|
registerNextTaskTool(server);
|
||||||
registerAddTaskTool(server);
|
registerAddTaskTool(server);
|
||||||
|
registerParsePRDTool(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
41
mcp-server/src/tools/parsePRD.js
Normal file
41
mcp-server/src/tools/parsePRD.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* tools/parsePRD.js
|
||||||
|
* Tool to parse PRD documents and generate Task Master tasks
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
import { executeMCPToolAction } from "./utils.js";
|
||||||
|
import { parsePRDDirect } from "../core/task-master-core.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the parsePRD tool with the MCP server
|
||||||
|
* @param {Object} server - FastMCP server instance
|
||||||
|
*/
|
||||||
|
export function registerParsePRDTool(server) {
|
||||||
|
server.addTool({
|
||||||
|
name: "parsePRD",
|
||||||
|
description: "Parse a PRD document and generate Task Master tasks",
|
||||||
|
parameters: z.object({
|
||||||
|
input: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Path to the PRD text file (default: sample-prd.txt)"),
|
||||||
|
numTasks: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Number of tasks to generate"),
|
||||||
|
projectRoot: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Root directory of the project (default: current working directory)")
|
||||||
|
}),
|
||||||
|
execute: async (args, { log }) => {
|
||||||
|
return executeMCPToolAction({
|
||||||
|
actionFn: parsePRDDirect,
|
||||||
|
args,
|
||||||
|
log,
|
||||||
|
actionName: "Parse PRD and generate tasks"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -180,95 +180,6 @@ export async function getCachedOrExecute({ cacheKey, actionFn, log }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a Task Master tool action with standardized error handling, logging, and response formatting.
|
|
||||||
* Integrates caching logic via getCachedOrExecute if a cacheKeyGenerator is provided.
|
|
||||||
*
|
|
||||||
* @param {Object} options - Options for executing the tool action
|
|
||||||
* @param {Function} options.actionFn - The core action function (e.g., listTasksDirect) to execute. Should return {success, data, error}.
|
|
||||||
* @param {Object} options.args - Arguments for the action, passed to actionFn and cacheKeyGenerator.
|
|
||||||
* @param {Object} options.log - Logger object from FastMCP.
|
|
||||||
* @param {string} options.actionName - Name of the action for logging purposes.
|
|
||||||
* @param {Function} [options.cacheKeyGenerator] - Optional function to generate a cache key based on args. If provided, caching is enabled.
|
|
||||||
* @param {Function} [options.processResult=processMCPResponseData] - Optional function to process the result data before returning.
|
|
||||||
* @returns {Promise<Object>} - Standardized response for FastMCP.
|
|
||||||
*/
|
|
||||||
export async function executeMCPToolAction({
|
|
||||||
actionFn,
|
|
||||||
args,
|
|
||||||
log,
|
|
||||||
actionName,
|
|
||||||
cacheKeyGenerator, // Note: We decided not to use this for listTasks for now
|
|
||||||
processResult = processMCPResponseData
|
|
||||||
}) {
|
|
||||||
try {
|
|
||||||
// Log the action start
|
|
||||||
log.info(`${actionName} with args: ${JSON.stringify(args)}`);
|
|
||||||
|
|
||||||
// Normalize project root path - common to almost all tools
|
|
||||||
const projectRootRaw = args.projectRoot || process.cwd();
|
|
||||||
const projectRoot = path.isAbsolute(projectRootRaw)
|
|
||||||
? projectRootRaw
|
|
||||||
: path.resolve(process.cwd(), projectRootRaw);
|
|
||||||
|
|
||||||
log.info(`Using project root: ${projectRoot}`);
|
|
||||||
const executionArgs = { ...args, projectRoot };
|
|
||||||
|
|
||||||
let result;
|
|
||||||
const cacheKey = cacheKeyGenerator ? cacheKeyGenerator(executionArgs) : null;
|
|
||||||
|
|
||||||
if (cacheKey) {
|
|
||||||
// Use caching utility
|
|
||||||
log.info(`Caching enabled for ${actionName} with key: ${cacheKey}`);
|
|
||||||
const cacheWrappedAction = async () => await actionFn(executionArgs, log);
|
|
||||||
result = await getCachedOrExecute({
|
|
||||||
cacheKey,
|
|
||||||
actionFn: cacheWrappedAction,
|
|
||||||
log
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Execute directly without caching
|
|
||||||
log.info(`Caching disabled for ${actionName}. Executing directly.`);
|
|
||||||
// We need to ensure the result from actionFn has a fromCache field
|
|
||||||
// Let's assume actionFn now consistently returns { success, data/error, fromCache }
|
|
||||||
// The current listTasksDirect does this if it calls getCachedOrExecute internally.
|
|
||||||
result = await actionFn(executionArgs, log);
|
|
||||||
// If the action function itself doesn't determine caching (like our original listTasksDirect refactor attempt),
|
|
||||||
// we'd set it here:
|
|
||||||
// result.fromCache = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle error case
|
|
||||||
if (!result.success) {
|
|
||||||
const errorMsg = result.error?.message || `Unknown error during ${actionName.toLowerCase()}`;
|
|
||||||
// Include fromCache in error logs too, might be useful
|
|
||||||
log.error(`Error during ${actionName.toLowerCase()}: ${errorMsg}. From cache: ${result.fromCache}`);
|
|
||||||
return createErrorResponse(errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log success
|
|
||||||
log.info(`Successfully completed ${actionName.toLowerCase()}. From cache: ${result.fromCache}`);
|
|
||||||
|
|
||||||
// Process the result data if needed
|
|
||||||
const processedData = processResult ? processResult(result.data) : result.data;
|
|
||||||
|
|
||||||
// Create a new object that includes both the processed data and the fromCache flag
|
|
||||||
const responsePayload = {
|
|
||||||
fromCache: result.fromCache, // Include the flag here
|
|
||||||
data: processedData // Embed the actual data under a 'data' key
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pass this combined payload to createContentResponse
|
|
||||||
return createContentResponse(responsePayload);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
// Handle unexpected errors during the execution wrapper itself
|
|
||||||
log.error(`Unexpected error during ${actionName.toLowerCase()} execution wrapper: ${error.message}`);
|
|
||||||
console.error(error.stack); // Log stack for debugging wrapper errors
|
|
||||||
return createErrorResponse(`Internal server error during ${actionName.toLowerCase()}: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively removes specified fields from task objects, whether single or in an array.
|
* Recursively removes specified fields from task objects, whether single or in an array.
|
||||||
* Handles common data structures returned by task commands.
|
* Handles common data structures returned by task commands.
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
|
|||||||
### Details:
|
### Details:
|
||||||
1. Research and implement SSE protocol for the MCP server\n2. Create dedicated SSE endpoints for event streaming\n3. Implement event emitter pattern for internal event management\n4. Add support for different event types (task status, logs, errors)\n5. Implement client connection management with proper keep-alive handling\n6. Add filtering capabilities to allow subscribing to specific event types\n7. Create in-memory event buffer for clients reconnecting\n8. Document SSE endpoint usage and client implementation examples\n9. Add robust error handling for dropped connections\n10. Implement rate limiting and backpressure mechanisms\n11. Add authentication for SSE connections
|
1. Research and implement SSE protocol for the MCP server\n2. Create dedicated SSE endpoints for event streaming\n3. Implement event emitter pattern for internal event management\n4. Add support for different event types (task status, logs, errors)\n5. Implement client connection management with proper keep-alive handling\n6. Add filtering capabilities to allow subscribing to specific event types\n7. Create in-memory event buffer for clients reconnecting\n8. Document SSE endpoint usage and client implementation examples\n9. Add robust error handling for dropped connections\n10. Implement rate limiting and backpressure mechanisms\n11. Add authentication for SSE connections
|
||||||
|
|
||||||
## 16. Implement parse-prd MCP command [pending]
|
## 16. Implement parse-prd MCP command [in-progress]
|
||||||
### Dependencies: None
|
### Dependencies: None
|
||||||
### Description: Create direct function wrapper and MCP tool for parsing PRD documents to generate tasks.
|
### Description: Create direct function wrapper and MCP tool for parsing PRD documents to generate tasks.
|
||||||
### Details:
|
### Details:
|
||||||
|
|||||||
@@ -1492,7 +1492,7 @@
|
|||||||
"title": "Implement parse-prd MCP command",
|
"title": "Implement parse-prd MCP command",
|
||||||
"description": "Create direct function wrapper and MCP tool for parsing PRD documents to generate tasks.",
|
"description": "Create direct function wrapper and MCP tool for parsing PRD documents to generate tasks.",
|
||||||
"details": "Following MCP implementation standards:\\n\\n1. Create parsePRDDirect function in task-master-core.js:\\n - Import parsePRD from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: input file, output path, numTasks\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create parse-prd.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import parsePRDDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerParsePRDTool(server) with server.addTool\\n - Use executeMCPToolAction in execute method\\n\\n3. Register in tools/index.js\\n\\n4. Add to .cursor/mcp.json with appropriate schema\\n\\n5. Write tests following testing guidelines:\\n - Unit test for parsePRDDirect\\n - Integration test for MCP tool",
|
"details": "Following MCP implementation standards:\\n\\n1. Create parsePRDDirect function in task-master-core.js:\\n - Import parsePRD from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: input file, output path, numTasks\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create parse-prd.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import parsePRDDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerParsePRDTool(server) with server.addTool\\n - Use executeMCPToolAction in execute method\\n\\n3. Register in tools/index.js\\n\\n4. Add to .cursor/mcp.json with appropriate schema\\n\\n5. Write tests following testing guidelines:\\n - Unit test for parsePRDDirect\\n - Integration test for MCP tool",
|
||||||
"status": "pending",
|
"status": "in-progress",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"parentTaskId": 23
|
"parentTaskId": 23
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user