From d5ecca25db82bf657b4f6e7cc3f6e8e631d477bc Mon Sep 17 00:00:00 2001 From: Eyal Toledano Date: Tue, 1 Apr 2025 03:12:44 -0400 Subject: [PATCH] fix(mcp): make projectRoot optional in all MCP tools - Update all tool definitions to use z.string().optional() for projectRoot - Fix direct function implementations to use findTasksJsonPath(args, log) pattern - Enables consistent project root detection without requiring explicit params - Update changeset to document these improvements This change ensures MCP tools work properly with the smart project root detection system, removing the need for explicit projectRoot parameters in client applications. Improves usability and reduces integration friction. --- .changeset/two-bats-smoke.md | 5 +++++ mcp-server/src/core/direct-functions/add-subtask.js | 2 +- mcp-server/src/core/direct-functions/add-task.js | 4 ++-- .../src/core/direct-functions/analyze-task-complexity.js | 2 +- mcp-server/src/core/direct-functions/clear-subtasks.js | 2 +- mcp-server/src/core/direct-functions/expand-all-tasks.js | 2 +- mcp-server/src/core/direct-functions/fix-dependencies.js | 4 ++-- .../src/core/direct-functions/remove-dependency.js | 2 +- mcp-server/src/core/direct-functions/remove-subtask.js | 2 +- .../src/core/direct-functions/validate-dependencies.js | 4 ++-- mcp-server/src/tools/add-dependency.js | 2 +- mcp-server/src/tools/add-subtask.js | 2 +- mcp-server/src/tools/add-task.js | 2 +- mcp-server/src/tools/analyze.js | 2 +- mcp-server/src/tools/clear-subtasks.js | 2 +- mcp-server/src/tools/complexity-report.js | 2 +- mcp-server/src/tools/expand-all.js | 2 +- mcp-server/src/tools/fix-dependencies.js | 2 +- mcp-server/src/tools/remove-dependency.js | 2 +- mcp-server/src/tools/remove-subtask.js | 2 +- tasks/task_023.txt | 6 ------ tasks/tasks.json | 9 --------- 22 files changed, 27 insertions(+), 37 deletions(-) diff --git a/.changeset/two-bats-smoke.md b/.changeset/two-bats-smoke.md index f9463947..9d87411c 100644 --- a/.changeset/two-bats-smoke.md +++ b/.changeset/two-bats-smoke.md @@ -16,6 +16,11 @@ - Parent directory traversal to find tasks.json - Package directory as fallback +- Updated all MCP tools to work without explicitly requiring project root: + - Changed all tool definitions from `projectRoot: z.string().describe(...)` to `projectRoot: z.string().optional().describe(...)` + - Updated all direct function implementations from `findTasksJsonPath(args.file, args.projectRoot)` to use the proper `findTasksJsonPath(args, log)` pattern + - These changes allow MCP tools to work properly without requiring the projectRoot parameter, using smart detection to automatically determine the project root + - Add comprehensive PROJECT_MARKERS array for detecting common project files: - Task Master specific files (tasks.json, tasks/tasks.json) - Version control markers (.git, .svn) diff --git a/mcp-server/src/core/direct-functions/add-subtask.js b/mcp-server/src/core/direct-functions/add-subtask.js index f3a71898..b647984c 100644 --- a/mcp-server/src/core/direct-functions/add-subtask.js +++ b/mcp-server/src/core/direct-functions/add-subtask.js @@ -47,7 +47,7 @@ export async function addSubtaskDirect(args, log) { } // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Parse dependencies if provided let dependencies = []; diff --git a/mcp-server/src/core/direct-functions/add-task.js b/mcp-server/src/core/direct-functions/add-task.js index b8ecd71b..ad2a5e51 100644 --- a/mcp-server/src/core/direct-functions/add-task.js +++ b/mcp-server/src/core/direct-functions/add-task.js @@ -20,8 +20,8 @@ import { findTasksJsonPath } from '../utils/path-utils.js'; */ export async function addTaskDirect(args, log) { try { - // Resolve the tasks file path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + // Find the tasks.json path + const tasksPath = findTasksJsonPath(args, log); // Check required parameters if (!args.prompt) { diff --git a/mcp-server/src/core/direct-functions/analyze-task-complexity.js b/mcp-server/src/core/direct-functions/analyze-task-complexity.js index c8f42e28..112dd275 100644 --- a/mcp-server/src/core/direct-functions/analyze-task-complexity.js +++ b/mcp-server/src/core/direct-functions/analyze-task-complexity.js @@ -24,7 +24,7 @@ export async function analyzeTaskComplexityDirect(args, log) { log.info(`Analyzing task complexity with args: ${JSON.stringify(args)}`); // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Determine output path let outputPath = args.output || 'scripts/task-complexity-report.json'; diff --git a/mcp-server/src/core/direct-functions/clear-subtasks.js b/mcp-server/src/core/direct-functions/clear-subtasks.js index 1d2f249a..516d55c4 100644 --- a/mcp-server/src/core/direct-functions/clear-subtasks.js +++ b/mcp-server/src/core/direct-functions/clear-subtasks.js @@ -32,7 +32,7 @@ export async function clearSubtasksDirect(args, log) { } // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Check if tasks.json exists if (!fs.existsSync(tasksPath)) { diff --git a/mcp-server/src/core/direct-functions/expand-all-tasks.js b/mcp-server/src/core/direct-functions/expand-all-tasks.js index ed49fd10..d2896950 100644 --- a/mcp-server/src/core/direct-functions/expand-all-tasks.js +++ b/mcp-server/src/core/direct-functions/expand-all-tasks.js @@ -22,7 +22,7 @@ export async function expandAllTasksDirect(args, log) { log.info(`Expanding all tasks with args: ${JSON.stringify(args)}`); // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Parse parameters const numSubtasks = args.num ? parseInt(args.num, 10) : undefined; diff --git a/mcp-server/src/core/direct-functions/fix-dependencies.js b/mcp-server/src/core/direct-functions/fix-dependencies.js index d5994a04..ff3d0a02 100644 --- a/mcp-server/src/core/direct-functions/fix-dependencies.js +++ b/mcp-server/src/core/direct-functions/fix-dependencies.js @@ -18,8 +18,8 @@ export async function fixDependenciesDirect(args, log) { try { log.info(`Fixing invalid dependencies in tasks...`); - // Determine the tasks file path - const tasksPath = args.file || await findTasksJsonPath(args.projectRoot); + // Find the tasks.json path + const tasksPath = findTasksJsonPath(args, log); // Verify the file exists if (!fs.existsSync(tasksPath)) { diff --git a/mcp-server/src/core/direct-functions/remove-dependency.js b/mcp-server/src/core/direct-functions/remove-dependency.js index 16ab652c..38f245c5 100644 --- a/mcp-server/src/core/direct-functions/remove-dependency.js +++ b/mcp-server/src/core/direct-functions/remove-dependency.js @@ -41,7 +41,7 @@ export async function removeDependencyDirect(args, log) { } // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Format IDs for the core function const taskId = args.id.includes && args.id.includes('.') ? args.id : parseInt(args.id, 10); diff --git a/mcp-server/src/core/direct-functions/remove-subtask.js b/mcp-server/src/core/direct-functions/remove-subtask.js index 2e9e47b9..6072b181 100644 --- a/mcp-server/src/core/direct-functions/remove-subtask.js +++ b/mcp-server/src/core/direct-functions/remove-subtask.js @@ -42,7 +42,7 @@ export async function removeSubtaskDirect(args, log) { } // Find the tasks.json path - const tasksPath = findTasksJsonPath(args.file, args.projectRoot); + const tasksPath = findTasksJsonPath(args, log); // Convert convertToTask to a boolean const convertToTask = args.convert === true; diff --git a/mcp-server/src/core/direct-functions/validate-dependencies.js b/mcp-server/src/core/direct-functions/validate-dependencies.js index 27fbf7dd..3f652cce 100644 --- a/mcp-server/src/core/direct-functions/validate-dependencies.js +++ b/mcp-server/src/core/direct-functions/validate-dependencies.js @@ -18,8 +18,8 @@ export async function validateDependenciesDirect(args, log) { try { log.info(`Validating dependencies in tasks...`); - // Determine the tasks file path - const tasksPath = args.file || await findTasksJsonPath(args.projectRoot); + // Find the tasks.json path + const tasksPath = findTasksJsonPath(args, log); // Verify the file exists if (!fs.existsSync(tasksPath)) { diff --git a/mcp-server/src/tools/add-dependency.js b/mcp-server/src/tools/add-dependency.js index e500bc42..22d78812 100644 --- a/mcp-server/src/tools/add-dependency.js +++ b/mcp-server/src/tools/add-dependency.js @@ -22,7 +22,7 @@ export function registerAddDependencyTool(server) { id: z.string().describe("ID of task that will depend on another task"), dependsOn: z.string().describe("ID of task that will become a dependency"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/add-subtask.js b/mcp-server/src/tools/add-subtask.js index 7a0e29dd..b3abc761 100644 --- a/mcp-server/src/tools/add-subtask.js +++ b/mcp-server/src/tools/add-subtask.js @@ -28,7 +28,7 @@ export function registerAddSubtaskTool(server) { dependencies: z.string().optional().describe("Comma-separated list of dependency IDs for the new subtask"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), skipGenerate: z.boolean().optional().describe("Skip regenerating task files"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/add-task.js b/mcp-server/src/tools/add-task.js index 6fea5d8b..4ea8c9cd 100644 --- a/mcp-server/src/tools/add-task.js +++ b/mcp-server/src/tools/add-task.js @@ -23,7 +23,7 @@ export function registerAddTaskTool(server) { dependencies: z.string().optional().describe("Comma-separated list of task IDs this task depends on"), priority: z.string().optional().describe("Task priority (high, medium, low)"), file: z.string().optional().describe("Path to the tasks file"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async ({ prompt, dependencies, priority, file, projectRoot }, log) => { try { diff --git a/mcp-server/src/tools/analyze.js b/mcp-server/src/tools/analyze.js index ffac81e0..2fc35581 100644 --- a/mcp-server/src/tools/analyze.js +++ b/mcp-server/src/tools/analyze.js @@ -24,7 +24,7 @@ export function registerAnalyzeTool(server) { threshold: z.union([z.number(), z.string()]).optional().describe("Minimum complexity score to recommend expansion (1-10) (default: 5)"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), research: z.boolean().optional().describe("Use Perplexity AI for research-backed complexity analysis"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/clear-subtasks.js b/mcp-server/src/tools/clear-subtasks.js index b0c2d561..60f52c2b 100644 --- a/mcp-server/src/tools/clear-subtasks.js +++ b/mcp-server/src/tools/clear-subtasks.js @@ -22,7 +22,7 @@ export function registerClearSubtasksTool(server) { id: z.string().optional().describe("Task IDs (comma-separated) to clear subtasks from"), all: z.boolean().optional().describe("Clear subtasks from all tasks"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }).refine(data => data.id || data.all, { message: "Either 'id' or 'all' parameter must be provided", path: ["id", "all"] diff --git a/mcp-server/src/tools/complexity-report.js b/mcp-server/src/tools/complexity-report.js index d8c37257..415ad713 100644 --- a/mcp-server/src/tools/complexity-report.js +++ b/mcp-server/src/tools/complexity-report.js @@ -20,7 +20,7 @@ export function registerComplexityReportTool(server) { description: "Display the complexity analysis report in a readable format", parameters: z.object({ file: z.string().optional().describe("Path to the report file (default: scripts/task-complexity-report.json)"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/expand-all.js b/mcp-server/src/tools/expand-all.js index e088c4e7..ddd6fbff 100644 --- a/mcp-server/src/tools/expand-all.js +++ b/mcp-server/src/tools/expand-all.js @@ -24,7 +24,7 @@ export function registerExpandAllTool(server) { prompt: z.string().optional().describe("Additional context to guide subtask generation"), force: z.boolean().optional().describe("Force regeneration of subtasks for tasks that already have them"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/fix-dependencies.js b/mcp-server/src/tools/fix-dependencies.js index 62219542..70340c67 100644 --- a/mcp-server/src/tools/fix-dependencies.js +++ b/mcp-server/src/tools/fix-dependencies.js @@ -20,7 +20,7 @@ export function registerFixDependenciesTool(server) { description: "Fix invalid dependencies in tasks automatically", parameters: z.object({ file: z.string().optional().describe("Path to the tasks file"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/remove-dependency.js b/mcp-server/src/tools/remove-dependency.js index c9d2dacb..2cecf3d6 100644 --- a/mcp-server/src/tools/remove-dependency.js +++ b/mcp-server/src/tools/remove-dependency.js @@ -22,7 +22,7 @@ export function registerRemoveDependencyTool(server) { id: z.string().describe("Task ID to remove dependency from"), dependsOn: z.string().describe("Task ID to remove as a dependency"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/mcp-server/src/tools/remove-subtask.js b/mcp-server/src/tools/remove-subtask.js index 1878aa9c..786de1fe 100644 --- a/mcp-server/src/tools/remove-subtask.js +++ b/mcp-server/src/tools/remove-subtask.js @@ -23,7 +23,7 @@ export function registerRemoveSubtaskTool(server) { convert: z.boolean().optional().describe("Convert the subtask to a standalone task instead of deleting it"), file: z.string().optional().describe("Path to the tasks file (default: tasks/tasks.json)"), skipGenerate: z.boolean().optional().describe("Skip regenerating task files"), - projectRoot: z.string().describe("Root directory of the project (default: current working directory)") + projectRoot: z.string().optional().describe("Root directory of the project (default: current working directory)") }), execute: async (args, { log }) => { try { diff --git a/tasks/task_023.txt b/tasks/task_023.txt index 9bd06e40..c75d2fe7 100644 --- a/tasks/task_023.txt +++ b/tasks/task_023.txt @@ -1207,9 +1207,3 @@ This method provides a consistent way to access environment variables defined in ### Details: -## 47. adjust rules so it prioritizes mcp commands over script [pending] -### Dependencies: None -### Description: -### Details: - - diff --git a/tasks/tasks.json b/tasks/tasks.json index e282ea64..697668d0 100644 --- a/tasks/tasks.json +++ b/tasks/tasks.json @@ -1780,15 +1780,6 @@ "status": "pending", "dependencies": [], "parentTaskId": 23 - }, - { - "id": 47, - "title": "adjust rules so it prioritizes mcp commands over script", - "description": "", - "details": "", - "status": "pending", - "dependencies": [], - "parentTaskId": 23 } ] },