chore: adds changeset.mdc to help agent automatically trigger changeset command with contextual information based on how we want to use it. not to be called for internal dev stuff.
This commit is contained in:
@@ -105,14 +105,18 @@ alwaysApply: false
|
||||
- **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).
|
||||
- Handles MCP requests via tool `execute` methods defined in `mcp-server/src/tools/*.js`.
|
||||
- Tool `execute` methods call corresponding direct function wrappers in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js) for core logic execution.
|
||||
- Direct function wrappers (`*Direct` functions) contain the main logic, including path resolution and optional caching.
|
||||
- Tool `execute` methods use `handleApiResult` from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js) to process the result from the direct function and format the final MCP response.
|
||||
- Uses CLI execution via `executeTaskMasterCommand` as a fallback only when necessary.
|
||||
- **Implements Caching**: Utilizes a caching layer (`ContextManager` with `lru-cache`). Caching logic is invoked *within* the direct function wrappers ([`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js)) using the `getCachedOrExecute` utility for performance-sensitive read operations (e.g., `listTasks`).
|
||||
- Standardizes response formatting and data filtering 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.
|
||||
- `mcp-server/src/tools/`: Directory containing individual tool definitions. Each tool's `execute` method orchestrates the call to core logic and handles the response.
|
||||
- `mcp-server/src/core/task-master-core.js`: Contains direct function wrappers (`*Direct`) that encapsulate core logic calls and caching.
|
||||
- `mcp-server/src/tools/utils.js`: Provides utilities like `handleApiResult`, `processMCPResponseData`, and `getCachedOrExecute`.
|
||||
|
||||
- **Data Flow and Module Dependencies**:
|
||||
|
||||
|
||||
105
.cursor/rules/changeset.mdc
Normal file
105
.cursor/rules/changeset.mdc
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
description: Guidelines for using Changesets (npm run changeset) to manage versioning and changelogs.
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Changesets Workflow Guidelines
|
||||
|
||||
Changesets is used to manage package versioning and generate accurate `CHANGELOG.md` files automatically. It's crucial to use it correctly after making meaningful changes that affect the package from an external perspective or significantly impact internal development workflow documented elsewhere.
|
||||
|
||||
## When to Run Changeset
|
||||
|
||||
- Run `npm run changeset` (or `npx changeset add`) **after** you have staged (`git add .`) a logical set of changes that should be communicated in the next release's `CHANGELOG.md`.
|
||||
- This typically includes:
|
||||
- **New Features** (Backward-compatible additions)
|
||||
- **Bug Fixes** (Fixes to existing functionality)
|
||||
- **Breaking Changes** (Changes that are not backward-compatible)
|
||||
- **Performance Improvements** (Enhancements to speed or resource usage)
|
||||
- **Significant Refactoring** (Major code restructuring, even if external behavior is unchanged, as it might affect stability or maintainability)
|
||||
- **User-Facing Documentation Updates** (Changes to README, usage guides, public API docs)
|
||||
- **Dependency Updates** (Especially if they fix known issues or introduce significant changes)
|
||||
- **Build/Tooling Changes** (If they affect how consumers might build or interact with the package)
|
||||
- **Every Pull Request** containing one or more of the above change types **should include a changeset file**.
|
||||
|
||||
## What NOT to Add a Changeset For
|
||||
|
||||
Avoid creating changesets for changes that have **no impact or relevance to external consumers** of the `task-master` package or contributors following **public-facing documentation**. Examples include:
|
||||
|
||||
- **Internal Documentation Updates:** Changes *only* to files within `.cursor/rules/` that solely guide internal development practices for this specific repository.
|
||||
- **Trivial Chores:** Very minor code cleanup, adding comments that don't clarify behavior, typo fixes in non-user-facing code or internal docs.
|
||||
- **Non-Impactful Test Updates:** Minor refactoring of tests, adding tests for existing functionality without fixing bugs.
|
||||
- **Local Configuration Changes:** Updates to personal editor settings, local `.env` files, etc.
|
||||
|
||||
**Rule of Thumb:** If a user installing or using the `task-master` package wouldn't care about the change, or if a contributor following the main README wouldn't need to know about it for their workflow, you likely don't need a changeset.
|
||||
|
||||
## How to Run and What It Asks
|
||||
|
||||
1. **Run the command**:
|
||||
```bash
|
||||
npm run changeset
|
||||
# or
|
||||
npx changeset add
|
||||
```
|
||||
2. **Select Packages**: It will prompt you to select the package(s) affected by your changes using arrow keys and spacebar. If this is not a monorepo, select the main package.
|
||||
3. **Select Bump Type**: Choose the appropriate semantic version bump for **each** selected package:
|
||||
* **`Major`**: For **breaking changes**. Use sparingly.
|
||||
* **`Minor`**: For **new features**.
|
||||
* **`Patch`**: For **bug fixes**, performance improvements, **user-facing documentation changes**, significant refactoring, relevant dependency updates, or impactful build/tooling changes.
|
||||
4. **Enter Summary**: Provide a concise summary of the changes **for the `CHANGELOG.md`**.
|
||||
* **Purpose**: This message is user-facing and explains *what* changed in the release.
|
||||
* **Format**: Use the imperative mood (e.g., "Add feature X", "Fix bug Y", "Update README setup instructions"). Keep it brief, typically a single line.
|
||||
* **Audience**: Think about users installing/updating the package or developers consuming its public API/CLI.
|
||||
* **Not a Git Commit Message**: This summary is *different* from your detailed Git commit message.
|
||||
|
||||
## Changeset Summary vs. Git Commit Message
|
||||
|
||||
- **Changeset Summary**:
|
||||
- **Audience**: Users/Consumers of the package (reads `CHANGELOG.md`).
|
||||
- **Purpose**: Briefly describe *what* changed in the released version that is relevant to them.
|
||||
- **Format**: Concise, imperative mood, single line usually sufficient.
|
||||
- **Example**: `Fix dependency resolution bug in 'next' command.`
|
||||
- **Git Commit Message**:
|
||||
- **Audience**: Developers browsing the Git history of *this* repository.
|
||||
- **Purpose**: Explain *why* the change was made, the context, and the implementation details (can include internal context).
|
||||
- **Format**: Follows commit conventions (e.g., Conventional Commits), can be multi-line with a subject and body.
|
||||
- **Example**:
|
||||
```
|
||||
fix(deps): Correct dependency lookup in 'next' command
|
||||
|
||||
The logic previously failed to account for subtask dependencies when
|
||||
determining the next available task. This commit refactors the
|
||||
dependency check in `findNextTask` within `task-manager.js` to
|
||||
correctly traverse both direct and subtask dependencies. Added
|
||||
unit tests to cover this specific scenario.
|
||||
```
|
||||
- ✅ **DO**: Provide *both* a concise changeset summary (when appropriate) *and* a detailed Git commit message.
|
||||
- ❌ **DON'T**: Use your detailed Git commit message body as the changeset summary.
|
||||
- ❌ **DON'T**: Skip running `changeset` for user-relevant changes just because you wrote a good commit message.
|
||||
|
||||
## The `.changeset` File
|
||||
|
||||
- Running the command creates a unique markdown file in the `.changeset/` directory (e.g., `.changeset/random-name.md`).
|
||||
- This file contains the bump type information and the summary you provided.
|
||||
- **This file MUST be staged and committed** along with your relevant code changes.
|
||||
|
||||
## Standard Workflow Sequence (When a Changeset is Needed)
|
||||
|
||||
1. Make your code or relevant documentation changes.
|
||||
2. Stage your changes: `git add .`
|
||||
3. Run changeset: `npm run changeset`
|
||||
* Select package(s).
|
||||
* Select bump type (`Patch`, `Minor`, `Major`).
|
||||
* Enter the **concise summary** for the changelog.
|
||||
4. Stage the generated changeset file: `git add .changeset/*.md`
|
||||
5. Commit all staged changes (code + changeset file) using your **detailed Git commit message**:
|
||||
```bash
|
||||
git commit -m "feat(module): Add new feature X..."
|
||||
```
|
||||
|
||||
## Release Process (Context)
|
||||
|
||||
- The generated `.changeset/*.md` files are consumed later during the release process.
|
||||
- Commands like `changeset version` read these files, update `package.json` versions, update the `CHANGELOG.md`, and delete the individual changeset files.
|
||||
- Commands like `changeset publish` then publish the new versions to npm.
|
||||
|
||||
Following this workflow ensures that versioning is consistent and changelogs are automatically and accurately generated based on the contributions made.
|
||||
24
.cursor/rules/glossary.mdc
Normal file
24
.cursor/rules/glossary.mdc
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
description: Glossary of other Cursor rules
|
||||
globs: **/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Glossary of Task Master Cursor Rules
|
||||
|
||||
This file provides a quick reference to the purpose of each rule file located in the `.cursor/rules` directory.
|
||||
|
||||
- **[`architecture.mdc`](mdc:.cursor/rules/architecture.mdc)**: Describes the high-level architecture of the Task Master CLI application.
|
||||
- **[`commands.mdc`](mdc:.cursor/rules/commands.mdc)**: Guidelines for implementing CLI commands using Commander.js.
|
||||
- **[`cursor_rules.mdc`](mdc:.cursor/rules/cursor_rules.mdc)**: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness.
|
||||
- **[`dependencies.mdc`](mdc:.cursor/rules/dependencies.mdc)**: Guidelines for managing task dependencies and relationships.
|
||||
- **[`dev_workflow.mdc`](mdc:.cursor/rules/dev_workflow.mdc)**: Guide for using meta-development script (`scripts/dev.js`) and the `task-master` CLI to manage task-driven development workflows.
|
||||
- **[`glossary.mdc`](mdc:.cursor/rules/glossary.mdc)**: This file; provides a glossary of other Cursor rules.
|
||||
- **[`mcp.mdc`](mdc:.cursor/rules/mcp.mdc)**: Guidelines for implementing and interacting with the Task Master MCP Server.
|
||||
- **[`new_features.mdc`](mdc:.cursor/rules/new_features.mdc)**: Guidelines for integrating new features into the Task Master CLI.
|
||||
- **[`self_improve.mdc`](mdc:.cursor/rules/self_improve.mdc)**: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.
|
||||
- **[`tasks.mdc`](mdc:.cursor/rules/tasks.mdc)**: Guidelines for implementing task management operations.
|
||||
- **[`tests.mdc`](mdc:.cursor/rules/tests.mdc)**: Guidelines for implementing and maintaining tests for Task Master CLI.
|
||||
- **[`ui.mdc`](mdc:.cursor/rules/ui.mdc)**: Guidelines for implementing and maintaining user interface components.
|
||||
- **[`utilities.mdc`](mdc:.cursor/rules/utilities.mdc)**: Guidelines for implementing utility functions.
|
||||
|
||||
@@ -18,70 +18,82 @@ The MCP server acts as a bridge between external tools (like Cursor) and the cor
|
||||
## 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.
|
||||
- **Standard Tool Execution Pattern**:
|
||||
- The `execute` method within each MCP tool (in `mcp-server/src/tools/*.js`) should:
|
||||
1. Call the corresponding `*Direct` function wrapper (e.g., `listTasksDirect`) from [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js), passing necessary arguments and the logger.
|
||||
2. Receive the result object (typically `{ success, data/error, fromCache }`).
|
||||
3. Pass this result object to the `handleApiResult` utility (from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js)) for standardized response formatting and error handling.
|
||||
4. Return the formatted response object provided by `handleApiResult`.
|
||||
- **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.
|
||||
- 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.
|
||||
- `getProjectRoot`: Normalizes project paths.
|
||||
- `handleApiResult`: Takes the raw result from a `*Direct` function and formats it into a standard MCP success or error response, automatically handling data processing via `processMCPResponseData`. This is called by the tool's `execute` method.
|
||||
- `createContentResponse`/`createErrorResponse`: Used by `handleApiResult` to format successful/error MCP responses.
|
||||
- `processMCPResponseData`: Filters/cleans data (e.g., removing `details`, `testStrategy`) before it's sent in the MCP response. Called by `handleApiResult`.
|
||||
- `getCachedOrExecute`: **Used inside `*Direct` functions** in `task-master-core.js` to implement caching 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.
|
||||
- **Caching**: To improve performance for frequently called read operations (like `listTasks`, `showTask`, `nextTask`), a caching layer using `lru-cache` is implemented.
|
||||
- **Caching logic resides *within* 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 (e.g., file path, filters).
|
||||
- The `getCachedOrExecute` utility handles checking the cache, executing the core logic function on a cache miss, storing the result, and returning the data along with a `fromCache` flag.
|
||||
- Cache statistics can be monitored using the `cacheStats` MCP tool (implemented via `getCacheStatsDirect`).
|
||||
- **Caching should generally be applied to read-only operations** that don't modify the `tasks.json` state. Commands like `set-status`, `add-task`, `update-task`, `parse-prd`, `add-dependency` should *not* be cached as they change the underlying data.
|
||||
|
||||
## 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/`:
|
||||
2. **Create Direct Wrapper (`task-master-core.js`)**:
|
||||
- Create an `async function yourCommandDirect(args, log)` in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js).
|
||||
- Inside the wrapper:
|
||||
- Import necessary core functions and utilities (`findTasksJsonPath`, `getCachedOrExecute` if caching).
|
||||
- Parse `args` and determine necessary inputs (e.g., `tasksPath` via `findTasksJsonPath`).
|
||||
- **If Caching**:
|
||||
- Generate a unique `cacheKey` based on arguments defining the operation.
|
||||
- Define an `async` function `coreActionFn` containing the actual call to the core logic, formatting its return as `{ success: true/false, data/error }`.
|
||||
- Call `const result = await getCachedOrExecute({ cacheKey, actionFn: coreActionFn, log });`.
|
||||
- `return result;` (which includes the `fromCache` flag).
|
||||
- **If Not Caching**:
|
||||
- Directly call the core logic function within a try/catch block.
|
||||
- Format the return as `{ success: true/false, data/error, fromCache: false }`.
|
||||
- Export the wrapper function and add it to the `directFunctions` map.
|
||||
3. **Create MCP Tool (`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 `z` for schema definition.
|
||||
- Import `handleApiResult` 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`:
|
||||
- Define `name`, `description`, and `parameters` using `zod` (include optional `projectRoot`, `file` if needed).
|
||||
- Define the `async execute(args, log)` function:
|
||||
```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
|
||||
});
|
||||
async execute(args, log) {
|
||||
try {
|
||||
log.info(`Executing Your Command with args: ${JSON.stringify(args)}`);
|
||||
// Call the direct function wrapper
|
||||
const result = await yourCommandDirect(args, log);
|
||||
|
||||
// Let handleApiResult format the final MCP response
|
||||
return handleApiResult(result, log, 'Error during Your Command');
|
||||
// Optionally pass a custom processor to handleApiResult if default filtering isn't sufficient:
|
||||
// return handleApiResult(result, log, 'Error...', customDataProcessor);
|
||||
} catch (error) {
|
||||
// Catch unexpected errors during the direct call itself
|
||||
log.error(`Unexpected error in tool execute: ${error.message}`);
|
||||
// Use createErrorResponse for unexpected errors
|
||||
return createErrorResponse(`Tool execution failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
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": { ... } }`).
|
||||
- MCP tools should return the object generated by `handleApiResult`.
|
||||
- `handleApiResult` uses `createContentResponse` or `createErrorResponse` internally.
|
||||
- `handleApiResult` also uses `processMCPResponseData` by default to filter potentially large fields (`details`, `testStrategy`) from task data. Provide a custom processor function to `handleApiResult` if different filtering is needed.
|
||||
- The final JSON response sent to the MCP client will include the `fromCache` boolean flag (obtained from the `*Direct` function's result) alongside the actual data (e.g., `{ "fromCache": true, "data": { ... } }` or `{ "fromCache": false, "data": { ... } }`).
|
||||
|
||||
@@ -312,48 +312,59 @@ For more information on module structure, see [`MODULE_PLAN.md`](mdc:scripts/mod
|
||||
|
||||
## 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.
|
||||
Integrating Task Master commands with the MCP server (for use by tools like Cursor) follows a specific pattern distinct from the CLI command implementation, prioritizing performance and reliability.
|
||||
|
||||
- **Goal**: Leverage direct function calls for performance and reliability, avoiding CLI overhead.
|
||||
- **Goal**: Leverage direct function calls to core logic, 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"
|
||||
});
|
||||
}
|
||||
});
|
||||
1. **Core Logic**: Ensure the command's core logic exists and is exported from the appropriate module (e.g., [`task-manager.js`](mdc:scripts/modules/task-manager.js)).
|
||||
2. **Direct Function Wrapper (`task-master-core.js`)**:
|
||||
- Create an `async function yourCommandDirect(args, log)` in [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js).
|
||||
- This function imports and calls the core logic function.
|
||||
- It handles argument parsing, path resolution (e.g., using `findTasksJsonPath`), and validation specific to the direct call.
|
||||
- **Implement Caching (if applicable)**:
|
||||
- **Use Case**: Apply caching primarily for read-only operations that benefit from repeated calls (e.g., `listTasks`, `showTask`, `nextTask`). Avoid caching for operations that modify state (`setTaskStatus`, `addTask`, `parsePRD`, `updateTask`, `addDependency`, etc.).
|
||||
- **Implementation**: Inside the `yourCommandDirect` function, use the `getCachedOrExecute` utility (imported from `../tools/utils.js`).
|
||||
- Generate a unique `cacheKey` based on relevant arguments (e.g., file path, filters).
|
||||
- Define an `async` function `coreActionFn` that wraps the actual call to the core logic and returns `{ success: true/false, data/error }`.
|
||||
- Call `await getCachedOrExecute({ cacheKey, actionFn: coreActionFn, log });`.
|
||||
- The `yourCommandDirect` function must return a standard object: `{ success: true/false, data/error, fromCache: boolean }`. For non-cached operations, `fromCache` should be `false`.
|
||||
- Export the function and add it to the `directFunctions` map in `task-master-core.js`.
|
||||
3. **MCP Tool File (`mcp-server/src/tools/`)**:
|
||||
- Create a new file (e.g., `yourCommand.js`).
|
||||
- Import `zod` (for schema), `handleApiResult`, `createErrorResponse` from `./utils.js`, and your `yourCommandDirect` function from `../core/task-master-core.js`.
|
||||
- Implement `registerYourCommandTool(server)` which calls `server.addTool`.
|
||||
- Define the tool's `name`, `description`, and `parameters` using `zod`.
|
||||
- Define the `async execute(args, log)` method. **This is the standard pattern**:
|
||||
```javascript
|
||||
// In mcp-server/src/tools/yourCommand.js
|
||||
import { z } from "zod";
|
||||
import { handleApiResult, createErrorResponse } from "./utils.js";
|
||||
import { yourCommandDirect } from "../core/task-master-core.js";
|
||||
|
||||
export function registerYourCommandTool(server) {
|
||||
server.addTool({
|
||||
name: "yourCommand",
|
||||
description: "Description of your command.",
|
||||
parameters: z.object({ /* zod schema, include projectRoot, file if needed */ }),
|
||||
async execute(args, log) {
|
||||
try {
|
||||
log.info(`Executing Your Command with args: ${JSON.stringify(args)}`);
|
||||
// 1. Call the direct function wrapper
|
||||
const result = await yourCommandDirect(args, log);
|
||||
|
||||
// 2. Pass the result to handleApiResult for formatting
|
||||
return handleApiResult(result, log, 'Error during Your Command');
|
||||
} catch (error) {
|
||||
// Catch unexpected errors from the direct call itself
|
||||
log.error(`Unexpected error in tool execute: ${error.message}`);
|
||||
return createErrorResponse(`Tool execution failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
});
|
||||
}
|
||||
```
|
||||
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`.
|
||||
|
||||
@@ -282,62 +282,44 @@ alwaysApply: false
|
||||
- **`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`).
|
||||
- Can be used within `*Direct` functions if needed, although often the `projectRoot` argument is passed through.
|
||||
|
||||
- **`handleApiResult(result, log, errorPrefix, processFunction)`**:
|
||||
- Takes the standard `{ success, data/error }` object returned by direct function wrappers (like `listTasksDirect`).
|
||||
- ✅ **DO**: Call this from the MCP tool's `execute` method after receiving the result from the `*Direct` function wrapper.
|
||||
- Takes the standard `{ success, data/error, fromCache }` object returned by direct function wrappers.
|
||||
- Checks the `success` flag.
|
||||
- If successful, processes the `data` using `processFunction` (defaults to `processMCPResponseData`).
|
||||
- If successful, processes the `result.data` using the provided `processFunction` (defaults to `processMCPResponseData` for filtering).
|
||||
- Includes the `result.fromCache` flag in the final payload.
|
||||
- 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.
|
||||
- ❌ **DON'T**: Use this as the primary method for MCP tools. Prefer direct function calls via `*Direct` wrappers. Use only as a fallback.
|
||||
|
||||
- **`processMCPResponseData(taskOrData, fieldsToRemove = ['details', 'testStrategy'])`**:
|
||||
- Filters task data before sending it to the MCP client.
|
||||
- Filters task data before sending it to the MCP client. Called by `handleApiResult` by default.
|
||||
- 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.
|
||||
```
|
||||
- Can handle single task objects or data structures containing tasks.
|
||||
|
||||
- **`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.
|
||||
- Used by `handleApiResult` to format successful MCP responses.
|
||||
- Wraps the `content` (which includes the `fromCache` flag and processed `data`) in the standard FastMCP `{ content: [{ type: "text", text: ... }] }` structure, stringifying the payload object.
|
||||
|
||||
- **`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`.
|
||||
- Used by `handleApiResult` or directly in the tool's `execute` catch block to format error responses for MCP.
|
||||
- Wraps the `errorMessage` in the standard FastMCP error structure.
|
||||
|
||||
- **`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.
|
||||
- **Use Case**: Primarily for read-only operations (e.g., `list`, `show`, `next`). Avoid for operations modifying data.
|
||||
- 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: ... }`).
|
||||
- If HIT: returns the cached result directly (which should be `{ success, data/error }`), adding `fromCache: true`.
|
||||
- If MISS: executes the provided `actionFn` (an async function returning `{ success, data/error }`).
|
||||
- If `actionFn` succeeds, its result is stored in the cache.
|
||||
- Returns the result (cached or fresh) wrapped in the standard structure `{ success, data/error, fromCache: boolean }`.
|
||||
|
||||
## Export Organization
|
||||
|
||||
|
||||
Reference in New Issue
Block a user