Files
claude-task-master/docs/MCP_INTEGRATION.md

8.1 KiB

Task Master MCP Integration

This document outlines how Task Master CLI functionality is integrated with MCP (Master Control Program) architecture to provide both CLI and programmatic API access to features.

Architecture Overview

The MCP integration uses a layered approach:

  1. Core Functions - In scripts/modules/ contain the main business logic
  2. Source Parameter - Core functions check the source parameter to determine behavior
  3. Task Master Core - In mcp-server/src/core/task-master-core.js provides direct function imports
  4. MCP Tools - In mcp-server/src/tools/ register the functions with the MCP server
┌─────────────────┐         ┌─────────────────┐
│    CLI User     │         │    MCP User     │
└────────┬────────┘         └────────┬────────┘
         │                           │
         ▼                           ▼
┌────────────────┐         ┌────────────────────┐
│  commands.js   │         │   MCP Tool API     │
└────────┬───────┘         └──────────┬─────────┘
         │                            │
         │                            │
         ▼                            ▼
┌───────────────────────────────────────────────┐
│                                               │
│     Core Modules (task-manager.js, etc.)      │
│                                               │
└───────────────────────────────────────────────┘

Core Function Pattern

Core functions should follow this pattern to support both CLI and MCP use:

/**
 * Example function with source parameter support
 * @param {Object} options - Additional options including source
 * @returns {Object|undefined} - Returns data when source is 'mcp'
 */
function exampleFunction(param1, param2, options = {}) {
  try {
    // Skip UI for MCP
    if (options.source !== 'mcp') {
      displayBanner();
      console.log(chalk.blue('Processing operation...'));
    }
    
    // Do the core business logic
    const result = doSomething(param1, param2);
    
    // For MCP, return structured data
    if (options.source === 'mcp') {
      return {
        success: true,
        data: result
      };
    }
    
    // For CLI, display output
    console.log(chalk.green('Operation completed successfully!'));
  } catch (error) {
    // Handle errors based on source
    if (options.source === 'mcp') {
      return {
        success: false,
        error: error.message
      };
    }
    
    // CLI error handling
    console.error(chalk.red(`Error: ${error.message}`));
    process.exit(1);
  }
}

Source-Adapter Utilities

For convenience, you can use the source adapter helpers in scripts/modules/source-adapter.js:

import { adaptForMcp, sourceSplitFunction } from './source-adapter.js';

// Simple adaptation - just adds source parameter support
export const simpleFunction = adaptForMcp(originalFunction);

// Split implementation - completely different code paths for CLI vs MCP
export const complexFunction = sourceSplitFunction(
  // CLI version with UI
  function(param1, param2) {
    displayBanner();
    console.log(`Processing ${param1}...`);
    // ... CLI implementation
  },
  // MCP version with structured return
  function(param1, param2, options = {}) {
    // ... MCP implementation
    return { success: true, data };
  }
);

Adding New Features

When adding new features, follow these steps to ensure CLI and MCP compatibility:

  1. Implement Core Logic in the appropriate module file
  2. Add Source Parameter Support using the pattern above
  3. Add to task-master-core.js to make it available for direct import
  4. Update Command Map in mcp-server/src/tools/utils.js
  5. Create Tool Implementation in mcp-server/src/tools/
  6. Register the Tool in mcp-server/src/tools/index.js

Core Function Implementation

// In scripts/modules/task-manager.js
export async function newFeature(param1, param2, options = {}) {
  try {
    // Source-specific UI
    if (options.source !== 'mcp') {
      displayBanner();
      console.log(chalk.blue('Running new feature...'));
    }
    
    // Shared core logic
    const result = processFeature(param1, param2);
    
    // Source-specific return handling
    if (options.source === 'mcp') {
      return {
        success: true,
        data: result
      };
    }
    
    // CLI output
    console.log(chalk.green('Feature completed successfully!'));
    displayOutput(result);
  } catch (error) {
    // Error handling based on source
    if (options.source === 'mcp') {
      return {
        success: false,
        error: error.message
      };
    }
    
    console.error(chalk.red(`Error: ${error.message}`));
    process.exit(1);
  }
}

Task Master Core Update

// In mcp-server/src/core/task-master-core.js
import { newFeature } from '../../../scripts/modules/task-manager.js';

// Add to exports
export default {
  // ... existing functions
  
  async newFeature(args = {}, options = {}) {
    const { param1, param2 } = args;
    return executeFunction(newFeature, [param1, param2], options);
  }
};

Command Map Update

// In mcp-server/src/tools/utils.js
const commandMap = {
  // ... existing mappings
  'new-feature': 'newFeature'
};

Tool Implementation

// In mcp-server/src/tools/newFeature.js
import { z } from "zod";
import {
  executeTaskMasterCommand,
  createContentResponse,
  createErrorResponse,
} from "./utils.js";

export function registerNewFeatureTool(server) {
  server.addTool({
    name: "newFeature",
    description: "Run the new feature",
    parameters: z.object({
      param1: z.string().describe("First parameter"),
      param2: z.number().optional().describe("Second parameter"),
      file: z.string().optional().describe("Path to the tasks file"),
      projectRoot: z.string().describe("Root directory of the project")
    }),
    execute: async (args, { log }) => {
      try {
        log.info(`Running new feature with args: ${JSON.stringify(args)}`);

        const cmdArgs = [];
        if (args.param1) cmdArgs.push(`--param1=${args.param1}`);
        if (args.param2) cmdArgs.push(`--param2=${args.param2}`);
        if (args.file) cmdArgs.push(`--file=${args.file}`);

        const projectRoot = args.projectRoot;

        // Execute the command
        const result = await executeTaskMasterCommand(
          "new-feature",
          log,
          cmdArgs,
          projectRoot
        );

        if (!result.success) {
          throw new Error(result.error);
        }

        return createContentResponse(result.stdout);
      } catch (error) {
        log.error(`Error in new feature: ${error.message}`);
        return createErrorResponse(`Error in new feature: ${error.message}`);
      }
    },
  });
}

Tool Registration

// In mcp-server/src/tools/index.js
import { registerNewFeatureTool } from "./newFeature.js";

export function registerTaskMasterTools(server) {
  // ... existing registrations
  registerNewFeatureTool(server);
}

Testing

Always test your MCP-compatible features with both CLI and MCP interfaces:

// Test CLI usage
node scripts/dev.js new-feature --param1=test --param2=123

// Test MCP usage
node mcp-server/tests/test-command.js newFeature

Best Practices

  1. Keep Core Logic DRY - Share as much logic as possible between CLI and MCP
  2. Structured Data for MCP - Return clean JSON objects from MCP source functions
  3. Consistent Error Handling - Standardize error formats for both interfaces
  4. Documentation - Update MCP tool documentation when adding new features
  5. Testing - Test both CLI and MCP interfaces for any new or modified feature