@@ -12,7 +12,7 @@ alwaysApply: false
|
|||||||
|
|
||||||
- **[`commands.js`](mdc:scripts/modules/commands.js): Command Handling**
|
- **[`commands.js`](mdc:scripts/modules/commands.js): Command Handling**
|
||||||
- **Purpose**: Defines and registers all CLI commands using Commander.js.
|
- **Purpose**: Defines and registers all CLI commands using Commander.js.
|
||||||
- **Responsibilities**:
|
- **Responsibilities** (See also: [`commands.mdc`](mdc:.cursor/rules/commands.mdc)):
|
||||||
- Parses command-line arguments and options.
|
- Parses command-line arguments and options.
|
||||||
- Invokes appropriate functions from other modules to execute commands.
|
- Invokes appropriate functions from other modules to execute commands.
|
||||||
- Handles user input and output related to command execution.
|
- Handles user input and output related to command execution.
|
||||||
@@ -86,7 +86,7 @@ alwaysApply: false
|
|||||||
|
|
||||||
- **[`utils.js`](mdc:scripts/modules/utils.js): Utility Functions and Configuration**
|
- **[`utils.js`](mdc:scripts/modules/utils.js): Utility Functions and Configuration**
|
||||||
- **Purpose**: Provides reusable utility functions and global configuration settings used across the application.
|
- **Purpose**: Provides reusable utility functions and global configuration settings used across the application.
|
||||||
- **Responsibilities**:
|
- **Responsibilities** (See also: [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc)):
|
||||||
- Manages global configuration settings loaded from environment variables and defaults.
|
- Manages global configuration settings loaded from environment variables and defaults.
|
||||||
- Implements logging utility with different log levels and output formatting.
|
- Implements logging utility with different log levels and output formatting.
|
||||||
- Provides file system operation utilities (read/write JSON files).
|
- Provides file system operation utilities (read/write JSON files).
|
||||||
@@ -101,6 +101,19 @@ alwaysApply: false
|
|||||||
- `formatTaskId(id)` / `findTaskById(tasks, taskId)`: Task ID and search utilities.
|
- `formatTaskId(id)` / `findTaskById(tasks, taskId)`: Task ID and search utilities.
|
||||||
- `findCycles(subtaskId, dependencyMap)`: Cycle detection algorithm.
|
- `findCycles(subtaskId, dependencyMap)`: Cycle detection algorithm.
|
||||||
|
|
||||||
|
- **[`mcp-server/`](mdc:mcp-server/): MCP Server Integration**
|
||||||
|
- **Purpose**: Provides an MCP (Model Context Protocol) interface for Task Master, allowing integration with external tools like Cursor. Uses FastMCP framework.
|
||||||
|
- **Responsibilities** (See also: [`mcp.mdc`](mdc:.cursor/rules/mcp.mdc)):
|
||||||
|
- Registers Task Master functionalities as tools consumable via MCP.
|
||||||
|
- Handles MCP requests and translates them into calls to the Task Master core logic.
|
||||||
|
- Prefers direct function calls to core modules via [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js) for performance.
|
||||||
|
- Uses CLI execution via `executeTaskMasterCommand` as a fallback.
|
||||||
|
- **Implements Caching**: Utilizes a caching layer (`ContextManager` with `lru-cache`) invoked via `getCachedOrExecute` within direct function wrappers ([`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js)) to optimize performance for specific read operations (e.g., listing tasks).
|
||||||
|
- Standardizes response formatting for MCP clients using utilities in [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js).
|
||||||
|
- **Key Components**:
|
||||||
|
- `mcp-server/src/server.js`: Main server setup and initialization.
|
||||||
|
- `mcp-server/src/tools/`: Directory containing individual tool definitions, each registering a specific Task Master command for MCP.
|
||||||
|
|
||||||
- **Data Flow and Module Dependencies**:
|
- **Data Flow and Module Dependencies**:
|
||||||
|
|
||||||
- **Commands Initiate Actions**: User commands entered via the CLI (handled by [`commands.js`](mdc:scripts/modules/commands.js)) are the entry points for most operations.
|
- **Commands Initiate Actions**: User commands entered via the CLI (handled by [`commands.js`](mdc:scripts/modules/commands.js)) are the entry points for most operations.
|
||||||
@@ -108,10 +121,11 @@ alwaysApply: false
|
|||||||
- **UI for Presentation**: [`ui.js`](mdc:scripts/modules/ui.js) is used by command handlers and task/dependency managers to display information to the user. UI functions primarily consume data and format it for output, without modifying core application state.
|
- **UI for Presentation**: [`ui.js`](mdc:scripts/modules/ui.js) is used by command handlers and task/dependency managers to display information to the user. UI functions primarily consume data and format it for output, without modifying core application state.
|
||||||
- **Utilities for Common Tasks**: [`utils.js`](mdc:scripts/modules/utils.js) provides helper functions used by all other modules for configuration, logging, file operations, and common data manipulations.
|
- **Utilities for Common Tasks**: [`utils.js`](mdc:scripts/modules/utils.js) provides helper functions used by all other modules for configuration, logging, file operations, and common data manipulations.
|
||||||
- **AI Services Integration**: AI functionalities (complexity analysis, task expansion, PRD parsing) are invoked from [`task-manager.js`](mdc:scripts/modules/task-manager.js) and potentially [`commands.js`](mdc:scripts/modules/commands.js), likely using functions that would reside in a dedicated `ai-services.js` module or be integrated within `utils.js` or `task-manager.js`.
|
- **AI Services Integration**: AI functionalities (complexity analysis, task expansion, PRD parsing) are invoked from [`task-manager.js`](mdc:scripts/modules/task-manager.js) and potentially [`commands.js`](mdc:scripts/modules/commands.js), likely using functions that would reside in a dedicated `ai-services.js` module or be integrated within `utils.js` or `task-manager.js`.
|
||||||
|
- **MCP Server Interaction**: External tools interact with the `mcp-server`, which then calls direct function wrappers in `task-master-core.js` or falls back to `executeTaskMasterCommand`. Responses are formatted by `mcp-server/src/tools/utils.js`. See [`mcp.mdc`](mdc:.cursor/rules/mcp.mdc) for details.
|
||||||
|
|
||||||
- **Testing Architecture**:
|
- **Testing Architecture**:
|
||||||
|
|
||||||
- **Test Organization Structure**:
|
- **Test Organization Structure** (See also: [`tests.mdc`](mdc:.cursor/rules/tests.mdc)):
|
||||||
- **Unit Tests**: Located in `tests/unit/`, reflect the module structure with one test file per module
|
- **Unit Tests**: Located in `tests/unit/`, reflect the module structure with one test file per module
|
||||||
- **Integration Tests**: Located in `tests/integration/`, test interactions between modules
|
- **Integration Tests**: Located in `tests/integration/`, test interactions between modules
|
||||||
- **End-to-End Tests**: Located in `tests/e2e/`, test complete workflows from a user perspective
|
- **End-to-End Tests**: Located in `tests/e2e/`, test complete workflows from a user perspective
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ alwaysApply: true
|
|||||||
---
|
---
|
||||||
|
|
||||||
- **Global CLI Commands**
|
- **Global CLI Commands**
|
||||||
- Task Master now provides a global CLI through the `task-master` command
|
- Task Master now provides a global CLI through the `task-master` command (See [`commands.mdc`](mdc:.cursor/rules/commands.mdc) for details)
|
||||||
- All functionality from `scripts/dev.js` is available through this interface
|
- All functionality from `scripts/dev.js` is available through this interface
|
||||||
- Install globally with `npm install -g claude-task-master` or use locally via `npx`
|
- Install globally with `npm install -g claude-task-master` or use locally via `npx`
|
||||||
- Use `task-master <command>` instead of `node scripts/dev.js <command>`
|
- Use `task-master <command>` instead of `node scripts/dev.js <command>`
|
||||||
- Examples:
|
- Examples:
|
||||||
- `task-master list` instead of `node scripts/dev.js list`
|
- `task-master list`
|
||||||
- `task-master next` instead of `node scripts/dev.js next`
|
- `task-master next`
|
||||||
- `task-master expand --id=3` instead of `node scripts/dev.js expand --id=3`
|
- `task-master expand --id=3`
|
||||||
- All commands accept the same options as their script equivalents
|
- All commands accept the same options as their script equivalents
|
||||||
- The CLI provides additional commands like `task-master init` for project setup
|
- The CLI (`task-master`) is the **primary** way for users to interact with the application.
|
||||||
|
|
||||||
- **Development Workflow Process**
|
- **Development Workflow Process**
|
||||||
- Start new projects by running `task-master init` or `node scripts/dev.js parse-prd --input=<prd-file.txt>` to generate initial tasks.json
|
- Start new projects by running `task-master init` or `node scripts/dev.js parse-prd --input=<prd-file.txt>` to generate initial tasks.json
|
||||||
@@ -32,6 +32,7 @@ alwaysApply: true
|
|||||||
- Generate task files with `task-master generate` after updating tasks.json
|
- Generate task files with `task-master generate` after updating tasks.json
|
||||||
- Maintain valid dependency structure with `task-master fix-dependencies` when needed
|
- Maintain valid dependency structure with `task-master fix-dependencies` when needed
|
||||||
- Respect dependency chains and task priorities when selecting work
|
- Respect dependency chains and task priorities when selecting work
|
||||||
|
- **MCP Server**: For integrations (like Cursor), interact via the MCP server which prefers direct function calls. Restart the MCP server if core logic in `scripts/modules` changes. See [`mcp.mdc`](mdc:.cursor/rules/mcp.mdc).
|
||||||
- Report progress regularly using the list command
|
- Report progress regularly using the list command
|
||||||
|
|
||||||
- **Task Complexity Analysis**
|
- **Task Complexity Analysis**
|
||||||
@@ -49,7 +50,7 @@ alwaysApply: true
|
|||||||
- Use `--prompt="<context>"` to provide additional context when needed
|
- Use `--prompt="<context>"` to provide additional context when needed
|
||||||
- Review and adjust generated subtasks as necessary
|
- Review and adjust generated subtasks as necessary
|
||||||
- Use `--all` flag to expand multiple pending tasks at once
|
- Use `--all` flag to expand multiple pending tasks at once
|
||||||
- If subtasks need regeneration, clear them first with `clear-subtasks` command
|
- If subtasks need regeneration, clear them first with `clear-subtasks` command (See Command Reference below)
|
||||||
|
|
||||||
- **Implementation Drift Handling**
|
- **Implementation Drift Handling**
|
||||||
- When implementation differs significantly from planned approach
|
- When implementation differs significantly from planned approach
|
||||||
@@ -79,16 +80,14 @@ alwaysApply: true
|
|||||||
```
|
```
|
||||||
|
|
||||||
- **Command Reference: parse-prd**
|
- **Command Reference: parse-prd**
|
||||||
- Legacy Syntax: `node scripts/dev.js parse-prd --input=<prd-file.txt>`
|
|
||||||
- CLI Syntax: `task-master parse-prd --input=<prd-file.txt>`
|
- CLI Syntax: `task-master parse-prd --input=<prd-file.txt>`
|
||||||
- Description: Parses a PRD document and generates a tasks.json file with structured tasks
|
- Description: Parses a PRD document and generates a `tasks.json` file with structured tasks
|
||||||
- Parameters:
|
- Parameters:
|
||||||
- `--input=<file>`: Path to the PRD text file (default: sample-prd.txt)
|
- `--input=<file>`: Path to the PRD text file (default: sample-prd.txt)
|
||||||
- Example: `task-master parse-prd --input=requirements.txt`
|
- Example: `task-master parse-prd --input=requirements.txt`
|
||||||
- Notes: Will overwrite existing tasks.json file. Use with caution.
|
- Notes: Will overwrite existing tasks.json file. Use with caution.
|
||||||
|
|
||||||
- **Command Reference: update**
|
- **Command Reference: update**
|
||||||
- Legacy Syntax: `node scripts/dev.js update --from=<id> --prompt="<prompt>"`
|
|
||||||
- CLI Syntax: `task-master update --from=<id> --prompt="<prompt>"`
|
- CLI Syntax: `task-master update --from=<id> --prompt="<prompt>"`
|
||||||
- Description: Updates tasks with ID >= specified ID based on the provided prompt
|
- Description: Updates tasks with ID >= specified ID based on the provided prompt
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -98,7 +97,6 @@ alwaysApply: true
|
|||||||
- Notes: Only updates tasks not marked as 'done'. Completed tasks remain unchanged.
|
- Notes: Only updates tasks not marked as 'done'. Completed tasks remain unchanged.
|
||||||
|
|
||||||
- **Command Reference: update-task**
|
- **Command Reference: update-task**
|
||||||
- Legacy Syntax: `node scripts/dev.js update-task --id=<id> --prompt="<prompt>"`
|
|
||||||
- CLI Syntax: `task-master update-task --id=<id> --prompt="<prompt>"`
|
- CLI Syntax: `task-master update-task --id=<id> --prompt="<prompt>"`
|
||||||
- Description: Updates a single task by ID with new information
|
- Description: Updates a single task by ID with new information
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -109,7 +107,6 @@ alwaysApply: true
|
|||||||
- Notes: Only updates tasks not marked as 'done'. Preserves completed subtasks.
|
- Notes: Only updates tasks not marked as 'done'. Preserves completed subtasks.
|
||||||
|
|
||||||
- **Command Reference: update-subtask**
|
- **Command Reference: update-subtask**
|
||||||
- Legacy Syntax: `node scripts/dev.js update-subtask --id=<id> --prompt="<prompt>"`
|
|
||||||
- CLI Syntax: `task-master update-subtask --id=<id> --prompt="<prompt>"`
|
- CLI Syntax: `task-master update-subtask --id=<id> --prompt="<prompt>"`
|
||||||
- Description: Appends additional information to a specific subtask without replacing existing content
|
- Description: Appends additional information to a specific subtask without replacing existing content
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -124,7 +121,6 @@ alwaysApply: true
|
|||||||
- Will not update subtasks marked as 'done' or 'completed'
|
- Will not update subtasks marked as 'done' or 'completed'
|
||||||
|
|
||||||
- **Command Reference: generate**
|
- **Command Reference: generate**
|
||||||
- Legacy Syntax: `node scripts/dev.js generate`
|
|
||||||
- CLI Syntax: `task-master generate`
|
- CLI Syntax: `task-master generate`
|
||||||
- Description: Generates individual task files in tasks/ directory based on tasks.json
|
- Description: Generates individual task files in tasks/ directory based on tasks.json
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -134,7 +130,6 @@ alwaysApply: true
|
|||||||
- Notes: Overwrites existing task files. Creates tasks/ directory if needed.
|
- Notes: Overwrites existing task files. Creates tasks/ directory if needed.
|
||||||
|
|
||||||
- **Command Reference: set-status**
|
- **Command Reference: set-status**
|
||||||
- Legacy Syntax: `node scripts/dev.js set-status --id=<id> --status=<status>`
|
|
||||||
- CLI Syntax: `task-master set-status --id=<id> --status=<status>`
|
- CLI Syntax: `task-master set-status --id=<id> --status=<status>`
|
||||||
- Description: Updates the status of a specific task in tasks.json
|
- Description: Updates the status of a specific task in tasks.json
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -144,7 +139,6 @@ alwaysApply: true
|
|||||||
- Notes: Common values are 'done', 'pending', and 'deferred', but any string is accepted.
|
- Notes: Common values are 'done', 'pending', and 'deferred', but any string is accepted.
|
||||||
|
|
||||||
- **Command Reference: list**
|
- **Command Reference: list**
|
||||||
- Legacy Syntax: `node scripts/dev.js list`
|
|
||||||
- CLI Syntax: `task-master list`
|
- CLI Syntax: `task-master list`
|
||||||
- Description: Lists all tasks in tasks.json with IDs, titles, and status
|
- Description: Lists all tasks in tasks.json with IDs, titles, and status
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -155,7 +149,6 @@ alwaysApply: true
|
|||||||
- Notes: Provides quick overview of project progress. Use at start of sessions.
|
- Notes: Provides quick overview of project progress. Use at start of sessions.
|
||||||
|
|
||||||
- **Command Reference: expand**
|
- **Command Reference: expand**
|
||||||
- Legacy Syntax: `node scripts/dev.js expand --id=<id> [--num=<number>] [--research] [--prompt="<context>"]`
|
|
||||||
- CLI Syntax: `task-master expand --id=<id> [--num=<number>] [--research] [--prompt="<context>"]`
|
- CLI Syntax: `task-master expand --id=<id> [--num=<number>] [--research] [--prompt="<context>"]`
|
||||||
- Description: Expands a task with subtasks for detailed implementation
|
- Description: Expands a task with subtasks for detailed implementation
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -169,7 +162,6 @@ alwaysApply: true
|
|||||||
- Notes: Uses complexity report recommendations if available.
|
- Notes: Uses complexity report recommendations if available.
|
||||||
|
|
||||||
- **Command Reference: analyze-complexity**
|
- **Command Reference: analyze-complexity**
|
||||||
- Legacy Syntax: `node scripts/dev.js analyze-complexity [options]`
|
|
||||||
- CLI Syntax: `task-master analyze-complexity [options]`
|
- CLI Syntax: `task-master analyze-complexity [options]`
|
||||||
- Description: Analyzes task complexity and generates expansion recommendations
|
- Description: Analyzes task complexity and generates expansion recommendations
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -182,7 +174,6 @@ alwaysApply: true
|
|||||||
- Notes: Report includes complexity scores, recommended subtasks, and tailored prompts.
|
- Notes: Report includes complexity scores, recommended subtasks, and tailored prompts.
|
||||||
|
|
||||||
- **Command Reference: clear-subtasks**
|
- **Command Reference: clear-subtasks**
|
||||||
- Legacy Syntax: `node scripts/dev.js clear-subtasks --id=<id>`
|
|
||||||
- CLI Syntax: `task-master clear-subtasks --id=<id>`
|
- CLI Syntax: `task-master clear-subtasks --id=<id>`
|
||||||
- Description: Removes subtasks from specified tasks to allow regeneration
|
- Description: Removes subtasks from specified tasks to allow regeneration
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -256,7 +247,6 @@ alwaysApply: true
|
|||||||
- Dependencies are visualized with status indicators in task listings and files
|
- Dependencies are visualized with status indicators in task listings and files
|
||||||
|
|
||||||
- **Command Reference: add-dependency**
|
- **Command Reference: add-dependency**
|
||||||
- Legacy Syntax: `node scripts/dev.js add-dependency --id=<id> --depends-on=<id>`
|
|
||||||
- CLI Syntax: `task-master add-dependency --id=<id> --depends-on=<id>`
|
- CLI Syntax: `task-master add-dependency --id=<id> --depends-on=<id>`
|
||||||
- Description: Adds a dependency relationship between two tasks
|
- Description: Adds a dependency relationship between two tasks
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -266,7 +256,6 @@ alwaysApply: true
|
|||||||
- Notes: Prevents circular dependencies and duplicates; updates task files automatically
|
- Notes: Prevents circular dependencies and duplicates; updates task files automatically
|
||||||
|
|
||||||
- **Command Reference: remove-dependency**
|
- **Command Reference: remove-dependency**
|
||||||
- Legacy Syntax: `node scripts/dev.js remove-dependency --id=<id> --depends-on=<id>`
|
|
||||||
- CLI Syntax: `task-master remove-dependency --id=<id> --depends-on=<id>`
|
- CLI Syntax: `task-master remove-dependency --id=<id> --depends-on=<id>`
|
||||||
- Description: Removes a dependency relationship between two tasks
|
- Description: Removes a dependency relationship between two tasks
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -276,7 +265,6 @@ alwaysApply: true
|
|||||||
- Notes: Checks if dependency actually exists; updates task files automatically
|
- Notes: Checks if dependency actually exists; updates task files automatically
|
||||||
|
|
||||||
- **Command Reference: validate-dependencies**
|
- **Command Reference: validate-dependencies**
|
||||||
- Legacy Syntax: `node scripts/dev.js validate-dependencies [options]`
|
|
||||||
- CLI Syntax: `task-master validate-dependencies [options]`
|
- CLI Syntax: `task-master validate-dependencies [options]`
|
||||||
- Description: Checks for and identifies invalid dependencies in tasks.json and task files
|
- Description: Checks for and identifies invalid dependencies in tasks.json and task files
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -288,7 +276,6 @@ alwaysApply: true
|
|||||||
- Use before fix-dependencies to audit your task structure
|
- Use before fix-dependencies to audit your task structure
|
||||||
|
|
||||||
- **Command Reference: fix-dependencies**
|
- **Command Reference: fix-dependencies**
|
||||||
- Legacy Syntax: `node scripts/dev.js fix-dependencies [options]`
|
|
||||||
- CLI Syntax: `task-master fix-dependencies [options]`
|
- CLI Syntax: `task-master fix-dependencies [options]`
|
||||||
- Description: Finds and fixes all invalid dependencies in tasks.json and task files
|
- Description: Finds and fixes all invalid dependencies in tasks.json and task files
|
||||||
- Parameters:
|
- Parameters:
|
||||||
@@ -301,7 +288,6 @@ alwaysApply: true
|
|||||||
- Provides detailed report of all fixes made
|
- Provides detailed report of all fixes made
|
||||||
|
|
||||||
- **Command Reference: complexity-report**
|
- **Command Reference: complexity-report**
|
||||||
- Legacy Syntax: `node scripts/dev.js complexity-report [options]`
|
|
||||||
- CLI Syntax: `task-master complexity-report [options]`
|
- CLI Syntax: `task-master complexity-report [options]`
|
||||||
- Description: Displays the task complexity analysis report in a formatted, easy-to-read way
|
- Description: Displays the task complexity analysis report in a formatted, easy-to-read way
|
||||||
- Parameters:
|
- Parameters:
|
||||||
|
|||||||
87
.cursor/rules/mcp.mdc
Normal file
87
.cursor/rules/mcp.mdc
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
description: Guidelines for implementing and interacting with the Task Master MCP Server
|
||||||
|
globs: mcp-server/src/**/*, scripts/modules/**/*
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# Task Master MCP Server Guidelines
|
||||||
|
|
||||||
|
This document outlines the architecture and implementation patterns for the Task Master Model Context Protocol (MCP) server, designed for integration with tools like Cursor.
|
||||||
|
|
||||||
|
## Architecture Overview (See also: [`architecture.mdc`](mdc:.cursor/rules/architecture.mdc))
|
||||||
|
|
||||||
|
The MCP server acts as a bridge between external tools (like Cursor) and the core Task Master CLI logic. It leverages FastMCP for the server framework.
|
||||||
|
|
||||||
|
- **Flow**: `External Tool (Cursor)` <-> `FastMCP Server` <-> `MCP Tools` (`mcp-server/src/tools/*.js`) <-> `Core Logic Wrappers` (`mcp-server/src/core/task-master-core.js`) <-> `Core Modules` (`scripts/modules/*.js`)
|
||||||
|
- **Goal**: Provide a performant and reliable way for external tools to interact with Task Master functionality without directly invoking the CLI for every operation.
|
||||||
|
|
||||||
|
## Key Principles
|
||||||
|
|
||||||
|
- **Prefer Direct Function Calls**: For optimal performance and error handling, MCP tools should utilize direct function wrappers defined in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js). These wrappers call the underlying logic from the core modules (e.g., [`task-manager.js`](mdc:scripts/modules/task-manager.js)).
|
||||||
|
- **Use `executeMCPToolAction`**: This utility function in [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js) is the standard wrapper for executing the main logic within an MCP tool's `execute` function. It handles common boilerplate like logging, argument processing, calling the core action (`*Direct` function), and formatting the response.
|
||||||
|
- **CLI Execution as Fallback**: The `executeTaskMasterCommand` utility in [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js) allows executing commands via the CLI (`task-master ...`). This should **only** be used as a fallback if a direct function wrapper is not yet implemented or if a specific command intrinsically requires CLI execution.
|
||||||
|
- **Centralized Utilities** (See also: [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc)):
|
||||||
|
- Use `findTasksJsonPath` (in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js)) within direct function wrappers to locate the `tasks.json` file consistently.
|
||||||
|
- **Leverage MCP Utilities**: The file [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js) contains essential helpers for MCP tool implementation:
|
||||||
|
- `getProjectRoot`: Normalizes project paths (used internally by other utils).
|
||||||
|
- `handleApiResult`: Standardizes handling results from direct function calls (success/error).
|
||||||
|
- `createContentResponse`/`createErrorResponse`: Formats successful/error MCP responses.
|
||||||
|
- `processMCPResponseData`: Filters/cleans data for MCP responses (e.g., removing `details`, `testStrategy`). This is the default processor used by `executeMCPToolAction`.
|
||||||
|
- `executeMCPToolAction`: The primary wrapper function for tool execution logic.
|
||||||
|
- `executeTaskMasterCommand`: Fallback for executing CLI commands.
|
||||||
|
- **Caching**: To improve performance for frequently called read operations (like `listTasks`), a caching layer using `lru-cache` is implemented.
|
||||||
|
- Caching logic should be added *inside* the direct function wrappers in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js) using the `getCachedOrExecute` utility from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js).
|
||||||
|
- Generate unique cache keys based on function arguments that define a distinct call.
|
||||||
|
- Responses will include a `fromCache` flag.
|
||||||
|
- Cache statistics can be monitored using the `cacheStats` MCP tool (implemented via `getCacheStatsDirect`).
|
||||||
|
|
||||||
|
## Implementing MCP Support for a Command
|
||||||
|
|
||||||
|
Follow these steps to add MCP support for an existing Task Master command (see [`new_features.mdc`](mdc:.cursor/rules/new_features.mdc) for more detail):
|
||||||
|
|
||||||
|
1. **Ensure Core Logic Exists**: Verify the core functionality is implemented and exported from the relevant module in `scripts/modules/`.
|
||||||
|
2. **Create Direct Wrapper**: In [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js):
|
||||||
|
- Import the core function.
|
||||||
|
- Import `getCachedOrExecute` from `../tools/utils.js`.
|
||||||
|
- Create an `async function yourCommandDirect(args, log)` wrapper.
|
||||||
|
- Inside the wrapper:
|
||||||
|
- Determine arguments needed for both the core logic and the cache key (e.g., `tasksPath`, filters). Use `findTasksJsonPath(args, log)` if needed.
|
||||||
|
- **Generate a unique `cacheKey`** based on the arguments that define a distinct operation (e.g., `\`yourCommand:${tasksPath}:${filter}\``).
|
||||||
|
- **Define the `coreActionFn`**: An `async` function that contains the actual call to the imported core logic function, handling its specific errors and returning `{ success: true/false, data/error }`.
|
||||||
|
- **Call `getCachedOrExecute`**:
|
||||||
|
```javascript
|
||||||
|
const result = await getCachedOrExecute({
|
||||||
|
cacheKey,
|
||||||
|
actionFn: coreActionFn, // The function wrapping the core logic call
|
||||||
|
log
|
||||||
|
});
|
||||||
|
return result; // Returns { success, data/error, fromCache }
|
||||||
|
```
|
||||||
|
- Export the wrapper function and add it to the `directFunctions` map.
|
||||||
|
3. **Create MCP Tool**: In `mcp-server/src/tools/`:
|
||||||
|
- Create a new file (e.g., `yourCommand.js`).
|
||||||
|
- Import `z` for parameter schema definition.
|
||||||
|
- Import `executeMCPToolAction` from [`./utils.js`](mdc:mcp-server/src/tools/utils.js).
|
||||||
|
- Import the `yourCommandDirect` wrapper function from `../core/task-master-core.js`.
|
||||||
|
- Implement `registerYourCommandTool(server)`:
|
||||||
|
- Call `server.addTool`.
|
||||||
|
- Define `name`, `description`, and `parameters` using `zod`. Include `projectRoot` and `file` as optional parameters if relevant.
|
||||||
|
- Define the `async execute(args, log)` function.
|
||||||
|
- Inside `execute`, call `executeMCPToolAction`:
|
||||||
|
```javascript
|
||||||
|
return executeMCPToolAction({
|
||||||
|
actionFn: yourCommandDirect, // The direct function wrapper
|
||||||
|
args, // Arguments from the tool call
|
||||||
|
log, // MCP logger instance
|
||||||
|
actionName: 'Your Command Description', // For logging
|
||||||
|
// processResult: customProcessor // Optional: if default filtering isn't enough
|
||||||
|
});
|
||||||
|
```
|
||||||
|
4. **Register Tool**: Import and call `registerYourCommandTool` in [`mcp-server/src/tools/index.js`](mdc:mcp-server/src/tools/index.js).
|
||||||
|
5. **Update `mcp.json`**: Add the new tool definition to the `tools` array in `.cursor/mcp.json`.
|
||||||
|
|
||||||
|
## Handling Responses
|
||||||
|
|
||||||
|
- MCP tools should return data formatted by `createContentResponse` (which stringifies objects) or `createErrorResponse`.
|
||||||
|
- The `processMCPResponseData` utility automatically removes potentially large fields like `details` and `testStrategy` from task objects before they are returned. This is the default behavior when using `executeMCPToolAction`. If specific fields need to be preserved or different fields removed, a custom `processResult` function can be passed to `executeMCPToolAction`.
|
||||||
|
- The `handleApiResult` utility (used by `executeMCPToolAction`) now expects the result object from the direct function wrapper to include a `fromCache` boolean flag. This flag is included in the final JSON response sent to the MCP client, nested alongside the actual data (e.g., `{ "fromCache": true, "data": { ... } }`).
|
||||||
@@ -8,14 +8,14 @@ alwaysApply: false
|
|||||||
|
|
||||||
## Feature Placement Decision Process
|
## Feature Placement Decision Process
|
||||||
|
|
||||||
- **Identify Feature Type**:
|
- **Identify Feature Type** (See [`architecture.mdc`](mdc:.cursor/rules/architecture.mdc) for module details):
|
||||||
- **Data Manipulation**: Features that create, read, update, or delete tasks belong in [`task-manager.js`](mdc:scripts/modules/task-manager.js)
|
- **Data Manipulation**: Features that create, read, update, or delete tasks belong in [`task-manager.js`](mdc:scripts/modules/task-manager.js). Follow guidelines in [`tasks.mdc`](mdc:.cursor/rules/tasks.mdc).
|
||||||
- **Dependency Management**: Features that handle task relationships belong in [`dependency-manager.js`](mdc:scripts/modules/dependency-manager.js)
|
- **Dependency Management**: Features that handle task relationships belong in [`dependency-manager.js`](mdc:scripts/modules/dependency-manager.js). Follow guidelines in [`dependencies.mdc`](mdc:.cursor/rules/dependencies.mdc).
|
||||||
- **User Interface**: Features that display information to users belong in [`ui.js`](mdc:scripts/modules/ui.js)
|
- **User Interface**: Features that display information to users belong in [`ui.js`](mdc:scripts/modules/ui.js). Follow guidelines in [`ui.mdc`](mdc:.cursor/rules/ui.mdc).
|
||||||
- **AI Integration**: Features that use AI models belong in [`ai-services.js`](mdc:scripts/modules/ai-services.js)
|
- **AI Integration**: Features that use AI models belong in [`ai-services.js`](mdc:scripts/modules/ai-services.js).
|
||||||
- **Cross-Cutting**: Features that don't fit one category may need components in multiple modules
|
- **Cross-Cutting**: Features that don't fit one category may need components in multiple modules
|
||||||
|
|
||||||
- **Command-Line Interface**:
|
- **Command-Line Interface** (See [`commands.mdc`](mdc:.cursor/rules/commands.mdc)):
|
||||||
- All new user-facing commands should be added to [`commands.js`](mdc:scripts/modules/commands.js)
|
- All new user-facing commands should be added to [`commands.js`](mdc:scripts/modules/commands.js)
|
||||||
- Use consistent patterns for option naming and help text
|
- Use consistent patterns for option naming and help text
|
||||||
- Follow the Commander.js model for subcommand structure
|
- Follow the Commander.js model for subcommand structure
|
||||||
@@ -24,11 +24,11 @@ alwaysApply: false
|
|||||||
|
|
||||||
The standard pattern for adding a feature follows this workflow:
|
The standard pattern for adding a feature follows this workflow:
|
||||||
|
|
||||||
1. **Core Logic**: Implement the business logic in the appropriate module
|
1. **Core Logic**: Implement the business logic in the appropriate module (e.g., [`task-manager.js`](mdc:scripts/modules/task-manager.js)).
|
||||||
2. **UI Components**: Add any display functions to [`ui.js`](mdc:scripts/modules/ui.js)
|
2. **UI Components**: Add any display functions to [`ui.js`](mdc:scripts/modules/ui.js) following [`ui.mdc`](mdc:.cursor/rules/ui.mdc).
|
||||||
3. **Command Integration**: Add the CLI command to [`commands.js`](mdc:scripts/modules/commands.js)
|
3. **Command Integration**: Add the CLI command to [`commands.js`](mdc:scripts/modules/commands.js) following [`commands.mdc`](mdc:.cursor/rules/commands.mdc).
|
||||||
4. **Testing**: Write tests for all components of the feature (following [`tests.mdc`](mdc:.cursor/rules/tests.mdc))
|
4. **Testing**: Write tests for all components of the feature (following [`tests.mdc`](mdc:.cursor/rules/tests.mdc))
|
||||||
5. **Configuration**: Update any configuration in [`utils.js`](mdc:scripts/modules/utils.js) if needed
|
5. **Configuration**: Update any configuration in [`utils.js`](mdc:scripts/modules/utils.js) if needed, following [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc).
|
||||||
6. **Documentation**: Update help text and documentation in [dev_workflow.mdc](mdc:scripts/modules/dev_workflow.mdc)
|
6. **Documentation**: Update help text and documentation in [dev_workflow.mdc](mdc:scripts/modules/dev_workflow.mdc)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -294,7 +294,7 @@ For each new feature:
|
|||||||
|
|
||||||
1. Add help text to the command definition
|
1. Add help text to the command definition
|
||||||
2. Update [`dev_workflow.mdc`](mdc:scripts/modules/dev_workflow.mdc) with command reference
|
2. Update [`dev_workflow.mdc`](mdc:scripts/modules/dev_workflow.mdc) with command reference
|
||||||
3. Add examples to the appropriate sections in [`MODULE_PLAN.md`](mdc:scripts/modules/MODULE_PLAN.md)
|
3. Consider updating [`architecture.mdc`](mdc:.cursor/rules/architecture.mdc) if the feature significantly changes module responsibilities.
|
||||||
|
|
||||||
Follow the existing command reference format:
|
Follow the existing command reference format:
|
||||||
```markdown
|
```markdown
|
||||||
@@ -309,3 +309,51 @@ Follow the existing command reference format:
|
|||||||
```
|
```
|
||||||
|
|
||||||
For more information on module structure, see [`MODULE_PLAN.md`](mdc:scripts/modules/MODULE_PLAN.md) and follow [`self_improve.mdc`](mdc:scripts/modules/self_improve.mdc) for best practices on updating documentation.
|
For more information on module structure, see [`MODULE_PLAN.md`](mdc:scripts/modules/MODULE_PLAN.md) and follow [`self_improve.mdc`](mdc:scripts/modules/self_improve.mdc) for best practices on updating documentation.
|
||||||
|
|
||||||
|
## Adding MCP Server Support for Commands
|
||||||
|
|
||||||
|
Integrating Task Master commands with the MCP server (for use by tools like Cursor) follows a specific pattern distinct from the CLI command implementation.
|
||||||
|
|
||||||
|
- **Goal**: Leverage direct function calls for performance and reliability, avoiding CLI overhead.
|
||||||
|
- **Reference**: See [`mcp.mdc`](mdc:.cursor/rules/mcp.mdc) for full details.
|
||||||
|
|
||||||
|
**MCP Integration Workflow**:
|
||||||
|
|
||||||
|
1. **Core Logic**: Ensure the command's core logic exists in the appropriate module (e.g., [`task-manager.js`](mdc:scripts/modules/task-manager.js)).
|
||||||
|
2. **Direct Function Wrapper**:
|
||||||
|
- In [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js), create an `async function yourCommandDirect(args, log)`.
|
||||||
|
- This function imports and calls the core logic.
|
||||||
|
- It uses utilities like `findTasksJsonPath` if needed.
|
||||||
|
- It handles argument parsing and validation specific to the direct call.
|
||||||
|
- **Implement Caching (if applicable)**: For read operations that benefit from caching, use the `getCachedOrExecute` utility here to wrap the core logic call. Generate a unique cache key based on relevant arguments.
|
||||||
|
- It returns a standard `{ success: true/false, data/error, fromCache: boolean }` object.
|
||||||
|
- Export the function and add it to the `directFunctions` map.
|
||||||
|
3. **MCP Tool File**:
|
||||||
|
- Create a new file in `mcp-server/src/tools/` (e.g., `yourCommand.js`).
|
||||||
|
- Import `zod`, `executeMCPToolAction` from `./utils.js`, and your `yourCommandDirect` function.
|
||||||
|
- Implement `registerYourCommandTool(server)` which calls `server.addTool`:
|
||||||
|
- Define the tool `name`, `description`, and `parameters` using `zod`. Include optional `projectRoot` and `file` if relevant, following patterns in existing tools.
|
||||||
|
- Define the `async execute(args, log)` method for the tool.
|
||||||
|
- **Crucially**, the `execute` method should primarily call `executeMCPToolAction`:
|
||||||
|
```javascript
|
||||||
|
// In mcp-server/src/tools/yourCommand.js
|
||||||
|
import { executeMCPToolAction } from "./utils.js";
|
||||||
|
import { yourCommandDirect } from "../core/task-master-core.js";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export function registerYourCommandTool(server) {
|
||||||
|
server.addTool({
|
||||||
|
name: "yourCommand",
|
||||||
|
description: "Description of your command.",
|
||||||
|
parameters: z.object({ /* zod schema */ }),
|
||||||
|
async execute(args, log) {
|
||||||
|
return executeMCPToolAction({
|
||||||
|
actionFn: yourCommandDirect, // Pass the direct function wrapper
|
||||||
|
args, log, actionName: "Your Command Description"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
4. **Register in Tool Index**: Import and call `registerYourCommandTool` in [`mcp-server/src/tools/index.js`](mdc:mcp-server/src/tools/index.js).
|
||||||
|
5. **Update `mcp.json`**: Add the tool definition to `.cursor/mcp.json`.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ globs: "**/*.test.js,tests/**/*"
|
|||||||
|
|
||||||
## Test Organization Structure
|
## Test Organization Structure
|
||||||
|
|
||||||
- **Unit Tests**
|
- **Unit Tests** (See [`architecture.mdc`](mdc:.cursor/rules/architecture.mdc) for module breakdown)
|
||||||
- Located in `tests/unit/`
|
- Located in `tests/unit/`
|
||||||
- Test individual functions and utilities in isolation
|
- Test individual functions and utilities in isolation
|
||||||
- Mock all external dependencies
|
- Mock all external dependencies
|
||||||
@@ -324,7 +324,7 @@ When testing ES modules (`"type": "module"` in package.json), traditional mockin
|
|||||||
## Testing Common Components
|
## Testing Common Components
|
||||||
|
|
||||||
- **CLI Commands**
|
- **CLI Commands**
|
||||||
- Mock the action handlers and verify they're called with correct arguments
|
- Mock the action handlers (defined in [`commands.js`](mdc:scripts/modules/commands.js)) and verify they're called with correct arguments
|
||||||
- Test command registration and option parsing
|
- Test command registration and option parsing
|
||||||
- Use `commander` test utilities or custom mocks
|
- Use `commander` test utilities or custom mocks
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
description: Guidelines for implementing utility functions
|
description: Guidelines for implementing utility functions
|
||||||
globs: scripts/modules/utils.js
|
globs: scripts/modules/utils.js, mcp-server/src/**/*
|
||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -273,13 +273,81 @@ alwaysApply: false
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MCP Server Utilities (`mcp-server/src/tools/utils.js`)
|
||||||
|
|
||||||
|
- **Purpose**: These utilities specifically support the MCP server tools, handling communication patterns and data formatting for MCP clients. Refer to [`mcp.mdc`](mdc:.cursor/rules/mcp.mdc) for usage patterns.
|
||||||
|
|
||||||
|
-(See also: [`tests.mdc`](mdc:.cursor/rules/tests.mdc) for testing these utilities)
|
||||||
|
|
||||||
|
- **`getProjectRoot(projectRootRaw, log)`**:
|
||||||
|
- Normalizes a potentially relative project root path into an absolute path.
|
||||||
|
- Defaults to `process.cwd()` if `projectRootRaw` is not provided.
|
||||||
|
- Primarily used *internally* by `executeMCPToolAction` and `executeTaskMasterCommand`. Tools usually don't need to call this directly.
|
||||||
|
|
||||||
|
- **`executeMCPToolAction({ actionFn, args, log, actionName, processResult })`**:
|
||||||
|
- ✅ **DO**: Use this as the main wrapper inside an MCP tool's `execute` method when calling a direct function wrapper.
|
||||||
|
- Handles standard workflow: logs action start, normalizes `projectRoot`, calls the `actionFn` (e.g., `listTasksDirect`), processes the result (using `handleApiResult`), logs success/error, and returns a formatted MCP response (`createContentResponse`/`createErrorResponse`).
|
||||||
|
- Simplifies tool implementation significantly by handling boilerplate.
|
||||||
|
- Accepts an optional `processResult` function to customize data filtering/transformation before sending the response (defaults to `processMCPResponseData`).
|
||||||
|
|
||||||
|
- **`handleApiResult(result, log, errorPrefix, processFunction)`**:
|
||||||
|
- Takes the standard `{ success, data/error }` object returned by direct function wrappers (like `listTasksDirect`).
|
||||||
|
- Checks the `success` flag.
|
||||||
|
- If successful, processes the `data` using `processFunction` (defaults to `processMCPResponseData`).
|
||||||
|
- Returns a formatted MCP response object using `createContentResponse` or `createErrorResponse`.
|
||||||
|
- Typically called *internally* by `executeMCPToolAction`.
|
||||||
|
|
||||||
|
- **`executeTaskMasterCommand(command, log, args, projectRootRaw)`**:
|
||||||
|
- Executes a Task Master command using `child_process.spawnSync`.
|
||||||
|
- Tries the global `task-master` command first, then falls back to `node scripts/dev.js`.
|
||||||
|
- Handles project root normalization internally.
|
||||||
|
- Returns `{ success, stdout, stderr }` or `{ success: false, error }`.
|
||||||
|
- ❌ **DON'T**: Use this as the primary method for MCP tools. Prefer `executeMCPToolAction` with direct function calls. Use only as a fallback for commands not yet refactored or those requiring CLI execution.
|
||||||
|
|
||||||
|
- **`processMCPResponseData(taskOrData, fieldsToRemove = ['details', 'testStrategy'])`**:
|
||||||
|
- Filters task data before sending it to the MCP client.
|
||||||
|
- By default, removes the `details` and `testStrategy` fields from task objects and their subtasks to reduce payload size.
|
||||||
|
- Can handle single task objects or data structures containing a `tasks` array (like from `listTasks`).
|
||||||
|
- This is the default processor used by `executeMCPToolAction`.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example usage (typically done inside executeMCPToolAction):
|
||||||
|
const rawResult = { success: true, data: { tasks: [ { id: 1, title: '...', details: '...', subtasks: [...] } ] } };
|
||||||
|
const filteredData = processMCPResponseData(rawResult.data);
|
||||||
|
// filteredData.tasks[0] will NOT have the 'details' field.
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`createContentResponse(content)`**:
|
||||||
|
- ✅ **DO**: Use this (usually via `handleApiResult` or `executeMCPToolAction`) to format successful MCP responses.
|
||||||
|
- Wraps the `content` (stringifies objects to JSON) in the standard FastMCP `{ content: [{ type: "text", text: ... }] }` structure.
|
||||||
|
|
||||||
|
- **`createErrorResponse(errorMessage)`**:
|
||||||
|
- ✅ **DO**: Use this (usually via `handleApiResult` or `executeMCPToolAction`) to format error responses for MCP.
|
||||||
|
- Wraps the `errorMessage` in the standard FastMCP error structure, including `isError: true`.
|
||||||
|
|
||||||
|
- **`getCachedOrExecute({ cacheKey, actionFn, log })`**:
|
||||||
|
- ✅ **DO**: Use this utility *inside direct function wrappers* (like `listTasksDirect` in `task-master-core.js`) to implement caching for MCP operations.
|
||||||
|
- Checks the `ContextManager` cache using `cacheKey`.
|
||||||
|
- If a hit occurs, returns the cached result directly.
|
||||||
|
- If a miss occurs, it executes the provided `actionFn` (which should be an async function returning `{ success, data/error }`).
|
||||||
|
- If `actionFn` succeeds, its result is stored in the cache under `cacheKey`.
|
||||||
|
- Returns the result (either cached or fresh) wrapped in the standard structure `{ success, data/error, fromCache: boolean }`.
|
||||||
|
|
||||||
|
- **`executeMCPToolAction({ actionFn, args, log, actionName, processResult })`**:
|
||||||
|
- Update: While this function *can* technically coordinate caching if provided a `cacheKeyGenerator`, the current preferred pattern involves implementing caching *within* the `actionFn` (the direct wrapper) using `getCachedOrExecute`. `executeMCPToolAction` primarily orchestrates the call to `actionFn` and handles processing its result (including the `fromCache` flag) via `handleApiResult`.
|
||||||
|
|
||||||
|
- **`handleApiResult(result, log, errorPrefix, processFunction)`**:
|
||||||
|
- Update: Now expects the `result` object to potentially contain a `fromCache` boolean flag. If present, this flag is included in the final response payload generated by `createContentResponse` (e.g., `{ fromCache: true, data: ... }`).
|
||||||
|
|
||||||
## Export Organization
|
## Export Organization
|
||||||
|
|
||||||
- **Grouping Related Functions**:
|
- **Grouping Related Functions**:
|
||||||
- ✅ DO: Export all utility functions in a single statement
|
- ✅ DO: Keep utilities relevant to their location (e.g., core utils in `scripts/modules/utils.js`, MCP utils in `mcp-server/src/tools/utils.js`).
|
||||||
- ✅ DO: Group related exports together
|
- ✅ DO: Export all utility functions in a single statement per file.
|
||||||
- ✅ DO: Export configuration constants
|
- ✅ DO: Group related exports together.
|
||||||
- ❌ DON'T: Use default exports
|
- ✅ DO: Export configuration constants.
|
||||||
|
- ❌ DON'T: Use default exports.
|
||||||
|
- ❌ DON'T: Create circular dependencies between utility files or between utilities and the modules that use them (See [`architecture.mdc`](mdc:.cursor/rules/architecture.mdc)).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// ✅ DO: Organize exports logically
|
// ✅ DO: Organize exports logically
|
||||||
@@ -311,4 +379,4 @@ alwaysApply: false
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Refer to [`utils.js`](mdc:scripts/modules/utils.js) for implementation examples and [`new_features.mdc`](mdc:.cursor/rules/new_features.mdc) for integration guidelines.
|
Refer to [`utils.js`](mdc:scripts/modules/utils.js) for implementation examples and [`new_features.mdc`](mdc:.cursor/rules/new_features.mdc) for integration guidelines. Use [`commands.mdc`](mdc:.cursor/rules/commands.mdc) for CLI integration details.
|
||||||
2128
docs/mcp-protocol-schema-03262025.json
Normal file
2128
docs/mcp-protocol-schema-03262025.json
Normal file
File diff suppressed because it is too large
Load Diff
85
mcp-server/src/core/__tests__/context-manager.test.js
Normal file
85
mcp-server/src/core/__tests__/context-manager.test.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
170
mcp-server/src/core/context-manager.js
Normal file
170
mcp-server/src/core/context-manager.js
Normal 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();
|
||||||
167
mcp-server/src/core/task-master-core.js
Normal file
167
mcp-server/src/core/task-master-core.js
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
/**
|
||||||
|
* task-master-core.js
|
||||||
|
* Direct function imports from Task Master modules
|
||||||
|
*
|
||||||
|
* This module provides direct access to Task Master core functions
|
||||||
|
* for improved performance and error handling compared to CLI execution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { dirname } from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
// Get the current module's directory
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
// Import Task Master modules
|
||||||
|
import {
|
||||||
|
listTasks,
|
||||||
|
// 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'.
|
||||||
|
* @param {Object} log - Logger object.
|
||||||
|
* @returns {string} - Absolute path to the tasks.json file.
|
||||||
|
* @throws {Error} - If tasks.json cannot be found.
|
||||||
|
*/
|
||||||
|
function findTasksJsonPath(args, log) {
|
||||||
|
// Assume projectRoot is already normalized absolute path if passed in args
|
||||||
|
// Or use getProjectRoot if we decide to centralize that logic
|
||||||
|
const projectRoot = args.projectRoot || process.cwd();
|
||||||
|
log.info(`Searching for tasks.json within project root: ${projectRoot}`);
|
||||||
|
|
||||||
|
const possiblePaths = [];
|
||||||
|
|
||||||
|
// 1. If a file is explicitly provided relative to projectRoot
|
||||||
|
if (args.file) {
|
||||||
|
possiblePaths.push(path.resolve(projectRoot, args.file));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check the standard locations relative to projectRoot
|
||||||
|
possiblePaths.push(
|
||||||
|
path.join(projectRoot, 'tasks.json'),
|
||||||
|
path.join(projectRoot, 'tasks', 'tasks.json')
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info(`Checking potential task file paths: ${possiblePaths.join(', ')}`);
|
||||||
|
|
||||||
|
// Find the first existing path
|
||||||
|
for (const p of possiblePaths) {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
log.info(`Found tasks file at: ${p}`);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no file was found, throw an error
|
||||||
|
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 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 {
|
||||||
|
// 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.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: stats
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
log.error(`Error getting cache stats: ${error.message}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: {
|
||||||
|
code: 'CACHE_STATS_ERROR',
|
||||||
|
message: error.message || 'Unknown error occurred'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps Task Master functions to their direct implementation
|
||||||
|
*/
|
||||||
|
export const directFunctions = {
|
||||||
|
list: listTasksDirect,
|
||||||
|
cacheStats: getCacheStatsDirect,
|
||||||
|
// Add more functions as we implement them
|
||||||
|
};
|
||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import {
|
||||||
executeTaskMasterCommand,
|
|
||||||
createContentResponse,
|
|
||||||
createErrorResponse,
|
createErrorResponse,
|
||||||
|
handleApiResult
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
|
import { listTasksDirect } from "../core/task-master-core.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the listTasks tool with the MCP server
|
* Register the listTasks tool with the MCP server
|
||||||
@@ -27,6 +27,7 @@ export function registerListTasksTool(server) {
|
|||||||
file: z.string().optional().describe("Path to the tasks file"),
|
file: z.string().optional().describe("Path to the tasks file"),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
"Root directory of the project (default: current working directory)"
|
"Root directory of the project (default: current working directory)"
|
||||||
),
|
),
|
||||||
@@ -34,32 +35,19 @@ export function registerListTasksTool(server) {
|
|||||||
execute: async (args, { log }) => {
|
execute: async (args, { log }) => {
|
||||||
try {
|
try {
|
||||||
log.info(`Listing tasks with filters: ${JSON.stringify(args)}`);
|
log.info(`Listing tasks with filters: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
const cmdArgs = [];
|
// Call core function - args contains projectRoot which is handled internally
|
||||||
if (args.status) cmdArgs.push(`--status=${args.status}`);
|
const result = await listTasksDirect(args, log);
|
||||||
if (args.withSubtasks) cmdArgs.push("--with-subtasks");
|
|
||||||
if (args.file) cmdArgs.push(`--file=${args.file}`);
|
// Log result and use handleApiResult utility
|
||||||
|
log.info(`Retrieved ${result.success ? (result.data?.tasks?.length || 0) : 0} tasks`);
|
||||||
const projectRoot = args.projectRoot;
|
return handleApiResult(result, log, 'Error listing tasks');
|
||||||
|
|
||||||
const result = executeTaskMasterCommand(
|
|
||||||
"list",
|
|
||||||
log,
|
|
||||||
cmdArgs,
|
|
||||||
projectRoot
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!result.success) {
|
|
||||||
throw new Error(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(`Listing tasks result: ${result.stdout}`, result.stdout);
|
|
||||||
|
|
||||||
return createContentResponse(result.stdout);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error listing tasks: ${error.message}`);
|
log.error(`Error listing tasks: ${error.message}`);
|
||||||
return createErrorResponse(`Error listing tasks: ${error.message}`);
|
return createErrorResponse(error.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We no longer need the formatTasksResponse function as we're returning raw JSON data
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import {
|
||||||
executeTaskMasterCommand,
|
executeTaskMasterCommand,
|
||||||
createContentResponse,
|
|
||||||
createErrorResponse,
|
createErrorResponse,
|
||||||
|
handleApiResult
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +23,7 @@ export function registerShowTaskTool(server) {
|
|||||||
file: z.string().optional().describe("Path to the tasks file"),
|
file: z.string().optional().describe("Path to the tasks file"),
|
||||||
projectRoot: z
|
projectRoot: z
|
||||||
.string()
|
.string()
|
||||||
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
"Root directory of the project (default: current working directory)"
|
"Root directory of the project (default: current working directory)"
|
||||||
),
|
),
|
||||||
@@ -31,26 +32,46 @@ export function registerShowTaskTool(server) {
|
|||||||
try {
|
try {
|
||||||
log.info(`Showing task details for ID: ${args.id}`);
|
log.info(`Showing task details for ID: ${args.id}`);
|
||||||
|
|
||||||
|
// Prepare arguments for CLI command
|
||||||
const cmdArgs = [`--id=${args.id}`];
|
const cmdArgs = [`--id=${args.id}`];
|
||||||
if (args.file) cmdArgs.push(`--file=${args.file}`);
|
if (args.file) cmdArgs.push(`--file=${args.file}`);
|
||||||
|
|
||||||
const projectRoot = args.projectRoot;
|
// Execute the command - function now handles project root internally
|
||||||
|
|
||||||
const result = executeTaskMasterCommand(
|
const result = executeTaskMasterCommand(
|
||||||
"show",
|
"show",
|
||||||
log,
|
log,
|
||||||
cmdArgs,
|
cmdArgs,
|
||||||
projectRoot
|
args.projectRoot // Pass raw project root, function will normalize it
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
// Process CLI result into API result format for handleApiResult
|
||||||
throw new Error(result.error);
|
if (result.success) {
|
||||||
|
try {
|
||||||
|
// Try to parse response as JSON
|
||||||
|
const data = JSON.parse(result.stdout);
|
||||||
|
// Return equivalent of a successful API call with data
|
||||||
|
return handleApiResult({ success: true, data }, log, 'Error showing task');
|
||||||
|
} catch (e) {
|
||||||
|
// If parsing fails, still return success but with raw string data
|
||||||
|
return handleApiResult(
|
||||||
|
{ success: true, data: result.stdout },
|
||||||
|
log,
|
||||||
|
'Error showing task',
|
||||||
|
// Skip data processing for string data
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Return equivalent of a failed API call
|
||||||
|
return handleApiResult(
|
||||||
|
{ success: false, error: { message: result.error } },
|
||||||
|
log,
|
||||||
|
'Error showing task'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createContentResponse(result.stdout);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error showing task: ${error.message}`);
|
log.error(`Error showing task: ${error.message}`);
|
||||||
return createErrorResponse(`Error showing task: ${error.message}`);
|
return createErrorResponse(error.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,22 +4,78 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { spawnSync } from "child_process";
|
import { spawnSync } from "child_process";
|
||||||
|
import path from "path";
|
||||||
|
import { contextManager } from '../core/context-manager.js'; // Import the singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get normalized project root path
|
||||||
|
* @param {string|undefined} projectRootRaw - Raw project root from arguments
|
||||||
|
* @param {Object} log - Logger object
|
||||||
|
* @returns {string} - Normalized absolute path to project root
|
||||||
|
*/
|
||||||
|
export function getProjectRoot(projectRootRaw, log) {
|
||||||
|
// Make sure projectRoot is set
|
||||||
|
const rootPath = projectRootRaw || process.cwd();
|
||||||
|
|
||||||
|
// Ensure projectRoot is absolute
|
||||||
|
const projectRoot = path.isAbsolute(rootPath)
|
||||||
|
? rootPath
|
||||||
|
: path.resolve(process.cwd(), rootPath);
|
||||||
|
|
||||||
|
log.info(`Using project root: ${projectRoot}`);
|
||||||
|
return projectRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle API result with standardized error handling and response formatting
|
||||||
|
* @param {Object} result - Result object from API call with success, data, and error properties
|
||||||
|
* @param {Object} log - Logger object
|
||||||
|
* @param {string} errorPrefix - Prefix for error messages
|
||||||
|
* @param {Function} processFunction - Optional function to process successful result data
|
||||||
|
* @returns {Object} - Standardized MCP response object
|
||||||
|
*/
|
||||||
|
export function handleApiResult(result, log, errorPrefix = 'API error', processFunction = processMCPResponseData) {
|
||||||
|
if (!result.success) {
|
||||||
|
const errorMsg = result.error?.message || `Unknown ${errorPrefix}`;
|
||||||
|
// 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
|
||||||
|
const processedData = processFunction ? processFunction(result.data) : result.data;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a Task Master CLI command using child_process
|
* Execute a Task Master CLI command using child_process
|
||||||
* @param {string} command - The command to execute
|
* @param {string} command - The command to execute
|
||||||
* @param {Object} log - The logger object from FastMCP
|
* @param {Object} log - The logger object from FastMCP
|
||||||
* @param {Array} args - Arguments for the command
|
* @param {Array} args - Arguments for the command
|
||||||
* @param {string} cwd - Working directory for command execution (defaults to current project root)
|
* @param {string|undefined} projectRootRaw - Optional raw project root path (will be normalized internally)
|
||||||
* @returns {Object} - The result of the command execution
|
* @returns {Object} - The result of the command execution
|
||||||
*/
|
*/
|
||||||
export function executeTaskMasterCommand(
|
export function executeTaskMasterCommand(
|
||||||
command,
|
command,
|
||||||
log,
|
log,
|
||||||
args = [],
|
args = [],
|
||||||
cwd = process.cwd()
|
projectRootRaw = null
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
// Normalize project root internally using the getProjectRoot utility
|
||||||
|
const cwd = getProjectRoot(projectRootRaw, log);
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`Executing task-master ${command} with args: ${JSON.stringify(
|
`Executing task-master ${command} with args: ${JSON.stringify(
|
||||||
args
|
args
|
||||||
@@ -76,33 +132,236 @@ export function executeTaskMasterCommand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates standard content response for tools
|
* Checks cache for a result using the provided key. If not found, executes the action function,
|
||||||
* @param {string} text - Text content to include in response
|
* caches the result upon success, and returns the result.
|
||||||
* @returns {Object} - Content response object
|
*
|
||||||
|
* @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 function createContentResponse(text) {
|
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 (e.g., listTasksDirect) to execute. Should return {success, data, error}.
|
||||||
|
* @param {Object} options.args - Arguments for the action, passed to actionFn and cacheKeyGenerator.
|
||||||
|
* @param {Object} options.log - Logger object from FastMCP.
|
||||||
|
* @param {string} options.actionName - Name of the action for logging purposes.
|
||||||
|
* @param {Function} [options.cacheKeyGenerator] - Optional function to generate a cache key based on args. If provided, caching is enabled.
|
||||||
|
* @param {Function} [options.processResult=processMCPResponseData] - Optional function to process the result data before returning.
|
||||||
|
* @returns {Promise<Object>} - Standardized response for FastMCP.
|
||||||
|
*/
|
||||||
|
export async function executeMCPToolAction({
|
||||||
|
actionFn,
|
||||||
|
args,
|
||||||
|
log,
|
||||||
|
actionName,
|
||||||
|
cacheKeyGenerator, // Note: We decided not to use this for listTasks for now
|
||||||
|
processResult = processMCPResponseData
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
// Log the action start
|
||||||
|
log.info(`${actionName} with args: ${JSON.stringify(args)}`);
|
||||||
|
|
||||||
|
// Normalize project root path - common to almost all tools
|
||||||
|
const projectRootRaw = args.projectRoot || process.cwd();
|
||||||
|
const projectRoot = path.isAbsolute(projectRootRaw)
|
||||||
|
? projectRootRaw
|
||||||
|
: path.resolve(process.cwd(), projectRootRaw);
|
||||||
|
|
||||||
|
log.info(`Using project root: ${projectRoot}`);
|
||||||
|
const executionArgs = { ...args, projectRoot };
|
||||||
|
|
||||||
|
let result;
|
||||||
|
const cacheKey = cacheKeyGenerator ? cacheKeyGenerator(executionArgs) : null;
|
||||||
|
|
||||||
|
if (cacheKey) {
|
||||||
|
// Use caching utility
|
||||||
|
log.info(`Caching enabled for ${actionName} with key: ${cacheKey}`);
|
||||||
|
const cacheWrappedAction = async () => await actionFn(executionArgs, log);
|
||||||
|
result = await getCachedOrExecute({
|
||||||
|
cacheKey,
|
||||||
|
actionFn: cacheWrappedAction,
|
||||||
|
log
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Execute directly without caching
|
||||||
|
log.info(`Caching disabled for ${actionName}. Executing directly.`);
|
||||||
|
// We need to ensure the result from actionFn has a fromCache field
|
||||||
|
// Let's assume actionFn now consistently returns { success, data/error, fromCache }
|
||||||
|
// The current listTasksDirect does this if it calls getCachedOrExecute internally.
|
||||||
|
result = await actionFn(executionArgs, log);
|
||||||
|
// If the action function itself doesn't determine caching (like our original listTasksDirect refactor attempt),
|
||||||
|
// we'd set it here:
|
||||||
|
// result.fromCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle error case
|
||||||
|
if (!result.success) {
|
||||||
|
const errorMsg = result.error?.message || `Unknown error during ${actionName.toLowerCase()}`;
|
||||||
|
// Include fromCache in error logs too, might be useful
|
||||||
|
log.error(`Error during ${actionName.toLowerCase()}: ${errorMsg}. From cache: ${result.fromCache}`);
|
||||||
|
return createErrorResponse(errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log success
|
||||||
|
log.info(`Successfully completed ${actionName.toLowerCase()}. From cache: ${result.fromCache}`);
|
||||||
|
|
||||||
|
// Process the result data if needed
|
||||||
|
const processedData = processResult ? processResult(result.data) : result.data;
|
||||||
|
|
||||||
|
// Create a new object that includes both the processed data and the fromCache flag
|
||||||
|
const responsePayload = {
|
||||||
|
fromCache: result.fromCache, // Include the flag here
|
||||||
|
data: processedData // Embed the actual data under a 'data' key
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pass this combined payload to createContentResponse
|
||||||
|
return createContentResponse(responsePayload);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
// Handle unexpected errors during the execution wrapper itself
|
||||||
|
log.error(`Unexpected error during ${actionName.toLowerCase()} execution wrapper: ${error.message}`);
|
||||||
|
console.error(error.stack); // Log stack for debugging wrapper errors
|
||||||
|
return createErrorResponse(`Internal server error during ${actionName.toLowerCase()}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively removes specified fields from task objects, whether single or in an array.
|
||||||
|
* Handles common data structures returned by task commands.
|
||||||
|
* @param {Object|Array} taskOrData - A single task object or a data object containing a 'tasks' array.
|
||||||
|
* @param {string[]} fieldsToRemove - An array of field names to remove.
|
||||||
|
* @returns {Object|Array} - The processed data with specified fields removed.
|
||||||
|
*/
|
||||||
|
export function processMCPResponseData(taskOrData, fieldsToRemove = ['details', 'testStrategy']) {
|
||||||
|
if (!taskOrData) {
|
||||||
|
return taskOrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to process a single task object
|
||||||
|
const processSingleTask = (task) => {
|
||||||
|
if (typeof task !== 'object' || task === null) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedTask = { ...task };
|
||||||
|
|
||||||
|
// Remove specified fields from the task
|
||||||
|
fieldsToRemove.forEach(field => {
|
||||||
|
delete processedTask[field];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Recursively process subtasks if they exist and are an array
|
||||||
|
if (processedTask.subtasks && Array.isArray(processedTask.subtasks)) {
|
||||||
|
// Use processArrayOfTasks to handle the subtasks array
|
||||||
|
processedTask.subtasks = processArrayOfTasks(processedTask.subtasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return processedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to process an array of tasks
|
||||||
|
const processArrayOfTasks = (tasks) => {
|
||||||
|
return tasks.map(processSingleTask);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the input is a data structure containing a 'tasks' array (like from listTasks)
|
||||||
|
if (typeof taskOrData === 'object' && taskOrData !== null && Array.isArray(taskOrData.tasks)) {
|
||||||
|
return {
|
||||||
|
...taskOrData, // Keep other potential fields like 'stats', 'filter'
|
||||||
|
tasks: processArrayOfTasks(taskOrData.tasks),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Check if the input is likely a single task object (add more checks if needed)
|
||||||
|
else if (typeof taskOrData === 'object' && taskOrData !== null && 'id' in taskOrData && 'title' in taskOrData) {
|
||||||
|
return processSingleTask(taskOrData);
|
||||||
|
}
|
||||||
|
// Check if the input is an array of tasks directly (less common but possible)
|
||||||
|
else if (Array.isArray(taskOrData)) {
|
||||||
|
return processArrayOfTasks(taskOrData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it doesn't match known task structures, return it as is
|
||||||
|
return taskOrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates standard content response for tools
|
||||||
|
* @param {string|Object} content - Content to include in response
|
||||||
|
* @returns {Object} - Content response object in FastMCP format
|
||||||
|
*/
|
||||||
|
export function createContentResponse(content) {
|
||||||
|
// FastMCP requires text type, so we format objects as JSON strings
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
text,
|
type: "text",
|
||||||
type: "text",
|
text: typeof content === 'object' ?
|
||||||
},
|
// Format JSON nicely with indentation
|
||||||
],
|
JSON.stringify(content, null, 2) :
|
||||||
|
// Keep other content types as-is
|
||||||
|
String(content)
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates error response for tools
|
* Creates error response for tools
|
||||||
* @param {string} errorMessage - Error message to include in response
|
* @param {string} errorMessage - Error message to include in response
|
||||||
* @returns {Object} - Error content response object
|
* @returns {Object} - Error content response object in FastMCP format
|
||||||
*/
|
*/
|
||||||
export function createErrorResponse(errorMessage) {
|
export function createErrorResponse(errorMessage) {
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
text: errorMessage,
|
|
||||||
type: "text",
|
type: "text",
|
||||||
},
|
text: `Error: ${errorMessage}`
|
||||||
|
}
|
||||||
],
|
],
|
||||||
|
isError: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
23
package-lock.json
generated
23
package-lock.json
generated
@@ -23,6 +23,7 @@
|
|||||||
"gradient-string": "^3.0.0",
|
"gradient-string": "^3.0.0",
|
||||||
"helmet": "^8.1.0",
|
"helmet": "^8.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"lru-cache": "^10.2.0",
|
||||||
"openai": "^4.89.0",
|
"openai": "^4.89.0",
|
||||||
"ora": "^8.2.0"
|
"ora": "^8.2.0"
|
||||||
},
|
},
|
||||||
@@ -163,6 +164,16 @@
|
|||||||
"node": ">=6.9.0"
|
"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": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.25.9",
|
"version": "7.25.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
|
||||||
@@ -5505,14 +5516,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "10.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
"dev": true,
|
"license": "ISC"
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"yallist": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/make-dir": {
|
"node_modules/make-dir": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/sdk": "^0.39.0",
|
"@anthropic-ai/sdk": "^0.39.0",
|
||||||
|
"@model-context-protocol/sdk": "^1.20.5",
|
||||||
"boxen": "^8.0.1",
|
"boxen": "^8.0.1",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"cli-table3": "^0.6.5",
|
"cli-table3": "^0.6.5",
|
||||||
@@ -46,12 +47,13 @@
|
|||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"fastmcp": "^1.20.5",
|
"fastmcp": "^1.20.5",
|
||||||
"figlet": "^1.8.0",
|
"figlet": "^1.8.0",
|
||||||
|
"fuse.js": "^7.0.0",
|
||||||
"gradient-string": "^3.0.0",
|
"gradient-string": "^3.0.0",
|
||||||
"helmet": "^8.1.0",
|
"helmet": "^8.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"lru-cache": "^10.2.0",
|
||||||
"openai": "^4.89.0",
|
"openai": "^4.89.0",
|
||||||
"ora": "^8.2.0",
|
"ora": "^8.2.0"
|
||||||
"fuse.js": "^7.0.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
|
|||||||
@@ -987,20 +987,26 @@ async function updateSingleTaskStatus(tasksPath, taskIdInput, newStatus, data) {
|
|||||||
* @param {string} tasksPath - Path to the tasks.json file
|
* @param {string} tasksPath - Path to the tasks.json file
|
||||||
* @param {string} statusFilter - Filter by status
|
* @param {string} statusFilter - Filter by status
|
||||||
* @param {boolean} withSubtasks - Whether to show subtasks
|
* @param {boolean} withSubtasks - Whether to show subtasks
|
||||||
|
* @param {string} outputFormat - Output format (text or json)
|
||||||
|
* @returns {Object} - Task list result for json format
|
||||||
*/
|
*/
|
||||||
function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat = 'text') {
|
||||||
try {
|
try {
|
||||||
displayBanner();
|
// Only display banner for text output
|
||||||
const data = readJSON(tasksPath);
|
if (outputFormat === 'text') {
|
||||||
|
displayBanner();
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = readJSON(tasksPath); // Reads the whole tasks.json
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter tasks by status if specified
|
// Filter tasks by status if specified
|
||||||
const filteredTasks = statusFilter
|
const filteredTasks = statusFilter && statusFilter.toLowerCase() !== 'all' // <-- Added check for 'all'
|
||||||
? data.tasks.filter(task =>
|
? data.tasks.filter(task =>
|
||||||
task.status && task.status.toLowerCase() === statusFilter.toLowerCase())
|
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
|
// Calculate completion statistics
|
||||||
const totalTasks = data.tasks.length;
|
const totalTasks = data.tasks.length;
|
||||||
@@ -1029,7 +1035,47 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
|
|
||||||
const subtaskCompletionPercentage = totalSubtasks > 0 ?
|
const subtaskCompletionPercentage = totalSubtasks > 0 ?
|
||||||
(completedSubtasks / totalSubtasks) * 100 : 0;
|
(completedSubtasks / totalSubtasks) * 100 : 0;
|
||||||
|
|
||||||
|
// For JSON output, return structured data
|
||||||
|
if (outputFormat === 'json') {
|
||||||
|
// *** Modification: Remove 'details' field for JSON output ***
|
||||||
|
const tasksWithoutDetails = filteredTasks.map(task => { // <-- USES filteredTasks!
|
||||||
|
// Omit 'details' from the parent task
|
||||||
|
const { details, ...taskRest } = task;
|
||||||
|
|
||||||
|
// If subtasks exist, omit 'details' from them too
|
||||||
|
if (taskRest.subtasks && Array.isArray(taskRest.subtasks)) {
|
||||||
|
taskRest.subtasks = taskRest.subtasks.map(subtask => {
|
||||||
|
const { details: subtaskDetails, ...subtaskRest } = subtask;
|
||||||
|
return subtaskRest;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return taskRest;
|
||||||
|
});
|
||||||
|
// *** End of Modification ***
|
||||||
|
|
||||||
|
return {
|
||||||
|
tasks: tasksWithoutDetails, // <--- THIS IS THE ARRAY BEING RETURNED
|
||||||
|
filter: statusFilter || 'all', // Return the actual filter used
|
||||||
|
stats: {
|
||||||
|
total: totalTasks,
|
||||||
|
completed: doneCount,
|
||||||
|
inProgress: inProgressCount,
|
||||||
|
pending: pendingCount,
|
||||||
|
blocked: blockedCount,
|
||||||
|
deferred: deferredCount,
|
||||||
|
completionPercentage,
|
||||||
|
subtasks: {
|
||||||
|
total: totalSubtasks,
|
||||||
|
completed: completedSubtasks,
|
||||||
|
completionPercentage: subtaskCompletionPercentage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... existing code for text output ...
|
||||||
|
|
||||||
// Create progress bars
|
// Create progress bars
|
||||||
const taskProgressBar = createProgressBar(completionPercentage, 30);
|
const taskProgressBar = createProgressBar(completionPercentage, 30);
|
||||||
const subtaskProgressBar = createProgressBar(subtaskCompletionPercentage, 30);
|
const subtaskProgressBar = createProgressBar(subtaskCompletionPercentage, 30);
|
||||||
@@ -1460,12 +1506,17 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false) {
|
|||||||
));
|
));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('error', `Error listing tasks: ${error.message}`);
|
log('error', `Error listing tasks: ${error.message}`);
|
||||||
console.error(chalk.red(`Error: ${error.message}`));
|
|
||||||
|
|
||||||
if (CONFIG.debug) {
|
if (outputFormat === 'json') {
|
||||||
console.error(error);
|
// Return structured error for JSON output
|
||||||
|
throw {
|
||||||
|
code: 'TASK_LIST_ERROR',
|
||||||
|
message: error.message,
|
||||||
|
details: error.stack
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.error(chalk.red(`Error: ${error.message}`));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ Testing approach:
|
|||||||
- Validate compatibility with existing MCP clients.
|
- Validate compatibility with existing MCP clients.
|
||||||
- Benchmark performance improvements from SDK integration.
|
- 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
|
### 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.
|
### 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:
|
### Details:
|
||||||
@@ -290,7 +290,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
|
|||||||
```
|
```
|
||||||
</info added on 2025-03-30T00:14:10.040Z>
|
</info added on 2025-03-30T00:14:10.040Z>
|
||||||
|
|
||||||
## 9. Implement Context Management and Caching Mechanisms [deferred]
|
## 9. Implement Context Management and Caching Mechanisms [done]
|
||||||
### Dependencies: 23.1
|
### 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.
|
### 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:
|
### Details:
|
||||||
@@ -303,7 +303,7 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
|
|||||||
7. Add cache statistics for monitoring performance
|
7. Add cache statistics for monitoring performance
|
||||||
8. Create unit tests for context management and caching functionality
|
8. Create unit tests for context management and caching functionality
|
||||||
|
|
||||||
## 10. Enhance Tool Registration and Resource Management [in-progress]
|
## 10. Enhance Tool Registration and Resource Management [deferred]
|
||||||
### Dependencies: 23.1, 23.8
|
### Dependencies: 23.1, 23.8
|
||||||
### Description: Refactor tool registration to follow FastMCP best practices, using decorators and improving the overall structure. Implement proper resource management for task templates and other shared resources.
|
### Description: Refactor tool registration to follow FastMCP best practices, using decorators and improving the overall structure. Implement proper resource management for task templates and other shared resources.
|
||||||
### Details:
|
### Details:
|
||||||
@@ -316,19 +316,19 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
|
|||||||
7. Add validation for tool inputs using FastMCP's built-in validation
|
7. Add validation for tool inputs using FastMCP's built-in validation
|
||||||
8. Create comprehensive tests for tool registration and resource access
|
8. Create comprehensive tests for tool registration and resource access
|
||||||
|
|
||||||
## 11. Implement Comprehensive Error Handling [pending]
|
## 11. Implement Comprehensive Error Handling [deferred]
|
||||||
### Dependencies: 23.1, 23.3
|
### Dependencies: 23.1, 23.3
|
||||||
### Description: Implement robust error handling using FastMCP's MCPError, including custom error types for different categories and standardized error responses.
|
### Description: Implement robust error handling using FastMCP's MCPError, including custom error types for different categories and standardized error responses.
|
||||||
### Details:
|
### Details:
|
||||||
1. Create custom error types extending MCPError for different categories (validation, auth, etc.)\n2. Implement standardized error responses following MCP protocol\n3. Add error handling middleware for all MCP endpoints\n4. Ensure proper error propagation from tools to client\n5. Add debug mode with detailed error information\n6. Document error types and handling patterns
|
1. Create custom error types extending MCPError for different categories (validation, auth, etc.)\n2. Implement standardized error responses following MCP protocol\n3. Add error handling middleware for all MCP endpoints\n4. Ensure proper error propagation from tools to client\n5. Add debug mode with detailed error information\n6. Document error types and handling patterns
|
||||||
|
|
||||||
## 12. Implement Structured Logging System [pending]
|
## 12. Implement Structured Logging System [deferred]
|
||||||
### Dependencies: 23.1, 23.3
|
### Dependencies: 23.1, 23.3
|
||||||
### Description: Implement a comprehensive logging system for the MCP server with different log levels, structured logging format, and request/response tracking.
|
### Description: Implement a comprehensive logging system for the MCP server with different log levels, structured logging format, and request/response tracking.
|
||||||
### Details:
|
### Details:
|
||||||
1. Design structured log format for consistent parsing\n2. Implement different log levels (debug, info, warn, error)\n3. Add request/response logging middleware\n4. Implement correlation IDs for request tracking\n5. Add performance metrics logging\n6. Configure log output destinations (console, file)\n7. Document logging patterns and usage
|
1. Design structured log format for consistent parsing\n2. Implement different log levels (debug, info, warn, error)\n3. Add request/response logging middleware\n4. Implement correlation IDs for request tracking\n5. Add performance metrics logging\n6. Configure log output destinations (console, file)\n7. Document logging patterns and usage
|
||||||
|
|
||||||
## 13. Create Testing Framework and Test Suite [pending]
|
## 13. Create Testing Framework and Test Suite [deferred]
|
||||||
### Dependencies: 23.1, 23.3
|
### Dependencies: 23.1, 23.3
|
||||||
### Description: Implement a comprehensive testing framework for the MCP server, including unit tests, integration tests, and end-to-end tests.
|
### Description: Implement a comprehensive testing framework for the MCP server, including unit tests, integration tests, and end-to-end tests.
|
||||||
### Details:
|
### Details:
|
||||||
@@ -346,3 +346,93 @@ function listTasks(tasksPath, statusFilter, withSubtasks = false, outputFormat =
|
|||||||
### Details:
|
### Details:
|
||||||
1. Research and implement SSE protocol for the MCP server\n2. Create dedicated SSE endpoints for event streaming\n3. Implement event emitter pattern for internal event management\n4. Add support for different event types (task status, logs, errors)\n5. Implement client connection management with proper keep-alive handling\n6. Add filtering capabilities to allow subscribing to specific event types\n7. Create in-memory event buffer for clients reconnecting\n8. Document SSE endpoint usage and client implementation examples\n9. Add robust error handling for dropped connections\n10. Implement rate limiting and backpressure mechanisms\n11. Add authentication for SSE connections
|
1. Research and implement SSE protocol for the MCP server\n2. Create dedicated SSE endpoints for event streaming\n3. Implement event emitter pattern for internal event management\n4. Add support for different event types (task status, logs, errors)\n5. Implement client connection management with proper keep-alive handling\n6. Add filtering capabilities to allow subscribing to specific event types\n7. Create in-memory event buffer for clients reconnecting\n8. Document SSE endpoint usage and client implementation examples\n9. Add robust error handling for dropped connections\n10. Implement rate limiting and backpressure mechanisms\n11. Add authentication for SSE connections
|
||||||
|
|
||||||
|
## 16. Implement parse-prd MCP command [pending]
|
||||||
|
### 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
|
||||||
|
|
||||||
|
|||||||
147
tasks/tasks.json
147
tasks/tasks.json
@@ -1400,7 +1400,7 @@
|
|||||||
"23.13"
|
"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>",
|
"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
|
"parentTaskId": 23
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1411,7 +1411,7 @@
|
|||||||
1
|
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",
|
"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": "done",
|
||||||
"parentTaskId": 23
|
"parentTaskId": 23
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1423,7 +1423,7 @@
|
|||||||
"23.8"
|
"23.8"
|
||||||
],
|
],
|
||||||
"details": "1. Update registerTaskMasterTools function to use FastMCP's decorator pattern\n2. Implement @mcp.tool() decorators for all existing tools\n3. Add proper type annotations and documentation for all tools\n4. Create resource handlers for task templates using @mcp.resource()\n5. Implement resource templates for common task patterns\n6. Update the server initialization to properly register all tools and resources\n7. Add validation for tool inputs using FastMCP's built-in validation\n8. Create comprehensive tests for tool registration and resource access",
|
"details": "1. Update registerTaskMasterTools function to use FastMCP's decorator pattern\n2. Implement @mcp.tool() decorators for all existing tools\n3. Add proper type annotations and documentation for all tools\n4. Create resource handlers for task templates using @mcp.resource()\n5. Implement resource templates for common task patterns\n6. Update the server initialization to properly register all tools and resources\n7. Add validation for tool inputs using FastMCP's built-in validation\n8. Create comprehensive tests for tool registration and resource access",
|
||||||
"status": "in-progress",
|
"status": "deferred",
|
||||||
"parentTaskId": 23
|
"parentTaskId": 23
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1431,7 +1431,7 @@
|
|||||||
"title": "Implement Comprehensive Error Handling",
|
"title": "Implement Comprehensive Error Handling",
|
||||||
"description": "Implement robust error handling using FastMCP's MCPError, including custom error types for different categories and standardized error responses.",
|
"description": "Implement robust error handling using FastMCP's MCPError, including custom error types for different categories and standardized error responses.",
|
||||||
"details": "1. Create custom error types extending MCPError for different categories (validation, auth, etc.)\\n2. Implement standardized error responses following MCP protocol\\n3. Add error handling middleware for all MCP endpoints\\n4. Ensure proper error propagation from tools to client\\n5. Add debug mode with detailed error information\\n6. Document error types and handling patterns",
|
"details": "1. Create custom error types extending MCPError for different categories (validation, auth, etc.)\\n2. Implement standardized error responses following MCP protocol\\n3. Add error handling middleware for all MCP endpoints\\n4. Ensure proper error propagation from tools to client\\n5. Add debug mode with detailed error information\\n6. Document error types and handling patterns",
|
||||||
"status": "pending",
|
"status": "deferred",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"23.1",
|
"23.1",
|
||||||
"23.3"
|
"23.3"
|
||||||
@@ -1443,7 +1443,7 @@
|
|||||||
"title": "Implement Structured Logging System",
|
"title": "Implement Structured Logging System",
|
||||||
"description": "Implement a comprehensive logging system for the MCP server with different log levels, structured logging format, and request/response tracking.",
|
"description": "Implement a comprehensive logging system for the MCP server with different log levels, structured logging format, and request/response tracking.",
|
||||||
"details": "1. Design structured log format for consistent parsing\\n2. Implement different log levels (debug, info, warn, error)\\n3. Add request/response logging middleware\\n4. Implement correlation IDs for request tracking\\n5. Add performance metrics logging\\n6. Configure log output destinations (console, file)\\n7. Document logging patterns and usage",
|
"details": "1. Design structured log format for consistent parsing\\n2. Implement different log levels (debug, info, warn, error)\\n3. Add request/response logging middleware\\n4. Implement correlation IDs for request tracking\\n5. Add performance metrics logging\\n6. Configure log output destinations (console, file)\\n7. Document logging patterns and usage",
|
||||||
"status": "pending",
|
"status": "deferred",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"23.1",
|
"23.1",
|
||||||
"23.3"
|
"23.3"
|
||||||
@@ -1455,7 +1455,7 @@
|
|||||||
"title": "Create Testing Framework and Test Suite",
|
"title": "Create Testing Framework and Test Suite",
|
||||||
"description": "Implement a comprehensive testing framework for the MCP server, including unit tests, integration tests, and end-to-end tests.",
|
"description": "Implement a comprehensive testing framework for the MCP server, including unit tests, integration tests, and end-to-end tests.",
|
||||||
"details": "1. Set up Jest testing framework with proper configuration\\n2. Create MCPTestClient for testing FastMCP server interaction\\n3. Implement unit tests for individual tool functions\\n4. Create integration tests for end-to-end request/response cycles\\n5. Set up test fixtures and mock data\\n6. Implement test coverage reporting\\n7. Document testing guidelines and examples",
|
"details": "1. Set up Jest testing framework with proper configuration\\n2. Create MCPTestClient for testing FastMCP server interaction\\n3. Implement unit tests for individual tool functions\\n4. Create integration tests for end-to-end request/response cycles\\n5. Set up test fixtures and mock data\\n6. Implement test coverage reporting\\n7. Document testing guidelines and examples",
|
||||||
"status": "pending",
|
"status": "deferred",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"23.1",
|
"23.1",
|
||||||
"23.3"
|
"23.3"
|
||||||
@@ -1486,6 +1486,141 @@
|
|||||||
"23.11"
|
"23.11"
|
||||||
],
|
],
|
||||||
"parentTaskId": 23
|
"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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
191
tests/integration/mcp-server/direct-functions.test.js
Normal file
191
tests/integration/mcp-server/direct-functions.test.js
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* Integration test for direct function imports in MCP server
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { jest } from '@jest/globals';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { dirname } from 'path';
|
||||||
|
|
||||||
|
// Get the current module's directory
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
// Import the direct functions
|
||||||
|
import { listTasksDirect } from '../../../mcp-server/src/core/task-master-core.js';
|
||||||
|
|
||||||
|
// Mock logger
|
||||||
|
const mockLogger = {
|
||||||
|
info: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
debug: jest.fn(),
|
||||||
|
warn: jest.fn()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test file paths
|
||||||
|
const testProjectRoot = path.join(__dirname, '../../fixture');
|
||||||
|
const testTasksPath = path.join(testProjectRoot, 'test-tasks.json');
|
||||||
|
|
||||||
|
describe('MCP Server Direct Functions', () => {
|
||||||
|
// Create test data before tests
|
||||||
|
beforeAll(() => {
|
||||||
|
// Create test directory if it doesn't exist
|
||||||
|
if (!fs.existsSync(testProjectRoot)) {
|
||||||
|
fs.mkdirSync(testProjectRoot, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a sample tasks.json file for testing
|
||||||
|
const sampleTasks = {
|
||||||
|
meta: {
|
||||||
|
projectName: 'Test Project',
|
||||||
|
version: '1.0.0'
|
||||||
|
},
|
||||||
|
tasks: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: 'Task 1',
|
||||||
|
description: 'First task',
|
||||||
|
status: 'done',
|
||||||
|
dependencies: [],
|
||||||
|
priority: 'high'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: 'Task 2',
|
||||||
|
description: 'Second task',
|
||||||
|
status: 'in-progress',
|
||||||
|
dependencies: [1],
|
||||||
|
priority: 'medium',
|
||||||
|
subtasks: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: 'Subtask 2.1',
|
||||||
|
description: 'First subtask',
|
||||||
|
status: 'done'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: 'Subtask 2.2',
|
||||||
|
description: 'Second subtask',
|
||||||
|
status: 'pending'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: 'Task 3',
|
||||||
|
description: 'Third task',
|
||||||
|
status: 'pending',
|
||||||
|
dependencies: [1, 2],
|
||||||
|
priority: 'low'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFileSync(testTasksPath, JSON.stringify(sampleTasks, null, 2));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up after tests
|
||||||
|
afterAll(() => {
|
||||||
|
// Remove test tasks file
|
||||||
|
if (fs.existsSync(testTasksPath)) {
|
||||||
|
fs.unlinkSync(testTasksPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to remove the directory (will only work if empty)
|
||||||
|
try {
|
||||||
|
fs.rmdirSync(testProjectRoot);
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore errors if the directory isn't empty
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset mocks before each test
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('listTasksDirect', () => {
|
||||||
|
test('should return all tasks when no filter is provided', async () => {
|
||||||
|
// Arrange
|
||||||
|
const args = {
|
||||||
|
projectRoot: testProjectRoot,
|
||||||
|
file: testTasksPath
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await listTasksDirect(args, mockLogger);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.data.tasks.length).toBe(3);
|
||||||
|
expect(result.data.stats.total).toBe(3);
|
||||||
|
expect(result.data.stats.completed).toBe(1);
|
||||||
|
expect(result.data.stats.inProgress).toBe(1);
|
||||||
|
expect(result.data.stats.pending).toBe(1);
|
||||||
|
expect(mockLogger.info).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should filter tasks by status', async () => {
|
||||||
|
// Arrange
|
||||||
|
const args = {
|
||||||
|
projectRoot: testProjectRoot,
|
||||||
|
file: testTasksPath,
|
||||||
|
status: 'pending'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await listTasksDirect(args, mockLogger);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.data.tasks.length).toBe(1);
|
||||||
|
expect(result.data.tasks[0].id).toBe(3);
|
||||||
|
expect(result.data.filter).toBe('pending');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should include subtasks when requested', async () => {
|
||||||
|
// Arrange
|
||||||
|
const args = {
|
||||||
|
projectRoot: testProjectRoot,
|
||||||
|
file: testTasksPath,
|
||||||
|
withSubtasks: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await listTasksDirect(args, mockLogger);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
|
||||||
|
// Verify subtasks are included
|
||||||
|
const taskWithSubtasks = result.data.tasks.find(t => t.id === 2);
|
||||||
|
expect(taskWithSubtasks.subtasks).toBeDefined();
|
||||||
|
expect(taskWithSubtasks.subtasks.length).toBe(2);
|
||||||
|
|
||||||
|
// Verify subtask details
|
||||||
|
expect(taskWithSubtasks.subtasks[0].id).toBe(1);
|
||||||
|
expect(taskWithSubtasks.subtasks[0].title).toBe('Subtask 2.1');
|
||||||
|
expect(taskWithSubtasks.subtasks[0].status).toBe('done');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle errors gracefully', async () => {
|
||||||
|
// Arrange
|
||||||
|
const args = {
|
||||||
|
projectRoot: testProjectRoot,
|
||||||
|
file: 'non-existent-file.json'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await listTasksDirect(args, mockLogger);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
expect(result.error).toBeDefined();
|
||||||
|
expect(result.error.code).toBeDefined();
|
||||||
|
expect(result.error.message).toBeDefined();
|
||||||
|
expect(mockLogger.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user