Files
claude-task-master/.cursor/rules/mcp.mdc
Eyal Toledano 1a74b50658 docs: Update rules for MCP/CLI workflow and project root handling
Updated several Cursor rules documentation files (`mcp.mdc`, `utilities.mdc`, `architecture.mdc`, `new_features.mdc`, `commands.mdc`) to accurately reflect recent refactoring and clarify best practices.

Key documentation updates include:

- Explicitly stating the preference for using MCP tools over CLI commands in integrated environments (`commands.mdc`, `dev_workflow.mdc`).

- Describing the new standard pattern for getting the project root using `getProjectRootFromSession` within MCP tool `execute` methods (`mcp.mdc`, `utilities.mdc`, `architecture.mdc`, `new_features.mdc`).

- Clarifying the simplified role of `findTasksJsonPath` in direct functions (`mcp.mdc`, `utilities.mdc`, `architecture.mdc`, `new_features.mdc`).

- Ensuring proper interlinking between related documentation files.
2025-04-08 15:54:06 -04:00

326 lines
19 KiB
Plaintext

---
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/direct-functions/*.js`, exported via `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.
## Tool Definition and Execution
### Tool Structure
MCP tools must follow a specific structure to properly interact with the FastMCP framework:
```javascript
server.addTool({
name: "tool_name", // Use snake_case for tool names
description: "Description of what the tool does",
parameters: z.object({
// Define parameters using Zod
param1: z.string().describe("Parameter description"),
param2: z.number().optional().describe("Optional parameter description"),
// IMPORTANT: For file operations, always include these optional parameters
file: z.string().optional().describe("Path to the tasks file"),
projectRoot: z.string().optional().describe("Root directory of the project (typically derived from session)")
}),
// The execute function is the core of the tool implementation
execute: async (args, context) => {
// Implementation goes here
// Return response in the appropriate format
}
});
```
### Execute Function Signature
The `execute` function receives validated arguments and the FastMCP context:
```javascript
execute: async (args, context) => {
// Tool implementation
}
```
- **args**: The first parameter contains all the validated parameters defined in the tool's schema.
- **context**: The second parameter is an object containing `{ log, reportProgress, session }` provided by FastMCP.
- ✅ **DO**: `execute: async (args, { log, reportProgress, session }) => {}`
### Standard Tool Execution Pattern
The `execute` method within each MCP tool (in `mcp-server/src/tools/*.js`) should follow this standard pattern:
1. **Log Entry**: Log the start of the tool execution with relevant arguments.
2. **Get Project Root**: Use the `getProjectRootFromSession(session, log)` utility (from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js)) to extract the project root path from the client session. Fall back to `args.projectRoot` if the session doesn't provide a root.
3. **Call Direct Function**: Invoke the corresponding `*Direct` function wrapper (e.g., `listTasksDirect` from [`task-master-core.js`](mdc:mcp-server/src/core/task-master-core.js)), passing an updated `args` object that includes the resolved `projectRoot`, along with the `log` object: `await someDirectFunction({ ...args, projectRoot: resolvedRootFolder }, log);`
4. **Handle Result**: Receive the result object (`{ success, data/error, fromCache }`) from the `*Direct` function.
5. **Format Response**: Pass this result object to the `handleApiResult` utility (from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js)) for standardized MCP response formatting and error handling.
6. **Return**: Return the formatted response object provided by `handleApiResult`.
```javascript
// Example execute method structure
import { getProjectRootFromSession, handleApiResult, createErrorResponse } from './utils.js';
import { someDirectFunction } from '../core/task-master-core.js';
// ... inside server.addTool({...})
execute: async (args, { log, reportProgress, session }) => {
try {
log.info(`Starting tool execution with args: ${JSON.stringify(args)}`);
// 1. Get Project Root
let rootFolder = getProjectRootFromSession(session, log);
if (!rootFolder && args.projectRoot) { // Fallback if needed
rootFolder = args.projectRoot;
log.info(`Using project root from args as fallback: ${rootFolder}`);
}
// 2. Call Direct Function (passing resolved root)
const result = await someDirectFunction({
...args,
projectRoot: rootFolder // Ensure projectRoot is explicitly passed
}, log);
// 3. Handle and Format Response
return handleApiResult(result, log);
} catch (error) {
log.error(`Error during tool execution: ${error.message}`);
return createErrorResponse(error.message);
}
}
```
### Logging Convention
The `log` object (destructured from `context`) provides standardized logging methods. Use it within both the `execute` method and the `*Direct` functions.
```javascript
// Proper logging usage
log.info(`Starting ${toolName} with parameters: ${JSON.stringify(sanitizedArgs)}`);
log.debug("Detailed operation info", { data });
log.warn("Potential issue detected");
log.error(`Error occurred: ${error.message}`, { stack: error.stack });
```
### Progress Reporting Convention
Use `reportProgress` (destructured from `context`) for long-running operations. It expects an object `{ progress: number, total?: number }`.
```javascript
await reportProgress({ progress: 0 }); // Start
// ... work ...
await reportProgress({ progress: 50 }); // Intermediate (total optional)
// ... more work ...
await reportProgress({ progress: 100 }); // Complete
```
### Session Usage Convention
The `session` object (destructured from `context`) contains authenticated session data and client information.
- **Authentication**: Access user-specific data (`session.userId`, etc.) if authentication is implemented.
- **Project Root**: The primary use in Task Master is accessing `session.roots` to determine the client's project root directory via the `getProjectRootFromSession` utility (from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js)). See the Standard Tool Execution Pattern above.
- **Capabilities**: Can be used to check client capabilities (`session.clientCapabilities`).
## Direct Function Wrappers (`*Direct`)
These functions, located in `mcp-server/src/core/direct-functions/`, form the core logic execution layer for MCP tools.
- **Purpose**: Bridge MCP tools and core Task Master modules (`scripts/modules/*`).
- **Responsibilities**:
- Receive `args` (including the `projectRoot` determined by the tool) and `log` object.
- **Find `tasks.json`**: Use `findTasksJsonPath(args, log)` from [`core/utils/path-utils.js`](mdc:mcp-server/src/core/utils/path-utils.js). This function prioritizes the provided `args.projectRoot`.
- Validate arguments specific to the core logic.
- **Implement Caching**: Use `getCachedOrExecute` from [`tools/utils.js`](mdc:mcp-server/src/tools/utils.js) for read operations.
- Call the underlying function from the core Task Master modules.
- Handle errors gracefully.
- Return a standardized result object: `{ success: boolean, data?: any, error?: { code: string, message: string }, fromCache: boolean }`.
## Key Principles
- **Prefer Direct Function Calls**: MCP tools should always call `*Direct` wrappers instead of `executeTaskMasterCommand`.
- **Standardized Execution Flow**: Follow the pattern: MCP Tool -> `getProjectRootFromSession` -> `*Direct` Function -> Core Logic.
- **Path Resolution via Direct Functions**: The `*Direct` function is responsible for finding the exact `tasks.json` path using `findTasksJsonPath`, relying on the `projectRoot` passed in `args`.
- **Centralized Utilities**: Use helpers from `mcp-server/src/tools/utils.js` (like `handleApiResult`, `getProjectRootFromSession`, `getCachedOrExecute`) and `mcp-server/src/core/utils/path-utils.js` (`findTasksJsonPath`). See [`utilities.mdc`](mdc:.cursor/rules/utilities.mdc).
- **Caching in Direct Functions**: Caching logic resides *within* the `*Direct` functions using `getCachedOrExecute`.
## Resources and Resource Templates
Resources provide LLMs with static or dynamic data without executing tools.
- **Implementation**: Use `@mcp.resource()` decorator pattern or `server.addResource`/`server.addResourceTemplate` in `mcp-server/src/core/resources/`.
- **Registration**: Register resources during server initialization in [`mcp-server/src/index.js`](mdc:mcp-server/src/index.js).
- **Best Practices**: Organize resources, validate parameters, use consistent URIs, handle errors. See [`fastmcp-core.txt`](docs/fastmcp-core.txt) for underlying SDK details.
*(Self-correction: Removed detailed Resource implementation examples as they were less relevant to the current user focus on tool execution flow and project roots. Kept the overview.)*
## 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 Function File in `mcp-server/src/core/direct-functions/`**:
- Create a new file (e.g., `your-command.js`) using **kebab-case** naming.
- Import necessary core functions and **`findTasksJsonPath` from `../utils/path-utils.js`**.
- Implement `async function yourCommandDirect(args, log)` using **camelCase** with `Direct` suffix:
- **Path Resolution**: Obtain the tasks file path using `const tasksPath = findTasksJsonPath(args, log);`. This handles project root detection automatically based on `args.projectRoot`.
- Parse other `args` and perform necessary validation.
- **If Caching**: Implement caching using `getCachedOrExecute` from `../../tools/utils.js`.
- **If Not Caching**: Directly call the core logic function within a try/catch block.
- Format the return as `{ success: true/false, data/error, fromCache: boolean }`.
- Export the wrapper function.
3. **Update `task-master-core.js` with Import/Export**: Import and re-export your `*Direct` function and add it to the `directFunctions` map.
4. **Create MCP Tool (`mcp-server/src/tools/`)**:
- Create a new file (e.g., `your-command.js`) using **kebab-case**.
- Import `zod`, `handleApiResult`, `createErrorResponse`, **`getProjectRootFromSession`**, and your `yourCommandDirect` function.
- Implement `registerYourCommandTool(server)`.
- Define the tool `name` using **snake_case** (e.g., `your_command`).
- Define the `parameters` using `zod`. **Crucially, define `projectRoot` as optional**: `projectRoot: z.string().optional().describe(...)`. Include `file` if applicable.
- Implement the standard `async execute(args, { log, reportProgress, session })` method:
- Get `rootFolder` using `getProjectRootFromSession` (with fallback to `args.projectRoot`).
- Call `yourCommandDirect({ ...args, projectRoot: rootFolder }, log)`.
- Pass the result to `handleApiResult(result, log, 'Error Message')`.
5. **Register Tool**: Import and call `registerYourCommandTool` in `mcp-server/src/tools/index.js`.
6. **Update `mcp.json`**: Add the new tool definition to the `tools` array in `.cursor/mcp.json`.
## Handling Responses
- 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": { ... } }`).
## Parameter Type Handling
- **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)).
- **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.
- **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.
- `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`, `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.
**MCP Tool Implementation Checklist**:
1. **Core Logic Verification**:
- [ ] Confirm the core function is properly exported from its module (e.g., `task-manager.js`)
- [ ] Identify all required parameters and their types
2. **Direct Function Wrapper**:
- [ ] Create the `*Direct` function in `task-master-core.js`
- [ ] Handle all parameter validations and type conversions
- [ ] Implement path resolving for relative paths
- [ ] Add appropriate error handling with standardized error codes
- [ ] Add to `directFunctions` map
3. **MCP Tool Implementation**:
- [ ] Create new file in `mcp-server/src/tools/` with kebab-case naming
- [ ] Define zod schema for all parameters
- [ ] Implement the `execute` method following the standard pattern
- [ ] Register tool in `mcp-server/src/tools/index.js`
4. **Testing**:
- [ ] Write unit tests for the direct function wrapper
- [ ] Write integration tests for the MCP tool
## Standard Error Codes
- **Standard Error Codes**: Use consistent error codes across direct function wrappers
- `INPUT_VALIDATION_ERROR`: For missing or invalid required parameters
- `FILE_NOT_FOUND_ERROR`: For file system path issues
- `CORE_FUNCTION_ERROR`: For errors thrown by the core function
- `UNEXPECTED_ERROR`: For all other unexpected errors
- **Error Object Structure**:
```javascript
{
success: false,
error: {
code: 'ERROR_CODE',
message: 'Human-readable error message'
},
fromCache: false
}
```
- **MCP Tool Logging Pattern**:
- ✅ DO: Log the start of execution with arguments (sanitized if sensitive)
- ✅ DO: Log successful completion with result summary
- ✅ DO: Log all error conditions with appropriate log levels
- ✅ DO: Include the cache status in result logs
- ❌ DON'T: Log entire large data structures or sensitive information
- The MCP server integrates with Task Master core functions through three layers:
1. Tool Definitions (`mcp-server/src/tools/*.js`) - Define parameters and validation
2. Direct Functions (`mcp-server/src/core/direct-functions/*.js`) - Handle core logic integration
3. Core Functions (`scripts/modules/*.js`) - Implement the actual functionality
- This layered approach provides:
- Clear separation of concerns
- Consistent parameter validation
- Centralized error handling
- Performance optimization through caching (for read operations)
- Standardized response formatting
## MCP Naming Conventions
- **Files and Directories**:
- ✅ DO: Use **kebab-case** for all file names: `list-tasks.js`, `set-task-status.js`
- ✅ DO: Use consistent directory structure: `mcp-server/src/tools/` for tool definitions, `mcp-server/src/core/direct-functions/` for direct function implementations
- **JavaScript Functions**:
- ✅ DO: Use **camelCase** with `Direct` suffix for direct function implementations: `listTasksDirect`, `setTaskStatusDirect`
- ✅ DO: Use **camelCase** with `Tool` suffix for tool registration functions: `registerListTasksTool`, `registerSetTaskStatusTool`
- ✅ DO: Use consistent action function naming inside direct functions: `coreActionFn` or similar descriptive name
- **MCP Tool Names**:
- ✅ DO: Use **snake_case** for tool names exposed to MCP clients: `list_tasks`, `set_task_status`, `parse_prd_document`
- ✅ DO: Include the core action in the tool name without redundant words: Use `list_tasks` instead of `list_all_tasks`
- **Examples**:
- File: `list-tasks.js`
- Direct Function: `listTasksDirect`
- Tool Registration: `registerListTasksTool`
- MCP Tool Name: `list_tasks`
- **Mapping**:
- The `directFunctions` map in `task-master-core.js` maps the core function name (in camelCase) to its direct implementation:
```javascript
export const directFunctions = {
list: listTasksDirect,
setStatus: setTaskStatusDirect,
// Add more functions as implemented
};
```