diff --git a/mcp-server/src/core/direct-functions/show-task.js b/mcp-server/src/core/direct-functions/show-task.js index a662a86b..13b298e8 100644 --- a/mcp-server/src/core/direct-functions/show-task.js +++ b/mcp-server/src/core/direct-functions/show-task.js @@ -23,7 +23,7 @@ import { findTasksJsonPath } from '../utils/path-utils.js'; * @param {Object} context - Context object containing session data. * @returns {Promise} - Result object with success status and data/error information. */ -export async function showTaskDirect(args, log, context = {}) { +export async function showTaskDirect(args, log) { // Destructure session from context if needed later, otherwise ignore // const { session } = context; // Destructure projectRoot and other args. projectRoot is assumed normalized. diff --git a/mcp-server/src/tools/add-dependency.js b/mcp-server/src/tools/add-dependency.js index 59dcb380..41a7e5b6 100644 --- a/mcp-server/src/tools/add-dependency.js +++ b/mcp-server/src/tools/add-dependency.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { addDependencyDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -35,28 +36,16 @@ export function registerAddDependencyTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info( `Adding dependency for task ${args.id} to depend on ${args.dependsOn}` ); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -92,6 +81,6 @@ export function registerAddDependencyTool(server) { log.error(`Error in addDependency tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/add-subtask.js b/mcp-server/src/tools/add-subtask.js index 39bbcf13..97cc8be4 100644 --- a/mcp-server/src/tools/add-subtask.js +++ b/mcp-server/src/tools/add-subtask.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { addSubtaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -60,24 +61,15 @@ export function registerAddSubtaskTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Adding subtask with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -113,6 +105,6 @@ export function registerAddSubtaskTool(server) { log.error(`Error in addSubtask tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/add-task.js b/mcp-server/src/tools/add-task.js index d2ba0611..892b2700 100644 --- a/mcp-server/src/tools/add-task.js +++ b/mcp-server/src/tools/add-task.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { createErrorResponse, getProjectRootFromSession, - handleApiResult + handleApiResult, + withNormalizedProjectRoot } from './utils.js'; import { addTaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -63,26 +64,15 @@ export function registerAddTaskTool(server) { .optional() .describe('Whether to use research capabilities for task creation') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Starting add-task with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -92,12 +82,10 @@ export function registerAddTaskTool(server) { ); } - // Call the direct function + // Call the direct functionP const result = await addTaskDirect( { - // Pass the explicitly resolved path tasksJsonPath: tasksJsonPath, - // Pass other relevant args prompt: args.prompt, title: args.title, description: args.description, @@ -106,18 +94,17 @@ export function registerAddTaskTool(server) { dependencies: args.dependencies, priority: args.priority, research: args.research, - projectRoot: rootFolder + projectRoot: args.projectRoot }, log, { session } ); - // Return the result return handleApiResult(result, log); } catch (error) { log.error(`Error in add-task tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/analyze.js b/mcp-server/src/tools/analyze.js index 33cb69c9..ea6d23fe 100644 --- a/mcp-server/src/tools/analyze.js +++ b/mcp-server/src/tools/analyze.js @@ -9,7 +9,7 @@ import fs from 'fs'; // Import fs for directory check/creation import { handleApiResult, createErrorResponse, - getProjectRootFromSession // Assuming this is in './utils.js' relative to this file + withNormalizedProjectRoot } from './utils.js'; import { analyzeTaskComplexityDirect } from '../core/task-master-core.js'; // Assuming core functions are exported via task-master-core.js import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -53,44 +53,34 @@ export function registerAnalyzeProjectComplexityTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { const toolName = 'analyze_project_complexity'; // Define tool name for logging try { log.info( `Executing ${toolName} tool with args: ${JSON.stringify(args)}` ); - // 1. Get Project Root (Mandatory for this tool) - const rootFolder = args.projectRoot; - if (!rootFolder || !path.isAbsolute(rootFolder)) { - log.error( - `${toolName}: projectRoot is required and must be absolute.` - ); - return createErrorResponse( - 'projectRoot is required and must be absolute.' - ); - } - log.info(`${toolName}: Project root: ${rootFolder}`); - - // 2. Resolve Paths relative to projectRoot let tasksJsonPath; try { - // Note: findTasksJsonPath expects 'file' relative to root, or absolute tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, // Pass root and optional relative file path + { projectRoot: args.projectRoot, file: args.file }, log ); log.info(`${toolName}: Resolved tasks path: ${tasksJsonPath}`); } catch (error) { log.error(`${toolName}: Error finding tasks.json: ${error.message}`); return createErrorResponse( - `Failed to find tasks.json within project root '${rootFolder}': ${error.message}` + `Failed to find tasks.json within project root '${args.projectRoot}': ${error.message}` ); } const outputPath = args.output - ? path.resolve(rootFolder, args.output) // Resolve relative output path - : path.resolve(rootFolder, 'scripts', 'task-complexity-report.json'); // Default location resolved relative to root + ? path.resolve(args.projectRoot, args.output) + : path.resolve( + args.projectRoot, + 'scripts', + 'task-complexity-report.json' + ); log.info(`${toolName}: Report output path: ${outputPath}`); @@ -113,26 +103,21 @@ export function registerAnalyzeProjectComplexityTool(server) { // 3. Call Direct Function - Pass projectRoot in first arg object const result = await analyzeTaskComplexityDirect( { - // Pass resolved absolute paths and other args tasksJsonPath: tasksJsonPath, - outputPath: outputPath, // Pass resolved absolute path + outputPath: outputPath, threshold: args.threshold, research: args.research, - projectRoot: rootFolder // <<< Pass projectRoot HERE + projectRoot: args.projectRoot }, log, - { session } // Pass context object with session + { session } ); // 4. Handle Result log.info( `${toolName}: Direct function result: success=${result.success}` ); - return handleApiResult( - result, - log, - 'Error analyzing task complexity' // Consistent error prefix - ); + return handleApiResult(result, log, 'Error analyzing task complexity'); } catch (error) { log.error( `Critical error in ${toolName} tool execute: ${error.message}` @@ -141,6 +126,6 @@ export function registerAnalyzeProjectComplexityTool(server) { `Internal tool error (${toolName}): ${error.message}` ); } - } + }) }); } diff --git a/mcp-server/src/tools/clear-subtasks.js b/mcp-server/src/tools/clear-subtasks.js index f4fbb547..ce82c176 100644 --- a/mcp-server/src/tools/clear-subtasks.js +++ b/mcp-server/src/tools/clear-subtasks.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { clearSubtasksDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -41,26 +42,15 @@ export function registerClearSubtasksTool(server) { message: "Either 'id' or 'all' parameter must be provided", path: ['id', 'all'] }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Clearing subtasks with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -72,14 +62,11 @@ export function registerClearSubtasksTool(server) { const result = await clearSubtasksDirect( { - // Pass the explicitly resolved path tasksJsonPath: tasksJsonPath, - // Pass other relevant args id: args.id, all: args.all }, log - // Remove context object as clearSubtasksDirect likely doesn't need session/reportProgress ); if (result.success) { @@ -93,6 +80,6 @@ export function registerClearSubtasksTool(server) { log.error(`Error in clearSubtasks tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/complexity-report.js b/mcp-server/src/tools/complexity-report.js index 79eb2568..b5ef8fa9 100644 --- a/mcp-server/src/tools/complexity-report.js +++ b/mcp-server/src/tools/complexity-report.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { complexityReportDirect } from '../core/task-master-core.js'; import path from 'path'; @@ -31,34 +32,24 @@ export function registerComplexityReportTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info( `Getting complexity report with args: ${JSON.stringify(args)}` ); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to the complexity report file - // Default to scripts/task-complexity-report.json relative to root + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) const reportPath = args.file - ? path.resolve(rootFolder, args.file) - : path.resolve(rootFolder, 'scripts', 'task-complexity-report.json'); + ? path.resolve(args.projectRoot, args.file) + : path.resolve( + args.projectRoot, + 'scripts', + 'task-complexity-report.json' + ); const result = await complexityReportDirect( { - // Pass the explicitly resolved path reportPath: reportPath - // No other args specific to this tool }, log ); @@ -84,6 +75,6 @@ export function registerComplexityReportTool(server) { `Failed to retrieve complexity report: ${error.message}` ); } - } + }) }); } diff --git a/mcp-server/src/tools/expand-all.js b/mcp-server/src/tools/expand-all.js index 1bbf5aee..a8ccc3cc 100644 --- a/mcp-server/src/tools/expand-all.js +++ b/mcp-server/src/tools/expand-all.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { expandAllTasksDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -59,25 +60,16 @@ export function registerExpandAllTool(server) { 'Absolute path to the project root directory (derived from session if possible)' ) }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info( `Tool expand_all execution started with args: ${JSON.stringify(args)}` ); - const rootFolder = getProjectRootFromSession(session, log); - if (!rootFolder) { - log.error('Could not determine project root from session.'); - return createErrorResponse( - 'Could not determine project root from session.' - ); - } - log.info(`Project root determined: ${rootFolder}`); - let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); log.info(`Resolved tasks.json path: ${tasksJsonPath}`); @@ -95,7 +87,7 @@ export function registerExpandAllTool(server) { research: args.research, prompt: args.prompt, force: args.force, - projectRoot: rootFolder + projectRoot: args.projectRoot }, log, { session } @@ -113,6 +105,6 @@ export function registerExpandAllTool(server) { `An unexpected error occurred: ${error.message}` ); } - } + }) }); } diff --git a/mcp-server/src/tools/expand-task.js b/mcp-server/src/tools/expand-task.js index 684ab9fa..ea6fcbc1 100644 --- a/mcp-server/src/tools/expand-task.js +++ b/mcp-server/src/tools/expand-task.js @@ -4,10 +4,13 @@ */ import { z } from 'zod'; -import { handleApiResult, createErrorResponse } from './utils.js'; +import { + handleApiResult, + createErrorResponse, + withNormalizedProjectRoot +} from './utils.js'; import { expandTaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; -import path from 'path'; /** * Register the expand-task tool with the MCP server @@ -44,32 +47,21 @@ export function registerExpandTaskTool(server) { .default(false) .describe('Force expansion even if subtasks exist') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Starting expand-task with args: ${JSON.stringify(args)}`); - const rootFolder = args.projectRoot; - if (!rootFolder || !path.isAbsolute(rootFolder)) { - log.error( - `expand-task: projectRoot is required and must be absolute.` - ); - return createErrorResponse( - 'projectRoot is required and must be absolute.' - ); - } - - // Resolve the path to tasks.json using the utility + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); - log.info(`expand-task: Resolved tasks path: ${tasksJsonPath}`); } catch (error) { - log.error(`expand-task: Error finding tasks.json: ${error.message}`); + log.error(`Error finding tasks.json: ${error.message}`); return createErrorResponse( - `Failed to find tasks.json within project root '${rootFolder}': ${error.message}` + `Failed to find tasks.json: ${error.message}` ); } @@ -81,24 +73,17 @@ export function registerExpandTaskTool(server) { research: args.research, prompt: args.prompt, force: args.force, - projectRoot: rootFolder + projectRoot: args.projectRoot }, log, { session } ); - log.info( - `expand-task: Direct function result: success=${result.success}` - ); return handleApiResult(result, log, 'Error expanding task'); } catch (error) { - log.error( - `Critical error in ${toolName} tool execute: ${error.message}` - ); - return createErrorResponse( - `Internal tool error (${toolName}): ${error.message}` - ); + log.error(`Error in expand-task tool: ${error.message}`); + return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/fix-dependencies.js b/mcp-server/src/tools/fix-dependencies.js index 729e5064..77a4d4e3 100644 --- a/mcp-server/src/tools/fix-dependencies.js +++ b/mcp-server/src/tools/fix-dependencies.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { fixDependenciesDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -26,24 +27,15 @@ export function registerFixDependenciesTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Fixing dependencies with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -71,6 +63,6 @@ export function registerFixDependenciesTool(server) { log.error(`Error in fixDependencies tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/generate.js b/mcp-server/src/tools/generate.js index 34cd380b..be683bc8 100644 --- a/mcp-server/src/tools/generate.js +++ b/mcp-server/src/tools/generate.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { generateTaskFilesDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -32,26 +33,15 @@ export function registerGenerateTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Generating task files with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -61,17 +51,14 @@ export function registerGenerateTool(server) { ); } - // Determine output directory: use explicit arg or default to tasks.json directory const outputDir = args.output - ? path.resolve(rootFolder, args.output) // Resolve relative to root if needed + ? path.resolve(args.projectRoot, args.output) : path.dirname(tasksJsonPath); const result = await generateTaskFilesDirect( { - // Pass the explicitly resolved paths tasksJsonPath: tasksJsonPath, outputDir: outputDir - // No other args specific to this tool }, log ); @@ -89,6 +76,6 @@ export function registerGenerateTool(server) { log.error(`Error in generate tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/get-task.js b/mcp-server/src/tools/get-task.js index f2f95332..bf46d7e8 100644 --- a/mcp-server/src/tools/get-task.js +++ b/mcp-server/src/tools/get-task.js @@ -57,7 +57,7 @@ export function registerShowTaskTool(server) { 'Absolute path to the project root directory (Optional, usually from session)' ) }), - execute: withNormalizedProjectRoot(async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log }) => { const { id, file, status, projectRoot } = args; try { @@ -88,8 +88,7 @@ export function registerShowTaskTool(server) { status: status, projectRoot: projectRoot }, - log, - { session } + log ); if (result.success) { diff --git a/mcp-server/src/tools/get-tasks.js b/mcp-server/src/tools/get-tasks.js index e6c6dec9..c54a272f 100644 --- a/mcp-server/src/tools/get-tasks.js +++ b/mcp-server/src/tools/get-tasks.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { createErrorResponse, handleApiResult, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { listTasksDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -42,31 +43,19 @@ export function registerListTasksTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Getting tasks with filters: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { log.error(`Error finding tasks.json: ${error.message}`); - // Use the error message from findTasksJsonPath for better context return createErrorResponse( `Failed to find tasks.json: ${error.message}` ); @@ -89,7 +78,7 @@ export function registerListTasksTool(server) { log.error(`Error getting tasks: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/models.js b/mcp-server/src/tools/models.js index 107acad2..25662503 100644 --- a/mcp-server/src/tools/models.js +++ b/mcp-server/src/tools/models.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { getProjectRootFromSession, handleApiResult, - createErrorResponse + createErrorResponse, + withNormalizedProjectRoot } from './utils.js'; import { modelsDirect } from '../core/task-master-core.js'; @@ -56,34 +57,22 @@ export function registerModelsTool(server) { .optional() .describe('Indicates the set model ID is a custom Ollama model.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Starting models tool with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Call the direct function + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) const result = await modelsDirect( - { ...args, projectRoot: rootFolder }, + { ...args, projectRoot: args.projectRoot }, log, { session } ); - // Handle and return the result return handleApiResult(result, log); } catch (error) { log.error(`Error in models tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/next-task.js b/mcp-server/src/tools/next-task.js index a81d341e..799cdc59 100644 --- a/mcp-server/src/tools/next-task.js +++ b/mcp-server/src/tools/next-task.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { nextTaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -27,7 +28,7 @@ export function registerNextTaskTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Finding next task with args: ${JSON.stringify(args)}`); @@ -80,6 +81,6 @@ export function registerNextTaskTool(server) { log.error(`Error in nextTask tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/remove-dependency.js b/mcp-server/src/tools/remove-dependency.js index 59b7caaf..3729cada 100644 --- a/mcp-server/src/tools/remove-dependency.js +++ b/mcp-server/src/tools/remove-dependency.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { removeDependencyDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -33,28 +34,17 @@ export function registerRemoveDependencyTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info( `Removing dependency for task ${args.id} from ${args.dependsOn} with args: ${JSON.stringify(args)}` ); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -66,9 +56,7 @@ export function registerRemoveDependencyTool(server) { const result = await removeDependencyDirect( { - // Pass the explicitly resolved path tasksJsonPath: tasksJsonPath, - // Pass other relevant args id: args.id, dependsOn: args.dependsOn }, @@ -86,6 +74,6 @@ export function registerRemoveDependencyTool(server) { log.error(`Error in removeDependency tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/remove-subtask.js b/mcp-server/src/tools/remove-subtask.js index a0f81554..2677ae48 100644 --- a/mcp-server/src/tools/remove-subtask.js +++ b/mcp-server/src/tools/remove-subtask.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { removeSubtaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -46,26 +47,15 @@ export function registerRemoveSubtaskTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Removing subtask with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -77,9 +67,7 @@ export function registerRemoveSubtaskTool(server) { const result = await removeSubtaskDirect( { - // Pass the explicitly resolved path tasksJsonPath: tasksJsonPath, - // Pass other relevant args id: args.id, convert: args.convert, skipGenerate: args.skipGenerate @@ -98,6 +86,6 @@ export function registerRemoveSubtaskTool(server) { log.error(`Error in removeSubtask tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); } diff --git a/mcp-server/src/tools/remove-task.js b/mcp-server/src/tools/remove-task.js index b064791b..e220ba78 100644 --- a/mcp-server/src/tools/remove-task.js +++ b/mcp-server/src/tools/remove-task.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { removeTaskDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -35,28 +36,15 @@ export function registerRemoveTaskTool(server) { .optional() .describe('Whether to skip confirmation prompt (default: false)') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Removing task(s) with ID(s): ${args.id}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - log.info(`Using project root: ${rootFolder}`); - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -68,7 +56,6 @@ export function registerRemoveTaskTool(server) { log.info(`Using tasks file path: ${tasksJsonPath}`); - // Assume client has already handled confirmation if needed const result = await removeTaskDirect( { tasksJsonPath: tasksJsonPath, @@ -88,6 +75,6 @@ export function registerRemoveTaskTool(server) { log.error(`Error in remove-task tool: ${error.message}`); return createErrorResponse(`Failed to remove task: ${error.message}`); } - } + }) }); } diff --git a/mcp-server/src/tools/set-task-status.js b/mcp-server/src/tools/set-task-status.js index 357f93f8..21132375 100644 --- a/mcp-server/src/tools/set-task-status.js +++ b/mcp-server/src/tools/set-task-status.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { setTaskStatusDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -36,26 +37,15 @@ export function registerSetTaskStatusTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Setting status of task(s) ${args.id} to: ${args.status}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - // Ensure project root was determined - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - - // Resolve the path to tasks.json + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -65,19 +55,15 @@ export function registerSetTaskStatusTool(server) { ); } - // Call the direct function with the resolved path const result = await setTaskStatusDirect( { - // Pass the explicitly resolved path tasksJsonPath: tasksJsonPath, - // Pass other relevant args id: args.id, status: args.status }, log ); - // Log the result if (result.success) { log.info( `Successfully updated status for task(s) ${args.id} to "${args.status}": ${result.data.message}` @@ -88,7 +74,6 @@ export function registerSetTaskStatusTool(server) { ); } - // Format and return the result return handleApiResult(result, log, 'Error setting task status'); } catch (error) { log.error(`Error in setTaskStatus tool: ${error.message}`); @@ -96,6 +81,6 @@ export function registerSetTaskStatusTool(server) { `Error setting task status: ${error.message}` ); } - } + }) }); } diff --git a/mcp-server/src/tools/validate-dependencies.js b/mcp-server/src/tools/validate-dependencies.js index 10beea0a..d21afbd6 100644 --- a/mcp-server/src/tools/validate-dependencies.js +++ b/mcp-server/src/tools/validate-dependencies.js @@ -7,7 +7,8 @@ import { z } from 'zod'; import { handleApiResult, createErrorResponse, - getProjectRootFromSession + getProjectRootFromSession, + withNormalizedProjectRoot } from './utils.js'; import { validateDependenciesDirect } from '../core/task-master-core.js'; import { findTasksJsonPath } from '../core/utils/path-utils.js'; @@ -27,24 +28,15 @@ export function registerValidateDependenciesTool(server) { .string() .describe('The directory of the project. Must be an absolute path.') }), - execute: async (args, { log, session }) => { + execute: withNormalizedProjectRoot(async (args, { log, session }) => { try { log.info(`Validating dependencies with args: ${JSON.stringify(args)}`); - // Get project root from args or session - const rootFolder = - args.projectRoot || getProjectRootFromSession(session, log); - - if (!rootFolder) { - return createErrorResponse( - 'Could not determine project root. Please provide it explicitly or ensure your session contains valid root information.' - ); - } - + // Use args.projectRoot directly (guaranteed by withNormalizedProjectRoot) let tasksJsonPath; try { tasksJsonPath = findTasksJsonPath( - { projectRoot: rootFolder, file: args.file }, + { projectRoot: args.projectRoot, file: args.file }, log ); } catch (error) { @@ -74,6 +66,6 @@ export function registerValidateDependenciesTool(server) { log.error(`Error in validateDependencies tool: ${error.message}`); return createErrorResponse(error.message); } - } + }) }); }