feat(cache): Implement caching for listTasks MCP endpoint

Implemented LRU caching for the  function to improve performance for repeated requests.

Key changes include:
- Added  dependency.
- Introduced a reusable  utility function in  leveraging a .
- Refactored  in  to use the caching utility with a key based on task path, filter, and subtask flag.
- Modified  to include the  boolean flag in the final JSON response structure, nesting the original data under a  key.
- Added  function and corresponding MCP tool () for monitoring cache performance.
- Improved error handling in  for cases where  is not found.

This addresses the previous issue of the empty task list likely caused by stale cache entries and provides clear visibility into whether a response is served from the cache.

Relates to #23.9
This commit is contained in:
Eyal Toledano
2025-03-30 02:25:24 -04:00
parent cd4f4e66d7
commit 42585519d3
10 changed files with 712 additions and 80 deletions

View File

@@ -0,0 +1,85 @@
import { jest } from '@jest/globals';
import { ContextManager } from '../context-manager.js';
describe('ContextManager', () => {
let contextManager;
beforeEach(() => {
contextManager = new ContextManager({
maxCacheSize: 10,
ttl: 1000, // 1 second for testing
maxContextSize: 1000
});
});
describe('getContext', () => {
it('should create a new context when not in cache', async () => {
const context = await contextManager.getContext('test-id', { test: true });
expect(context.id).toBe('test-id');
expect(context.metadata.test).toBe(true);
expect(contextManager.stats.misses).toBe(1);
expect(contextManager.stats.hits).toBe(0);
});
it('should return cached context when available', async () => {
// First call creates the context
await contextManager.getContext('test-id', { test: true });
// Second call should hit cache
const context = await contextManager.getContext('test-id', { test: true });
expect(context.id).toBe('test-id');
expect(context.metadata.test).toBe(true);
expect(contextManager.stats.hits).toBe(1);
expect(contextManager.stats.misses).toBe(1);
});
it('should respect TTL settings', async () => {
// Create context
await contextManager.getContext('test-id', { test: true });
// Wait for TTL to expire
await new Promise(resolve => setTimeout(resolve, 1100));
// Should create new context
await contextManager.getContext('test-id', { test: true });
expect(contextManager.stats.misses).toBe(2);
expect(contextManager.stats.hits).toBe(0);
});
});
describe('updateContext', () => {
it('should update existing context metadata', async () => {
await contextManager.getContext('test-id', { initial: true });
const updated = await contextManager.updateContext('test-id', { updated: true });
expect(updated.metadata.initial).toBe(true);
expect(updated.metadata.updated).toBe(true);
});
});
describe('invalidateContext', () => {
it('should remove context from cache', async () => {
await contextManager.getContext('test-id', { test: true });
contextManager.invalidateContext('test-id', { test: true });
// Should be a cache miss
await contextManager.getContext('test-id', { test: true });
expect(contextManager.stats.invalidations).toBe(1);
expect(contextManager.stats.misses).toBe(2);
});
});
describe('getStats', () => {
it('should return current cache statistics', async () => {
await contextManager.getContext('test-id', { test: true });
const stats = contextManager.getStats();
expect(stats.hits).toBe(0);
expect(stats.misses).toBe(1);
expect(stats.invalidations).toBe(0);
expect(stats.size).toBe(1);
expect(stats.maxSize).toBe(10);
expect(stats.ttl).toBe(1000);
});
});
});

View File

@@ -0,0 +1,170 @@
/**
* context-manager.js
* Context and cache management for Task Master MCP Server
*/
import { FastMCP } from 'fastmcp';
import { LRUCache } from 'lru-cache';
/**
* Configuration options for the ContextManager
* @typedef {Object} ContextManagerConfig
* @property {number} maxCacheSize - Maximum number of items in the cache
* @property {number} ttl - Time to live for cached items in milliseconds
* @property {number} maxContextSize - Maximum size of context window in tokens
*/
export class ContextManager {
/**
* Create a new ContextManager instance
* @param {ContextManagerConfig} config - Configuration options
*/
constructor(config = {}) {
this.config = {
maxCacheSize: config.maxCacheSize || 1000,
ttl: config.ttl || 1000 * 60 * 5, // 5 minutes default
maxContextSize: config.maxContextSize || 4000
};
// Initialize LRU cache for context data
this.cache = new LRUCache({
max: this.config.maxCacheSize,
ttl: this.config.ttl,
updateAgeOnGet: true
});
// Cache statistics
this.stats = {
hits: 0,
misses: 0,
invalidations: 0
};
}
/**
* Create a new context or retrieve from cache
* @param {string} contextId - Unique identifier for the context
* @param {Object} metadata - Additional metadata for the context
* @returns {Object} Context object with metadata
*/
async getContext(contextId, metadata = {}) {
const cacheKey = this._getCacheKey(contextId, metadata);
// Try to get from cache first
const cached = this.cache.get(cacheKey);
if (cached) {
this.stats.hits++;
return cached;
}
this.stats.misses++;
// Create new context if not in cache
const context = {
id: contextId,
metadata: {
...metadata,
created: new Date().toISOString()
}
};
// Cache the new context
this.cache.set(cacheKey, context);
return context;
}
/**
* Update an existing context
* @param {string} contextId - Context identifier
* @param {Object} updates - Updates to apply to the context
* @returns {Object} Updated context
*/
async updateContext(contextId, updates) {
const context = await this.getContext(contextId);
// Apply updates to context
Object.assign(context.metadata, updates);
// Update cache
const cacheKey = this._getCacheKey(contextId, context.metadata);
this.cache.set(cacheKey, context);
return context;
}
/**
* Invalidate a context in the cache
* @param {string} contextId - Context identifier
* @param {Object} metadata - Metadata used in the cache key
*/
invalidateContext(contextId, metadata = {}) {
const cacheKey = this._getCacheKey(contextId, metadata);
this.cache.delete(cacheKey);
this.stats.invalidations++;
}
/**
* Get cached data associated with a specific key.
* Increments cache hit stats if found.
* @param {string} key - The cache key.
* @returns {any | undefined} The cached data or undefined if not found/expired.
*/
getCachedData(key) {
const cached = this.cache.get(key);
if (cached !== undefined) { // Check for undefined specifically, as null/false might be valid cached values
this.stats.hits++;
return cached;
}
this.stats.misses++;
return undefined;
}
/**
* Set data in the cache with a specific key.
* @param {string} key - The cache key.
* @param {any} data - The data to cache.
*/
setCachedData(key, data) {
this.cache.set(key, data);
}
/**
* Invalidate a specific cache key.
* Increments invalidation stats.
* @param {string} key - The cache key to invalidate.
*/
invalidateCacheKey(key) {
this.cache.delete(key);
this.stats.invalidations++;
}
/**
* Get cache statistics
* @returns {Object} Cache statistics
*/
getStats() {
return {
hits: this.stats.hits,
misses: this.stats.misses,
invalidations: this.stats.invalidations,
size: this.cache.size,
maxSize: this.config.maxCacheSize,
ttl: this.config.ttl
};
}
/**
* Generate a cache key from context ID and metadata
* @private
* @deprecated No longer used for direct cache key generation outside the manager.
* Prefer generating specific keys in calling functions.
*/
_getCacheKey(contextId, metadata) {
// Kept for potential backward compatibility or internal use if needed later.
return `${contextId}:${JSON.stringify(metadata)}`;
}
}
// Export a singleton instance with default config
export const contextManager = new ContextManager();

View File

@@ -21,6 +21,10 @@ import {
// We'll import more functions as we continue implementation
} from '../../../scripts/modules/task-manager.js';
// Import context manager
import { contextManager } from './context-manager.js';
import { getCachedOrExecute } from '../tools/utils.js'; // Import the utility here
/**
* Finds the absolute path to the tasks.json file based on project root and arguments.
* @param {Object} args - Command arguments, potentially including 'projectRoot' and 'file'.
@@ -58,52 +62,95 @@ function findTasksJsonPath(args, log) {
}
// If no file was found, throw an error
throw new Error(`Tasks file not found in any of the expected locations relative to ${projectRoot}: ${possiblePaths.join(', ')}`);
const error = new Error(`Tasks file not found in any of the expected locations relative to ${projectRoot}: ${possiblePaths.join(', ')}`);
error.code = 'TASKS_FILE_NOT_FOUND';
throw error;
}
/**
* Direct function wrapper for listTasks with error handling
*
* @param {Object} args - Command arguments (projectRoot is expected to be resolved)
* @param {Object} log - Logger object
* @returns {Object} - Task list result
* Direct function wrapper for listTasks with error handling and caching.
*
* @param {Object} args - Command arguments (projectRoot is expected to be resolved).
* @param {Object} log - Logger object.
* @returns {Promise<Object>} - Task list result { success: boolean, data?: any, error?: { code: string, message: string }, fromCache: boolean }.
*/
export async function listTasksDirect(args, log) {
let tasksPath;
try {
log.info(`Listing tasks with args: ${JSON.stringify(args)}`);
// Use the helper function to find the tasks file path
const tasksPath = findTasksJsonPath(args, log);
// Extract other arguments
const statusFilter = args.status || null;
const withSubtasks = args.withSubtasks || false;
log.info(`Using tasks file at: ${tasksPath}`);
log.info(`Status filter: ${statusFilter}, withSubtasks: ${withSubtasks}`);
// Call listTasks with json format
const result = listTasks(tasksPath, statusFilter, withSubtasks, 'json');
if (!result || !result.tasks) {
throw new Error('Invalid or empty response from listTasks function');
// Find the tasks path first - needed for cache key and execution
tasksPath = findTasksJsonPath(args, log);
} catch (error) {
if (error.code === 'TASKS_FILE_NOT_FOUND') {
log.error(`Tasks file not found: ${error.message}`);
// Return the error structure expected by the calling tool/handler
return { success: false, error: { code: error.code, message: error.message }, fromCache: false };
}
log.info(`Successfully retrieved ${result.tasks.length} tasks`);
// Return the raw result directly
log.error(`Unexpected error finding tasks file: ${error.message}`);
// Re-throw for outer catch or return structured error
return { success: false, error: { code: 'FIND_TASKS_PATH_ERROR', message: error.message }, fromCache: false };
}
// Generate cache key *after* finding tasksPath
const statusFilter = args.status || 'all';
const withSubtasks = args.withSubtasks || false;
const cacheKey = `listTasks:${tasksPath}:${statusFilter}:${withSubtasks}`;
// Define the action function to be executed on cache miss
const coreListTasksAction = async () => {
try {
log.info(`Executing core listTasks function for path: ${tasksPath}, filter: ${statusFilter}, subtasks: ${withSubtasks}`);
const resultData = listTasks(tasksPath, statusFilter, withSubtasks, 'json');
if (!resultData || !resultData.tasks) {
log.error('Invalid or empty response from listTasks core function');
return { success: false, error: { code: 'INVALID_CORE_RESPONSE', message: 'Invalid or empty response from listTasks core function' } };
}
log.info(`Core listTasks function retrieved ${resultData.tasks.length} tasks`);
return { success: true, data: resultData };
} catch (error) {
log.error(`Core listTasks function failed: ${error.message}`);
return { success: false, error: { code: 'LIST_TASKS_CORE_ERROR', message: error.message || 'Failed to list tasks' } };
}
};
// Use the caching utility
try {
const result = await getCachedOrExecute({
cacheKey,
actionFn: coreListTasksAction,
log
});
log.info(`listTasksDirect completed. From cache: ${result.fromCache}`);
return result; // Returns { success, data/error, fromCache }
} catch(error) {
// Catch unexpected errors from getCachedOrExecute itself (though unlikely)
log.error(`Unexpected error during getCachedOrExecute for listTasks: ${error.message}`);
console.error(error.stack);
return { success: false, error: { code: 'CACHE_UTIL_ERROR', message: error.message }, fromCache: false };
}
}
/**
* Get cache statistics for monitoring
* @param {Object} args - Command arguments
* @param {Object} log - Logger object
* @returns {Object} - Cache statistics
*/
export async function getCacheStatsDirect(args, log) {
try {
log.info('Retrieving cache statistics');
const stats = contextManager.getStats();
return {
success: true,
data: result // Return the actual object, not a stringified version
data: stats
};
} catch (error) {
log.error(`Error in listTasksDirect: ${error.message}`);
// Ensure we always return a properly structured error object
log.error(`Error getting cache stats: ${error.message}`);
return {
success: false,
error: {
code: error.code || 'LIST_TASKS_ERROR',
code: 'CACHE_STATS_ERROR',
message: error.message || 'Unknown error occurred'
}
};
@@ -115,5 +162,6 @@ export async function listTasksDirect(args, log) {
*/
export const directFunctions = {
list: listTasksDirect,
cacheStats: getCacheStatsDirect,
// Add more functions as we implement them
};

View File

@@ -5,6 +5,7 @@
import { spawnSync } from "child_process";
import path from "path";
import { contextManager } from '../core/context-manager.js'; // Import the singleton
/**
* Get normalized project root path
@@ -36,15 +37,25 @@ export function getProjectRoot(projectRootRaw, log) {
export function handleApiResult(result, log, errorPrefix = 'API error', processFunction = processMCPResponseData) {
if (!result.success) {
const errorMsg = result.error?.message || `Unknown ${errorPrefix}`;
log.error(`${errorPrefix}: ${errorMsg}`);
// Include cache status in error logs
log.error(`${errorPrefix}: ${errorMsg}. From cache: ${result.fromCache}`); // Keep logging cache status on error
return createErrorResponse(errorMsg);
}
// Process the result data if needed and if we have a processor function
// Process the result data if needed
const processedData = processFunction ? processFunction(result.data) : result.data;
// Return formatted response
return createContentResponse(processedData);
// Log success including cache status
log.info(`Successfully completed operation. From cache: ${result.fromCache}`); // Add success log with cache status
// Create the response payload including the fromCache flag
const responsePayload = {
fromCache: result.fromCache, // Get the flag from the original 'result'
data: processedData // Nest the processed data under a 'data' key
};
// Pass this combined payload to createContentResponse
return createContentResponse(responsePayload);
}
/**
@@ -121,56 +132,140 @@ export function executeTaskMasterCommand(
}
/**
* Executes a Task Master tool action with standardized error handling, logging, and response formatting
* Checks cache for a result using the provided key. If not found, executes the action function,
* caches the result upon success, and returns the result.
*
* @param {Object} options - Configuration options.
* @param {string} options.cacheKey - The unique key for caching this operation's result.
* @param {Function} options.actionFn - The async function to execute if the cache misses.
* Should return an object like { success: boolean, data?: any, error?: { code: string, message: string } }.
* @param {Object} options.log - The logger instance.
* @returns {Promise<Object>} - An object containing the result, indicating if it was from cache.
* Format: { success: boolean, data?: any, error?: { code: string, message: string }, fromCache: boolean }
*/
export async function getCachedOrExecute({ cacheKey, actionFn, log }) {
// Check cache first
const cachedResult = contextManager.getCachedData(cacheKey);
if (cachedResult !== undefined) {
log.info(`Cache hit for key: ${cacheKey}`);
// Return the cached data in the same structure as a fresh result
return {
...cachedResult, // Spread the cached result to maintain its structure
fromCache: true // Just add the fromCache flag
};
}
log.info(`Cache miss for key: ${cacheKey}. Executing action function.`);
// Execute the action function if cache missed
const result = await actionFn();
// If the action was successful, cache the result (but without fromCache flag)
if (result.success && result.data !== undefined) {
log.info(`Action successful. Caching result for key: ${cacheKey}`);
// Cache the entire result structure (minus the fromCache flag)
const { fromCache, ...resultToCache } = result;
contextManager.setCachedData(cacheKey, resultToCache);
} else if (!result.success) {
log.warn(`Action failed for cache key ${cacheKey}. Result not cached. Error: ${result.error?.message}`);
} else {
log.warn(`Action for cache key ${cacheKey} succeeded but returned no data. Result not cached.`);
}
// Return the fresh result, indicating it wasn't from cache
return {
...result,
fromCache: false
};
}
/**
* 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 to execute (must return {success, data, error})
* @param {Object} options.args - Arguments for the action
* @param {Object} options.log - Logger object from FastMCP
* @param {string} options.actionName - Name of the action for logging purposes
* @param {Function} options.processResult - Optional function to process the result before returning
* @returns {Promise<Object>} - Standardized response for FastMCP
* @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}`);
// Execute the core action function with normalized arguments
const result = await actionFn({...args, projectRoot}, log);
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()}`;
log.error(`Error during ${actionName.toLowerCase()}: ${errorMsg}`);
// 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()}`);
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
};
// Return formatted response
return createContentResponse(processedData);
// Pass this combined payload to createContentResponse
return createContentResponse(responsePayload);
} catch (error) {
// Handle unexpected errors
log.error(`Unexpected error during ${actionName.toLowerCase()}: ${error.message}`);
return createErrorResponse(error.message);
// 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}`);
}
}

23
package-lock.json generated
View File

@@ -23,6 +23,7 @@
"gradient-string": "^3.0.0",
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.2",
"lru-cache": "^10.2.0",
"openai": "^4.89.0",
"ora": "^8.2.0"
},
@@ -163,6 +164,16 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
@@ -5505,14 +5516,10 @@
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"license": "ISC"
},
"node_modules/make-dir": {
"version": "4.0.0",

View File

@@ -37,6 +37,7 @@
"license": "MIT",
"dependencies": {
"@anthropic-ai/sdk": "^0.39.0",
"@model-context-protocol/sdk": "^1.20.5",
"boxen": "^8.0.1",
"chalk": "^4.1.2",
"cli-table3": "^0.6.5",
@@ -46,12 +47,13 @@
"express": "^4.21.2",
"fastmcp": "^1.20.5",
"figlet": "^1.8.0",
"fuse.js": "^7.0.0",
"gradient-string": "^3.0.0",
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.2",
"lru-cache": "^10.2.0",
"openai": "^4.89.0",
"ora": "^8.2.0",
"fuse.js": "^7.0.0"
"ora": "^8.2.0"
},
"engines": {
"node": ">=14.0.0"

View File

@@ -997,16 +997,16 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
displayBanner();
}
const data = readJSON(tasksPath);
const data = readJSON(tasksPath); // Reads the whole tasks.json
if (!data || !data.tasks) {
throw new Error(`No valid tasks found in ${tasksPath}`);
}
// Filter tasks by status if specified
const filteredTasks = statusFilter
const filteredTasks = statusFilter && statusFilter.toLowerCase() !== 'all' // <-- Added check for 'all'
? data.tasks.filter(task =>
task.status && task.status.toLowerCase() === statusFilter.toLowerCase())
: data.tasks;
: data.tasks; // Default to all tasks if no filter or filter is 'all'
// Calculate completion statistics
const totalTasks = data.tasks.length;
@@ -1039,7 +1039,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
// For JSON output, return structured data
if (outputFormat === 'json') {
// *** Modification: Remove 'details' field for JSON output ***
const tasksWithoutDetails = filteredTasks.map(task => {
const tasksWithoutDetails = filteredTasks.map(task => { // <-- USES filteredTasks!
// Omit 'details' from the parent task
const { details, ...taskRest } = task;
@@ -1055,8 +1055,8 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
// *** End of Modification ***
return {
tasks: tasksWithoutDetails, // Return the modified tasks
filter: statusFilter,
tasks: tasksWithoutDetails, // <--- THIS IS THE ARRAY BEING RETURNED
filter: statusFilter || 'all', // Return the actual filter used
stats: {
total: totalTasks,
completed: doneCount,

View File

@@ -222,7 +222,7 @@ Testing approach:
- Validate compatibility with existing MCP clients.
- Benchmark performance improvements from SDK integration.
## 8. Implement Direct Function Imports and Replace CLI-based Execution [in-progress]
## 8. Implement Direct Function Imports and Replace CLI-based Execution [done]
### Dependencies: 23.13
### Description: Refactor the MCP server implementation to use direct Task Master function imports instead of the current CLI-based execution using child_process.spawnSync. This will improve performance, reliability, and enable better error handling.
### Details:
@@ -290,7 +290,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
```
</info added on 2025-03-30T00:14:10.040Z>
## 9. Implement Context Management and Caching Mechanisms [deferred]
## 9. Implement Context Management and Caching Mechanisms [in-progress]
### Dependencies: 23.1
### Description: Enhance the MCP server with proper context management and caching to improve performance and user experience, especially for frequently accessed data and contexts.
### Details:
@@ -346,3 +346,93 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
### 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
## 16. Implement parse-prd MCP command [pending]
### Dependencies: None
### 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
## 17. Implement update MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for updating multiple tasks based on prompt.
### Details:
Following MCP implementation standards:\n\n1. Create updateTasksDirect function in task-master-core.js:\n - Import updateTasks from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: fromId, prompt, useResearch\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create update.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import updateTasksDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerUpdateTool(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 updateTasksDirect\n - Integration test for MCP tool
## 18. Implement update-task MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for updating a single task by ID with new information.
### Details:
Following MCP implementation standards:\n\n1. Create updateTaskByIdDirect function in task-master-core.js:\n - Import updateTaskById from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId, prompt, useResearch\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create update-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 updateTaskByIdDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerUpdateTaskTool(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 updateTaskByIdDirect\n - Integration test for MCP tool
## 19. Implement update-subtask MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for appending information to a specific subtask.
### Details:
Following MCP implementation standards:\n\n1. Create updateSubtaskByIdDirect function in task-master-core.js:\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 - Add to directFunctions map\n\n2. 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\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 updateSubtaskByIdDirect\n - Integration test for MCP tool
## 20. Implement generate MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for generating task files from tasks.json.
### Details:
Following MCP implementation standards:\n\n1. Create generateTaskFilesDirect function in task-master-core.js:\n - Import generateTaskFiles from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: tasksPath, outputDir\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create generate.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import generateTaskFilesDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerGenerateTool(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 generateTaskFilesDirect\n - Integration test for MCP tool
## 21. Implement set-status MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for setting task status.
### Details:
Following MCP implementation standards:\n\n1. Create setTaskStatusDirect function in task-master-core.js:\n - Import setTaskStatus from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId, status\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create set-status.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import setTaskStatusDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerSetStatusTool(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 setTaskStatusDirect\n - Integration test for MCP tool
## 22. Implement show-task MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for showing task details.
### Details:
Following MCP implementation standards:\n\n1. Create showTaskDirect function in task-master-core.js:\n - Import showTask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create show-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 showTaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerShowTaskTool(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 showTaskDirect\n - Integration test for MCP tool
## 23. Implement next-task MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for finding the next task to work on.
### Details:
Following MCP implementation standards:\n\n1. Create nextTaskDirect function in task-master-core.js:\n - Import nextTask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments (no specific args needed except projectRoot/file)\n - Handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create next-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 nextTaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerNextTaskTool(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 nextTaskDirect\n - Integration test for MCP tool
## 24. Implement expand-task MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for expanding a task into subtasks.
### Details:
Following MCP implementation standards:\n\n1. Create expandTaskDirect function in task-master-core.js:\n - Import expandTask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId, prompt, num, force, research\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create expand-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 expandTaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerExpandTaskTool(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 expandTaskDirect\n - Integration test for MCP tool
## 25. Implement add-task MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for adding new tasks.
### Details:
Following MCP implementation standards:\n\n1. Create addTaskDirect function in task-master-core.js:\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 - Add to directFunctions map\n\n2. 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\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 addTaskDirect\n - Integration test for MCP tool
## 26. Implement add-subtask MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for adding subtasks to existing tasks.
### Details:
Following MCP implementation standards:\n\n1. Create addSubtaskDirect function in task-master-core.js:\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 - Add to directFunctions map\n\n2. 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\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 addSubtaskDirect\n - Integration test for MCP tool
## 27. Implement remove-subtask MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for removing subtasks from tasks.
### Details:
Following MCP implementation standards:\n\n1. Create removeSubtaskDirect function in task-master-core.js:\n - Import removeSubtask from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: parentTaskId, subtaskId\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create remove-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 removeSubtaskDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerRemoveSubtaskTool(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 removeSubtaskDirect\n - Integration test for MCP tool
## 28. Implement analyze MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for analyzing task complexity.
### Details:
Following MCP implementation standards:\n\n1. Create analyzeTaskComplexityDirect function in task-master-core.js:\n - Import analyzeTaskComplexity from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create analyze.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import analyzeTaskComplexityDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerAnalyzeTool(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 analyzeTaskComplexityDirect\n - Integration test for MCP tool
## 29. Implement clear-subtasks MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for clearing subtasks from a parent task.
### Details:
Following MCP implementation standards:\n\n1. Create clearSubtasksDirect function in task-master-core.js:\n - Import clearSubtasks from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: taskId\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create clear-subtasks.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import clearSubtasksDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerClearSubtasksTool(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 clearSubtasksDirect\n - Integration test for MCP tool
## 30. Implement expand-all MCP command [pending]
### Dependencies: None
### Description: Create direct function wrapper and MCP tool for expanding all tasks into subtasks.
### Details:
Following MCP implementation standards:\n\n1. Create expandAllTasksDirect function in task-master-core.js:\n - Import expandAllTasks from task-manager.js\n - Handle file paths using findTasksJsonPath utility\n - Process arguments: prompt, num, force, research\n - Validate inputs and handle errors with try/catch\n - Return standardized { success, data/error } object\n - Add to directFunctions map\n\n2. Create expand-all.js MCP tool in mcp-server/src/tools/:\n - Import z from zod for parameter schema\n - Import executeMCPToolAction from ./utils.js\n - Import expandAllTasksDirect from task-master-core.js\n - Define parameters matching CLI options using zod schema\n - Implement registerExpandAllTool(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 expandAllTasksDirect\n - Integration test for MCP tool

View File

@@ -1400,7 +1400,7 @@
"23.13"
],
"details": "\n\n<info added on 2025-03-30T00:14:10.040Z>\n```\n# Refactoring Strategy for Direct Function Imports\n\n## Core Approach\n1. Create a clear separation between data retrieval/processing and presentation logic\n2. Modify function signatures to accept `outputFormat` parameter ('cli'|'json', default: 'cli')\n3. Implement early returns for JSON format to bypass CLI-specific code\n\n## Implementation Details for `listTasks`\n```javascript\nfunction listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat = 'cli') {\n try {\n // Existing data retrieval logic\n const filteredTasks = /* ... */;\n \n // Early return for JSON format\n if (outputFormat === 'json') return filteredTasks;\n \n // Existing CLI output logic\n } catch (error) {\n if (outputFormat === 'json') {\n throw {\n code: 'TASK_LIST_ERROR',\n message: error.message,\n details: error.stack\n };\n } else {\n console.error(error);\n process.exit(1);\n }\n }\n}\n```\n\n## Testing Strategy\n- Create integration tests in `tests/integration/mcp-server/`\n- Use FastMCP InMemoryTransport for direct client-server testing\n- Test both JSON and CLI output formats\n- Verify structure consistency with schema validation\n\n## Additional Considerations\n- Update JSDoc comments to document new parameters and return types\n- Ensure backward compatibility with default CLI behavior\n- Add JSON schema validation for consistent output structure\n- Apply similar pattern to other core functions (expandTask, updateTaskById, etc.)\n\n## Error Handling Improvements\n- Standardize error format for JSON returns:\n```javascript\n{\n code: 'ERROR_CODE',\n message: 'Human-readable message',\n details: {}, // Additional context when available\n stack: process.env.NODE_ENV === 'development' ? error.stack : undefined\n}\n```\n- Enrich JSON errors with error codes and debug info\n- Ensure validation failures return proper objects in JSON mode\n```\n</info added on 2025-03-30T00:14:10.040Z>",
"status": "in-progress",
"status": "done",
"parentTaskId": 23
},
{
@@ -1411,7 +1411,7 @@
1
],
"details": "1. Implement a context manager class that leverages FastMCP's Context object\n2. Add caching for frequently accessed task data with configurable TTL settings\n3. Implement context tagging for better organization of context data\n4. Add methods to efficiently handle large context windows\n5. Create helper functions for storing and retrieving context data\n6. Implement cache invalidation strategies for task updates\n7. Add cache statistics for monitoring performance\n8. Create unit tests for context management and caching functionality",
"status": "deferred",
"status": "in-progress",
"parentTaskId": 23
},
{
@@ -1486,6 +1486,141 @@
"23.11"
],
"parentTaskId": 23
},
{
"id": 16,
"title": "Implement parse-prd MCP command",
"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",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 17,
"title": "Implement update MCP command",
"description": "Create direct function wrapper and MCP tool for updating multiple tasks based on prompt.",
"details": "Following MCP implementation standards:\\n\\n1. Create updateTasksDirect function in task-master-core.js:\\n - Import updateTasks from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: fromId, prompt, useResearch\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create update.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import updateTasksDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerUpdateTool(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 updateTasksDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 18,
"title": "Implement update-task MCP command",
"description": "Create direct function wrapper and MCP tool for updating a single task by ID with new information.",
"details": "Following MCP implementation standards:\\n\\n1. Create updateTaskByIdDirect function in task-master-core.js:\\n - Import updateTaskById from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId, prompt, useResearch\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create update-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 updateTaskByIdDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerUpdateTaskTool(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 updateTaskByIdDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 19,
"title": "Implement update-subtask MCP command",
"description": "Create direct function wrapper and MCP tool for appending information to a specific subtask.",
"details": "Following MCP implementation standards:\\n\\n1. Create updateSubtaskByIdDirect function in task-master-core.js:\\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 - Add to directFunctions map\\n\\n2. 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\\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 updateSubtaskByIdDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 20,
"title": "Implement generate MCP command",
"description": "Create direct function wrapper and MCP tool for generating task files from tasks.json.",
"details": "Following MCP implementation standards:\\n\\n1. Create generateTaskFilesDirect function in task-master-core.js:\\n - Import generateTaskFiles from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: tasksPath, outputDir\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create generate.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import generateTaskFilesDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerGenerateTool(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 generateTaskFilesDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 21,
"title": "Implement set-status MCP command",
"description": "Create direct function wrapper and MCP tool for setting task status.",
"details": "Following MCP implementation standards:\\n\\n1. Create setTaskStatusDirect function in task-master-core.js:\\n - Import setTaskStatus from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId, status\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create set-status.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import setTaskStatusDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerSetStatusTool(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 setTaskStatusDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 22,
"title": "Implement show-task MCP command",
"description": "Create direct function wrapper and MCP tool for showing task details.",
"details": "Following MCP implementation standards:\\n\\n1. Create showTaskDirect function in task-master-core.js:\\n - Import showTask from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create show-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 showTaskDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerShowTaskTool(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 showTaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 23,
"title": "Implement next-task MCP command",
"description": "Create direct function wrapper and MCP tool for finding the next task to work on.",
"details": "Following MCP implementation standards:\\n\\n1. Create nextTaskDirect function in task-master-core.js:\\n - Import nextTask from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments (no specific args needed except projectRoot/file)\\n - Handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create next-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 nextTaskDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerNextTaskTool(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 nextTaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 24,
"title": "Implement expand-task MCP command",
"description": "Create direct function wrapper and MCP tool for expanding a task into subtasks.",
"details": "Following MCP implementation standards:\\n\\n1. Create expandTaskDirect function in task-master-core.js:\\n - Import expandTask from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId, prompt, num, force, research\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create expand-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 expandTaskDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerExpandTaskTool(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 expandTaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 25,
"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 function in task-master-core.js:\\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 - Add to directFunctions map\\n\\n2. 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\\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 addTaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 26,
"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 function in task-master-core.js:\\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 - Add to directFunctions map\\n\\n2. 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\\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 addSubtaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 27,
"title": "Implement remove-subtask MCP command",
"description": "Create direct function wrapper and MCP tool for removing subtasks from tasks.",
"details": "Following MCP implementation standards:\\n\\n1. Create removeSubtaskDirect function in task-master-core.js:\\n - Import removeSubtask from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: parentTaskId, subtaskId\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create remove-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 removeSubtaskDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerRemoveSubtaskTool(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 removeSubtaskDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 28,
"title": "Implement analyze MCP command",
"description": "Create direct function wrapper and MCP tool for analyzing task complexity.",
"details": "Following MCP implementation standards:\\n\\n1. Create analyzeTaskComplexityDirect function in task-master-core.js:\\n - Import analyzeTaskComplexity from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create analyze.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import analyzeTaskComplexityDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerAnalyzeTool(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 analyzeTaskComplexityDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 29,
"title": "Implement clear-subtasks MCP command",
"description": "Create direct function wrapper and MCP tool for clearing subtasks from a parent task.",
"details": "Following MCP implementation standards:\\n\\n1. Create clearSubtasksDirect function in task-master-core.js:\\n - Import clearSubtasks from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: taskId\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create clear-subtasks.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import clearSubtasksDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerClearSubtasksTool(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 clearSubtasksDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
},
{
"id": 30,
"title": "Implement expand-all MCP command",
"description": "Create direct function wrapper and MCP tool for expanding all tasks into subtasks.",
"details": "Following MCP implementation standards:\\n\\n1. Create expandAllTasksDirect function in task-master-core.js:\\n - Import expandAllTasks from task-manager.js\\n - Handle file paths using findTasksJsonPath utility\\n - Process arguments: prompt, num, force, research\\n - Validate inputs and handle errors with try/catch\\n - Return standardized { success, data/error } object\\n - Add to directFunctions map\\n\\n2. Create expand-all.js MCP tool in mcp-server/src/tools/:\\n - Import z from zod for parameter schema\\n - Import executeMCPToolAction from ./utils.js\\n - Import expandAllTasksDirect from task-master-core.js\\n - Define parameters matching CLI options using zod schema\\n - Implement registerExpandAllTool(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 expandAllTasksDirect\\n - Integration test for MCP tool",
"status": "pending",
"dependencies": [],
"parentTaskId": 23
}
]
},

View File

@@ -24,8 +24,8 @@ const mockLogger = {
};
// Test file paths
const testProjectRoot = path.join(__dirname, '../../fixtures/test-project');
const testTasksPath = path.join(testProjectRoot, 'tasks.json');
const testProjectRoot = path.join(__dirname, '../../fixture');
const testTasksPath = path.join(testProjectRoot, 'test-tasks.json');
describe('MCP Server Direct Functions', () => {
// Create test data before tests