# llms-full (private-aware)
> Built from GitHub files and website pages. Large files may be truncated.

--- llms-install.md ---
# Taskmaster AI Installation Guide

This guide helps AI assistants install and configure Taskmaster for users in their development projects.

## What is Taskmaster?

Taskmaster is an AI-driven task management system designed for development workflows. It helps break down projects into manageable tasks, track dependencies, and maintain development momentum through structured, AI-enhanced planning.

## Installation Steps

### Step 1: Add MCP Configuration

Add the following configuration to the user's MCP settings file (`.cursor/mcp.json` for Cursor, or equivalent for other editors):

```json
{
	"mcpServers": {
		"taskmaster-ai": {
			"command": "npx",
			"args": ["-y", "task-master-ai"],
			"env": {
				"ANTHROPIC_API_KEY": "user_will_add_their_key_here",
				"PERPLEXITY_API_KEY": "user_will_add_their_key_here",
				"OPENAI_API_KEY": "user_will_add_their_key_here",
				"GOOGLE_API_KEY": "user_will_add_their_key_here",
				"MISTRAL_API_KEY": "user_will_add_their_key_here",
				"OPENROUTER_API_KEY": "user_will_add_their_key_here",
				"XAI_API_KEY": "user_will_add_their_key_here"
			}
		}
	}
}
```

### Step 2: API Key Requirements

Inform the user they need **at least one** API key from the following providers:

- **Anthropic** (for Claude models) - Recommended
- **OpenAI** (for GPT models)
- **Google** (for Gemini models)
- **Perplexity** (for research features) - Highly recommended
- **Mistral** (for Mistral models)
- **OpenRouter** (access to multiple models)
- **xAI** (for Grok models)

The user will be able to define 3 separate roles (can be the same provider or separate providers) for main AI operations, research operations (research providers/models only), and a fallback model in case of errors.

### Step 3: Initialize Project

Once the MCP server is configured and API keys are added, initialize Taskmaster in the user's project:

> Can you initialize Task Master in my project?

This will run the `initialize_project` tool to set up the basic file structure.

### Step 4: Create Initial Tasks

Users have two options for creating initial tasks:

**Option A: Parse a PRD (Recommended)**
If they have a Product Requirements Document:

> Can you parse my PRD file at [path/to/prd.txt] to generate initial tasks?

If the user does not have a PRD, the AI agent can help them create one and store it in scripts/prd.txt for parsing.

**Option B: Start from scratch**

> Can you help me add my first task: [describe the task]

## Common Usage Patterns

### Daily Workflow

> What's the next task I should work on?
> Can you show me the details for task [ID]?
> Can you mark task [ID] as done?

### Task Management

> Can you break down task [ID] into subtasks?
> Can you add a new task: [description]
> Can you analyze the complexity of my tasks?

### Project Organization

> Can you show me all my pending tasks?
> Can you move task [ID] to become a subtask of [parent ID]?
> Can you update task [ID] with this new information: [details]

## Verification Steps

After installation, verify everything is working:

1. **Check MCP Connection**: The AI should be able to access Task Master tools
2. **Test Basic Commands**: Try `get_tasks` to list current tasks
3. **Verify API Keys**: Ensure AI-powered commands work (like `add_task`)

Note: An API key fallback exists that allows the MCP server to read API keys from `.env` instead of the MCP JSON config. It is recommended to have keys in both places in case the MCP server is unable to read keys from its environment for whatever reason.

When adding keys to `.env` only, the `models` tool will explain that the keys are not OK for MCP. Despite this, the fallback should kick in and the API keys will be read from the `.env` file.

## Troubleshooting

**If MCP server doesn't start:**

- Verify the JSON configuration is valid
- Check that Node.js is installed
- Ensure API keys are properly formatted

**If AI commands fail:**

- Verify at least one API key is configured
- Check API key permissions and quotas
- Try using a different model via the `models` tool

## CLI Fallback

Taskmaster is also available via CLI commands, by installing with `npm install task-master-ai@latest` in a terminal. Running `task-master help` will show all available commands, which offer a 1:1 experience with the MCP server. As the AI agent, you should refer to the system prompts and rules provided to you to identify Taskmaster-specific rules that help you understand how and when to use it.

## Next Steps

Once installed, users can:

- Create new tasks with `add-task` or parse a PRD (scripts/prd.txt) into tasks with `parse-prd`
- Set up model preferences with `models` tool
- Expand tasks into subtasks with `expand-all` and `expand-task`
- Explore advanced features like research mode and complexity analysis

For detailed documentation, refer to the Task Master docs directory.``


--- docs/README.md ---
# Task Master Documentation

Welcome to the Task Master documentation. Use the links below to navigate to the information you need:

## Getting Started

- [Configuration Guide](configuration.md) - Set up environment variables and customize Task Master
- [Tutorial](tutorial.md) - Step-by-step guide to getting started with Task Master

## Reference

- [Command Reference](command-reference.md) - Complete list of all available commands (including research and multi-task viewing)
- [Task Structure](task-structure.md) - Understanding the task format and features
- [Available Models](models.md) - Complete list of supported AI models and providers

## Examples & Licensing

- [Example Interactions](examples.md) - Common Cursor AI interaction examples  
- [Licensing Information](licensing.md) - Detailed information about the license

## Need More Help?

If you can't find what you're looking for in these docs, please check the [main README](../README.md) or visit our [GitHub repository](https://github.com/eyaltoledano/claude-task-master).


## Links discovered
- [Configuration Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/configuration.md)
- [Tutorial](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/tutorial.md)
- [Command Reference](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/command-reference.md)
- [Task Structure](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/task-structure.md)
- [Available Models](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/models.md)
- [Example Interactions](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/examples.md)
- [Licensing Information](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/licensing.md)
- [main README](https://github.com/eyaltoledano/claude-task-master/blob/main/README.md)
- [GitHub repository](https://github.com/eyaltoledano/claude-task-master)

--- .taskmaster/docs/README.md ---
# Meta-Development Script

This folder contains a **meta-development script** (`dev.js`) and related utilities that manage tasks for an AI-driven or traditional software development workflow. The script revolves around a `tasks.json` file, which holds an up-to-date list of development tasks.

## Overview

In an AI-driven development process—particularly with tools like [Cursor](https://www.cursor.so/)—it's beneficial to have a **single source of truth** for tasks. This script allows you to:

1. **Parse** a PRD or requirements document (`.txt`) to initialize a set of tasks (`tasks.json`).
2. **List** all existing tasks (IDs, statuses, titles).
3. **Update** tasks to accommodate new prompts or architecture changes (useful if you discover "implementation drift").
4. **Generate** individual task files (e.g., `task_001.txt`) for easy reference or to feed into an AI coding workflow.
5. **Set task status**—mark tasks as `done`, `pending`, or `deferred` based on progress.
6. **Expand** tasks with subtasks—break down complex tasks into smaller, more manageable subtasks.
7. **Research-backed subtask generation**—use Perplexity AI to generate more informed and contextually relevant subtasks.
8. **Clear subtasks**—remove subtasks from specified tasks to allow regeneration or restructuring.
9. **Show task details**—display detailed information about a specific task and its subtasks.

## Configuration

The script can be configured through environment variables in a `.env` file at the root of the project:

### Required Configuration

- `ANTHROPIC_API_KEY`: Your Anthropic API key for Claude

### Optional Configuration

- `MODEL`: Specify which Claude model to use (default: "claude-3-7-sonnet-20250219")
- `MAX_TOKENS`: Maximum tokens for model responses (default: 4000)
- `TEMPERATURE`: Temperature for model responses (default: 0.7)
- `PERPLEXITY_API_KEY`: Your Perplexity API key for research-backed subtask generation
- `PERPLEXITY_MODEL`: Specify which Perplexity model to use (default: "sonar-medium-online")
- `DEBUG`: Enable debug logging (default: false)
- `TASKMASTER_LOG_LEVEL`: Log level - debug, info, warn, error (default: info)
- `DEFAULT_SUBTASKS`: Default number of subtasks when expanding (default: 3)
- `DEFAULT_PRIORITY`: Default priority for generated tasks (default: medium)
- `PROJECT_NAME`: Override default project name in tasks.json
- `PROJECT_VERSION`: Override default version in tasks.json

## How It Works

1. **`tasks.json`**:

   - A JSON file at the project root containing an array of tasks (each with `id`, `title`, `description`, `status`, etc.).
   - The `meta` field can store additional info like the project's name, version, or reference to the PRD.
   - Tasks can have `subtasks` for more detailed implementation steps.
   - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending) to easily track progress.

2. **Script Commands**
   You can run the script via:

   ```bash
   node scripts/dev.js [command] [options]
   ```

   Available commands:

   - `parse-prd`: Generate tasks from a PRD document
   - `list`: Display all tasks with their status
   - `update`: Update tasks based on new information
   - `generate`: Create individual task files
   - `set-status`: Change a task's status
   - `expand`: Add subtasks to a task or all tasks
   - `clear-subtasks`: Remove subtasks from specified tasks
   - `next`: Determine the next task to work on based on dependencies
   - `show`: Display detailed information about a specific task

   Run `node scripts/dev.js` without arguments to see detailed usage information.

## Listing Tasks

The `list` command allows you to view all tasks and their status:

```bash
# List all tasks
node scripts/dev.js list

# List tasks with a specific status
node scripts/dev.js list --status=pending

# List tasks and include their subtasks
node scripts/dev.js list --with-subtasks

# List tasks with a specific status and include their subtasks
node scripts/dev.js list --status=pending --with-subtasks
```

## Updating Tasks

The `update` command allows you to update tasks based on new information or implementation changes:

```bash
# Update tasks starting from ID 4 with a new prompt
node scripts/dev.js update --from=4 --prompt="Refactor tasks from ID 4 onward to use Express instead of Fastify"

# Update all tasks (default from=1)
node scripts/dev.js update --prompt="Add authentication to all relevant tasks"

# With research-backed updates using Perplexity AI
node scripts/dev.js update --from=4 --prompt="Integrate OAuth 2.0" --research

# Specify a different tasks file
node scripts/dev.js update --file=custom-tasks.json --from=5 --prompt="Change database from MongoDB to PostgreSQL"
```

Notes:

- The `--prompt` parameter is required and should explain the changes or new context
- Only tasks that aren't marked as 'done' will be updated
- Tasks with ID >= the specified --from value will be updated
- The `--research` flag uses Perplexity AI for more informed updates when available

## Updating a Single Task

The `update-task` command allows you to update a specific task instead of multiple tasks:

```bash
# Update a specific task with new information
node scripts/dev.js update-task --id=4 --prompt="Use JWT for authentication"

# With research-backed updates using Perplexity AI
node scripts/dev.js update-task --id=4 --prompt="Use JWT for authentication" --research
```

This command:

- Updates only the specified task rather than a range of tasks
- Provides detailed validation with helpful error messages
- Checks for required API keys when using research mode
- Falls back gracefully if Perplexity API is unavailable
- Preserves tasks that are already marked as "done"
- Includes contextual error handling for common issues

## Setting Task Status

The `set-status` command allows you to change a task's status:

```bash
# Mark a task as done
node scripts/dev.js set-status --id=3 --status=done

# Mark a task as pending
node scripts/dev.js set-status --id=4 --status=pending

# Mark a specific subtask as done
node scripts/dev.js set-status --id=3.1 --status=done

# Mark multiple tasks at once
node scripts/dev.js set-status --id=1,2,3 --status=done
```

Notes:

- When marking a parent task as "done", all of its subtasks will automatically be marked as "done" as well
- Common status values are 'done', 'pending', and 'deferred', but any string is accepted
- You can specify multiple task IDs by separating them with commas
- Subtask IDs are specified using the format `parentId.subtaskId` (e.g., `3.1`)
- Dependencies are updated to show completion status (✅ for completed, ⏱️ for pending) throughout the system

## Expanding Tasks

The `expand` command allows you to break down tasks into subtasks for more detailed implementation:

```bash
# Expand a specific task with 3 subtasks (default)
node scripts/dev.js expand --id=3

# Expand a specific task with 5 subtasks
node scripts/dev.js expand --id=3 --num=5

# Expand a task with additional context
node scripts/dev.js expand --id=3 --prompt="Focus on security aspects"

# Expand all pending tasks that don't have subtasks
node scripts/dev.js expand --all

# Force regeneration of subtasks for all pending tasks
node scripts/dev.js expand --all --force

# Use Perplexity AI for research-backed subtask generation
node scripts/dev.js expand --id=3 --research

# Use Perplexity AI for research-backed generation on all pending tasks
node scripts/dev.js expand --all --research
```

## Clearing Subtasks

The `clear-subtasks` command allows you to remove subtasks from specified tasks:

```bash
# Clear subtasks from a specific task
node scripts/dev.js clear-subtasks --id=3

# Clear subtasks from multiple tasks
node scripts/dev.js clear-subtasks --id=1,2,3

# Clear subtasks from all tasks
node scripts/dev.js clear-subtasks --all
```

Notes:

- After clearing subtasks, task files are automatically regenerated
- This is useful when you want to regenerate subtasks with a different approach
- Can be combined with the `expand` command to immediately generate new subtasks
- Works with both parent tasks and individual subtasks

## AI Integration

The script integrates with two AI services:

1. **Anthropic Claude**: Used for parsing PRDs, generating tasks, and creating subtasks.
2. **Perplexity AI**: Used for research-backed subtask generation when the `--research` flag is specified.

The Perplexity integration uses the OpenAI client to connect to Perplexity's API, which provides enhanced research capabilities for generating more informed subtasks. If the Perplexity API is unavailable or encounters an error, the script will automatically fall back to using Anthropic's Claude.

To use the Perplexity integration:

1. Obtain a Perplexity API key
2. Add `PERPLEXITY_API_KEY` to your `.env` file
3. Optionally specify `PERPLEXITY_MODEL` in your `.env` file (default: "sonar-medium-online")
4. Use the `--research` flag with the `expand` command

## Logging

The script supports different logging levels controlled by the `TASKMASTER_LOG_LEVEL` environment variable:

- `debug`: Detailed information, typically useful for troubleshooting
- `info`: Confirmation that things are working as expected (default)
- `warn`: Warning messages that don't prevent execution
- `error`: Error messages that might prevent execution

When `DEBUG=true` is set, debug logs are also written to a `dev-debug.log` file in the project root.

## Managing Task Dependencies

The `add-dependency` and `remove-dependency` commands allow you to manage task dependencies:

```bash
# Add a dependency to a task
node scripts/dev.js add-dependency --id=<id> --depends-on=<id>

# Remove a dependency from a task
node scripts/dev.js remove-dependency --id=<id> --depends-on=<id>
```

These commands:

1. **Allow precise dependency management**:

   - Add dependencies between tasks with automatic validation
   - Remove dependencies when they're no longer needed
   - Update task files automatically after changes

2. **Include validation checks**:

   - Prevent circular dependencies (a task depending on itself)
   - Prevent duplicate dependencies
   - Verify that both tasks exist before adding/removing dependencies
   - Check if dependencies exist before attempting to remove them

3. **Provide clear feedback**:

   - Success messages confirm when dependencies are added/removed
   - Error messages explain why operations failed (if applicable)

4. **Automatically update task files**:
   - Regenerates task files to reflect dependency changes
   - Ensures tasks and their files stay synchronized

## Dependency Validation and Fixing

The script provides two specialized commands to ensure task dependencies remain valid and properly maintained:

### Validating Dependencies

The `validate-dependencies` command allows you to check for invalid dependencies without making changes:

```bash
# Check for invalid dependencies in tasks.json
node scripts/dev.js validate-dependencies

# Specify a different tasks file
node scripts/dev.js validate-dependencies --file=custom-tasks.json
```

This command:

- Scans all tasks and subtasks for non-existent dependencies
- Identifies potential self-dependencies (tasks referencing themselves)
- Reports all found issues without modifying files
- Provides a comprehensive summary of dependency state
- Gives detailed statistics on task dependencies

Use this command to audit your task structure before applying fixes.

### Fixing Dependencies

The `fix-dependencies` command proactively finds and fixes all invalid dependencies:

```bash
# Find and fix all invalid dependencies
node scripts/dev.js fix-dependencies

# Specify a different tasks file
node scripts/dev.js fix-dependencies --file=custom-tasks.json
```

This command:

1. **Validates all dependencies** across tasks and subtasks
2. **Automatically removes**:
   - References to non-existent tasks and subtasks
   - Self-dependencies (tasks depending on themselves)
3. **Fixes issues in both**:
   - The tasks.json data structure
   - Individual task files during regeneration
4. **Provides a detailed report**:
   - Types of issues fixed (non-existent vs. self-dependencies)
   - Number of tasks affected (tasks vs. subtasks)
   - Where fixes were applied (tasks.json vs. task files)
   - List of all individual fixes made

This is especially useful when tasks have been deleted or IDs have changed, potentially breaking dependency chains.

## Analyzing Task Complexity

The `analyze-complexity` command allows you to automatically assess task complexity and generate expansion recommendations:

```bash
# Analyze all tasks and generate expansion recommendations
node scripts/dev.js analyze-complexity

# Specify a custom output file
node scripts/dev.js analyze-complexity --output=custom-report.json

# Override the model used for analysis
node scripts/dev.js analyze-complexity --model=claude-3-opus-20240229

# Set a custom complexity threshold (1-10)
node scripts/dev.js analyze-complexity --threshold=6

# Use Perplexity AI for research-backed complexity analysis
node scripts/dev.js analyze-complexity --research
```

Notes:

- The command uses Claude to analyze each task's complexity (or Perplexity with --research flag)
- Tasks are scored on a scale of 1-10
- Each task receives a recommended number of subtasks based on DEFAULT_SUBTASKS configuration
- The default output path is `scripts/task-complexity-report.json`
- Each task in the analysis includes a ready-to-use `expansionCommand` that can be copied directly to the terminal or executed programmatically
- Tasks with complexity scores below the threshold (default: 5) may not need expansion
- The research flag provides more contextual and informed complexity assessments

### Integration with Expand Command

The `expand` command automatically checks for and uses complexity analysis if available:

```bash
# Expand a task, using complexity report recommendations if available
node scripts/dev.js expand --id=8

# Expand all tasks, prioritizing by complexity score if a report exists
node scripts/dev.js expand --all

# Override recommendations with explicit values
node scripts/dev.js expand --id=8 --num=5 --prompt="Custom prompt"
```

When a complexity report exists:

- The `expand` command will use the recommended subtask count from the report (unless overridden)
- It will use the tailored expansion prompt from the report (unless a custom prompt is provided)
- When using `--all`, tasks are sorted by complexity score (highest first)
- The `--research` flag is preserved from the complexity analysis to expansion

The output report structure is:

```json
{
 "meta": {
  "generatedAt": "2023-06-15T12:34:56.789Z",
  "tasksAnalyzed": 20,
  "thresholdScore": 5,
  "projectName": "Your Project Name",
  "usedResearch": true
 },
 "complexityAnalysis": [
  {
   "taskId": 8,
   "taskTitle": "Develop Implementation Drift Handling",
   "complexityScore": 9.5,
   "recommendedSubtasks": 6,
   "expansionPrompt": "Create subtasks that handle detecting...",
   "reasoning": "This task requires sophisticated logic...",
   "expansionCommand": "node scripts/dev.js expand --id=8 --num=6 --prompt=\"Create subtasks...\" --research"
  }
  // More tasks sorted by complexity score (highest first)
 ]
}
```

## Finding the Next Task

The `next` command helps you determine which task to work on next based on dependencies and status:

```bash
# Show the next task to work on
node scripts/dev.js next

# Specify a different tasks file
node scripts/dev.js next --file=custom-tasks.json
```

This command:

1. Identifies all **eligible tasks** - pending or in-progress tasks whose dependencies are all satisfied (marked as done)
2. **Prioritizes** these eligible tasks by:
   - Priority level (high > medium > low)
   - Number of dependencies (fewer dependencies first)
   - Task ID (lower ID first)
3. **Displays** comprehensive information about the selected task:
   - Basic task details (ID, title, priority, dependencies)
   - Detailed description and implementation details
   - Subtasks if they exist
4. Provides **contextual suggested actions**:
   - Command to mark the task as in-progress
   - Command to mark the task as done when completed
   - Commands for working with subtasks (update status or expand)

This feature ensures you're always working on the most appropriate task based on your project's current state and dependency structure.

## Showing Task Details

The `show` command allows you to view detailed information about a specific task:

```bash
# Show details for a specific task
node scripts/dev.js show 1

# Alternative syntax with --id option
node scripts/dev.js show --id=1

# Show details for a subtask
node scripts/dev.js show --id=1.2

# Specify a different tasks file
node scripts/dev.js show 3 --file=custom-tasks.json
```

This command:

1. **Displays comprehensive information** about the specified task:
   - Basic task details (ID, title, priority, dependencies, status)
   - Full description and implementation details
   - Test strategy information
   - Subtasks if they exist
2. **Handles both regular tasks and subtasks**:
   - For regular tasks, shows all subtasks and their status
   - For subtasks, shows the parent task relationship
3. **Provides contextual suggested actions**:
   - Commands to update the task status
   - Commands for working with subtasks
   - For subtasks, provides a link to view the parent task

This command is particularly useful when you need to examine a specific task in detail before implementing it or when you want to check the status and details of a particular task.

## Enhanced Error Handling

The script now includes improved error handling throughout all commands:

1. **Detailed Validation**:

   - Required parameters (like task IDs and prompts) are validated early
   - File existence is checked with customized errors for common scenarios
   - Parameter type conversion is handled with clear error messages

2. **Contextual Error Messages**:

   - Task not found errors include suggestions to run the list command
   - API key errors include reminders to check environment variables
   - Invalid ID format errors show the expected format

3. **Command-Specific Help Displays**:

   - When validation fails, detailed help for the specific command is shown
   - Help displays include usage examples and parameter descriptions
   - Formatted in clear, color-coded boxes with examples

4. **Helpful Error Recovery**:
   - Detailed troubleshooting steps for common errors
   - Graceful fallbacks for missing optional dependencies
   - Clear instructions for how to fix configuration issues

## Version Checking

The script now automatically checks for updates without slowing down execution:

1. **Background Version Checking**:

   - Non-blocking version checks run in the background while commands execute
   - Actual command execution isn't delayed by version checking
   - Update notifications appear after command completion

2. **Update Notifications**:

   - When a newer version is available, a notification is displayed
   - Notifications include current version, latest version, and update command
   - Formatted in an attention-grabbing box with clear instructions

3. **Implementation Details**:
   - Uses semantic versioning to compare current and latest versions
   - Fetches version information from npm registry with a timeout
   - Gracefully handles connection issues without affecting command execution

## Subtask Management

The script now includes enhanced commands for managing subtasks:

### Adding Subtasks

```bash
# Add a subtask to an existing task
node scripts/dev.js add-subtask --parent=5 --title="Implement login UI" --description="Create login form"

# Convert an existing task to a subtask
node scripts/dev.js add-subtask --parent=5 --task-id=8

# Add a subtask with dependencies
node scripts/dev.js add-subtask --parent=5 --title="Authentication middleware" --dependencies=5.1,5.2

# Skip regenerating task files
node scripts/dev.js add-subtask --parent=5 --title="Login API route" --skip-generate
```

Key features:

- Create new subtasks with detailed properties or convert existing tasks
- Define dependencies between subtasks
- Set custom status for new subtasks
- Provides next-step suggestions after creation

### Removing Subtasks

```bash
# Remove a subtask
node scripts/dev.js remove-subtask --id=5.2

# Remove multiple subtasks
node scripts/dev.js remove-subtask --id=5.2,5.3,5.4

# Convert a subtask to a standalone task
node scripts/dev.js remove-subtask --id=5.2 --convert

# Skip regenerating task files
node scripts/dev.js remove-subtask --id=5.2 --skip-generate
```

Key features:

- Remove subtasks individually or in batches
- Optionally convert subtasks to standalone tasks
- Control whether task files are regenerated
- Provides detailed success messages and next steps


## Links discovered
- [Cursor](https://www.cursor.so/)

--- apps/docs/README.md ---
# Task Master Documentation

Welcome to the Task Master documentation. This documentation site provides comprehensive guides for getting started with Task Master.

## Getting Started

- [Quick Start Guide](/getting-started/quick-start) - Complete setup and first-time usage guide
- [Requirements](/getting-started/quick-start/requirements) - What you need to get started
- [Installation](/getting-started/quick-start/installation) - How to install Task Master

## Core Capabilities

- [MCP Tools](/capabilities/mcp) - Model Control Protocol integration
- [CLI Commands](/capabilities/cli-root-commands) - Command line interface reference
- [Task Structure](/capabilities/task-structure) - Understanding tasks and subtasks

## Best Practices

- [Advanced Configuration](/best-practices/configuration-advanced) - Detailed configuration options
- [Advanced Tasks](/best-practices/advanced-tasks) - Working with complex task structures

## Need More Help?

If you can't find what you're looking for in these docs, please check the root README.md or visit our [GitHub repository](https://github.com/eyaltoledano/claude-task-master).


## Links discovered
- [Quick Start Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/getting-started/quick-start.md)
- [Requirements](https://github.com/eyaltoledano/claude-task-master/blob/main/getting-started/quick-start/requirements.md)
- [Installation](https://github.com/eyaltoledano/claude-task-master/blob/main/getting-started/quick-start/installation.md)
- [MCP Tools](https://github.com/eyaltoledano/claude-task-master/blob/main/capabilities/mcp.md)
- [CLI Commands](https://github.com/eyaltoledano/claude-task-master/blob/main/capabilities/cli-root-commands.md)
- [Task Structure](https://github.com/eyaltoledano/claude-task-master/blob/main/capabilities/task-structure.md)
- [Advanced Configuration](https://github.com/eyaltoledano/claude-task-master/blob/main/best-practices/configuration-advanced.md)
- [Advanced Tasks](https://github.com/eyaltoledano/claude-task-master/blob/main/best-practices/advanced-tasks.md)
- [GitHub repository](https://github.com/eyaltoledano/claude-task-master)

--- apps/docs/getting-started/api-keys.mdx ---
# API Keys Configuration

Task Master supports multiple AI providers through environment variables. This page lists all available API keys and their configuration requirements.

## Required API Keys

> **Note**: At least one required API key must be configured for Task Master to function.
>
> "Required: Yes" below means "required to use that specific provider," not "required globally." You only need at least one provider configured.

### ANTHROPIC_API_KEY (Recommended)
- **Provider**: Anthropic Claude models
- **Format**: `sk-ant-api03-...`
- **Required**: ✅ **Yes**
- **Models**: Claude 3.5 Sonnet, Claude 3 Haiku, Claude 3 Opus
- **Get Key**: [Anthropic Console](https://console.anthropic.com/)

```bash
ANTHROPIC_API_KEY="sk-ant-api03-your-key-here"
```

### PERPLEXITY_API_KEY (Highly Recommended for Research)
- **Provider**: Perplexity AI (Research features)
- **Format**: `pplx-...`
- **Required**: ✅ **Yes**
- **Purpose**: Enables research-backed task expansions and updates
- **Models**: Perplexity Sonar models
- **Get Key**: [Perplexity API](https://www.perplexity.ai/settings/api)

```bash
PERPLEXITY_API_KEY="pplx-your-key-here"
```

### OPENAI_API_KEY
- **Provider**: OpenAI GPT models
- **Format**: `sk-proj-...` or `sk-...`
- **Required**: ✅ **Yes**
- **Models**: GPT-4, GPT-4 Turbo, GPT-3.5 Turbo, O1 models
- **Get Key**: [OpenAI Platform](https://platform.openai.com/api-keys)

```bash
OPENAI_API_KEY="sk-proj-your-key-here"
```

### GOOGLE_API_KEY
- **Provider**: Google Gemini models
- **Format**: Various formats
- **Required**: ✅ **Yes**
- **Models**: Gemini Pro, Gemini Flash, Gemini Ultra
- **Get Key**: [Google AI Studio](https://aistudio.google.com/app/apikey)
- **Alternative**: Use `GOOGLE_APPLICATION_CREDENTIALS` for service account (Google Vertex)

```bash
GOOGLE_API_KEY="your-google-api-key-here"
```

### GROQ_API_KEY
- **Provider**: Groq (High-performance inference)
- **Required**: ✅ **Yes**
- **Models**: Llama models, Mixtral models (via Groq)
- **Get Key**: [Groq Console](https://console.groq.com/keys)

```bash
GROQ_API_KEY="your-groq-key-here"
```

### OPENROUTER_API_KEY
- **Provider**: OpenRouter (Multiple model access)
- **Required**: ✅ **Yes**
- **Models**: Access to various models through single API
- **Get Key**: [OpenRouter](https://openrouter.ai/keys)

```bash
OPENROUTER_API_KEY="your-openrouter-key-here"
```

### AZURE_OPENAI_API_KEY
- **Provider**: Azure OpenAI Service
- **Required**: ✅ **Yes**
- **Requirements**: Also requires `AZURE_OPENAI_ENDPOINT` configuration
- **Models**: GPT models via Azure
- **Get Key**: [Azure Portal](https://portal.azure.com/)

```bash
AZURE_OPENAI_API_KEY="your-azure-key-here"
```

### XAI_API_KEY
- **Provider**: xAI (Grok) models
- **Required**: ✅ **Yes**
- **Models**: Grok models
- **Get Key**: [xAI Console](https://console.x.ai/)

```bash
XAI_API_KEY="your-xai-key-here"
```

## Optional API Keys

> **Note**: These API keys are optional - providers will work without them or use alternative authentication methods.

### AWS_ACCESS_KEY_ID (Bedrock)
- **Provider**: AWS Bedrock
- **Required**: ❌ **No** (uses AWS credential chain)
- **Models**: Claude models via AWS Bedrock
- **Authentication**: Uses AWS credential chain (profiles, IAM roles, etc.)
- **Get Key**: [AWS Console](https://console.aws.amazon.com/iam/)

```bash
# Optional - AWS credential chain is preferred
AWS_ACCESS_KEY_ID="your-aws-access-key"
AWS_SECRET_ACCESS_KEY="your-aws-secret-key"
```

### CLAUDE_CODE_API_KEY
- **Provider**: Claude Code CLI
- **Required**: ❌ **No** (uses OAuth tokens)
- **Purpose**: Integration with local Claude Code CLI
- **Authentication**: Uses OAuth tokens, no API key needed

```bash
# Not typically needed
CLAUDE_CODE_API_KEY="not-usually-required"
```

### GEMINI_API_KEY
- **Provider**: Gemini CLI
- **Required**: ❌ **No** (uses OAuth authentication)
- **Purpose**: Integration with Gemini CLI
- **Authentication**: Primarily uses OAuth via CLI, API key is optional

```bash
# Optional - OAuth via CLI is preferred
GEMINI_API_KEY="your-gemini-key-here"
```

### GROK_CLI_API_KEY
- **Provider**: Grok CLI
- **Required**: ❌ **No** (can use CLI config)
- **Purpose**: Integration with Grok CLI
- **Authentication**: Can use Grok CLI's own config file

```bash
# Optional - CLI config is preferred
GROK_CLI_API_KEY="your-grok-cli-key"
```

### OLLAMA_API_KEY
- **Provider**: Ollama (Local/Remote)
- **Required**: ❌ **No** (local installation doesn't need key)
- **Purpose**: For remote Ollama servers that require authentication
- **Requirements**: Only needed for remote servers with authentication
- **Note**: Not needed for local Ollama installations

```bash
# Only needed for remote Ollama servers
OLLAMA_API_KEY="your-ollama-api-key-here"
```

### GITHUB_API_KEY
- **Provider**: GitHub (Import/Export features)
- **Format**: `ghp_...` or `github_pat_...`
- **Required**: ❌ **No** (for GitHub features only)
- **Purpose**: GitHub import/export features
- **Get Key**: [GitHub Settings](https://github.com/settings/tokens)

```bash
GITHUB_API_KEY="ghp-your-github-key-here"
```

## Configuration Methods

### Method 1: Environment File (.env)
Create a `.env` file in your project root:

```bash
# Copy from .env.example
cp .env.example .env

# Edit with your keys
vim .env
```

### Method 2: System Environment Variables
```bash
export ANTHROPIC_API_KEY="your-key-here"
export PERPLEXITY_API_KEY="your-key-here"
# ... other keys
```

### Method 3: MCP Server Configuration
For Claude Code integration, configure keys in `.mcp.json`:

```json
{
  "mcpServers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        "ANTHROPIC_API_KEY": "your-key-here",
        "PERPLEXITY_API_KEY": "your-key-here",
        "OPENAI_API_KEY": "your-key-here"
      }
    }
  }
}
```

## Key Requirements

### Minimum Requirements
- **At least one** AI provider key is required
- **ANTHROPIC_API_KEY** is recommended as the primary provider
- **PERPLEXITY_API_KEY** is highly recommended for research features

### Provider-Specific Requirements
- **Azure OpenAI**: Requires both `AZURE_OPENAI_API_KEY` and `AZURE_OPENAI_ENDPOINT` configuration
- **Google Vertex**: Requires `VERTEX_PROJECT_ID` and `VERTEX_LOCATION` environment variables
- **AWS Bedrock**: Uses AWS credential chain (profiles, IAM roles, etc.) instead of API keys
- **Ollama**: Only needs API key for remote servers with authentication
- **CLI Providers**: Gemini CLI, Grok CLI, and Claude Code use OAuth/CLI config instead of API keys

## Model Configuration

After setting up API keys, configure which models to use:

```bash
# Interactive model setup
task-master models --setup

# Set specific models
task-master models --set-main claude-3-5-sonnet-20241022
task-master models --set-research perplexity-llama-3.1-sonar-large-128k-online
task-master models --set-fallback gpt-4o-mini
```

## Security Best Practices

1. **Never commit API keys** to version control
2. **Use .env files** and add them to `.gitignore`
3. **Rotate keys regularly** especially if compromised
4. **Use minimal permissions** for service accounts
5. **Monitor usage** to detect unauthorized access

## Troubleshooting

### Key Validation
```bash
# Check if keys are properly configured
task-master models

# Test specific provider
task-master add-task --prompt="test task" --model=claude-3-5-sonnet-20241022
```

### Common Issues
- **Invalid key format**: Check the expected format for each provider
- **Insufficient permissions**: Ensure keys have necessary API access
- **Rate limits**: Some providers have usage limits
- **Regional restrictions**: Some models may not be available in all regions

### Getting Help
If you encounter issues with API key configuration:
- Check the [FAQ](/getting-started/faq) for common solutions
- Join our [Discord community](https://discord.gg/fWJkU7rf) for support
- Report issues on [GitHub](https://github.com/eyaltoledano/claude-task-master/issues)

## Links discovered
- [Anthropic Console](https://console.anthropic.com/)
- [Perplexity API](https://www.perplexity.ai/settings/api)
- [OpenAI Platform](https://platform.openai.com/api-keys)
- [Google AI Studio](https://aistudio.google.com/app/apikey)
- [Groq Console](https://console.groq.com/keys)
- [OpenRouter](https://openrouter.ai/keys)
- [Azure Portal](https://portal.azure.com/)
- [xAI Console](https://console.x.ai/)
- [AWS Console](https://console.aws.amazon.com/iam/)
- [GitHub Settings](https://github.com/settings/tokens)
- [FAQ](https://github.com/eyaltoledano/claude-task-master/blob/main/getting-started/faq.md)
- [Discord community](https://discord.gg/fWJkU7rf)
- [GitHub](https://github.com/eyaltoledano/claude-task-master/issues)

--- apps/docs/getting-started/contribute.mdx ---
# Contributing to Task Master

Thank you for your interest in contributing to Task Master! We're excited to work with you and appreciate your help in making this project better. 🚀

## 🤝 Our Collaborative Approach

We're a **PR-friendly team** that values collaboration:

- ✅ **We review PRs quickly** - Usually within hours, not days
- ✅ **We're super reactive** - Expect fast feedback and engagement
- ✅ **We sometimes take over PRs** - If your contribution is valuable but needs cleanup, we might jump in to help finish it
- ✅ **We're open to all contributions** - From bug fixes to major features

**We don't mind AI-generated code**, but we do expect you to:

- ✅ **Review and understand** what the AI generated
- ✅ **Test the code thoroughly** before submitting
- ✅ **Ensure it's well-written** and follows our patterns
- ❌ **Don't submit "AI slop"** - untested, unreviewed AI output

> **Why this matters**: We spend significant time reviewing PRs. Help us help you by submitting quality contributions that save everyone time!

## 🚀 Quick Start for Contributors

### 1. Fork and Clone

```bash
git clone https://github.com/YOUR_USERNAME/claude-task-master.git
cd claude-task-master
npm install
```

### 2. Create a Feature Branch

**Important**: Always target the `next` branch, not `main`:

```bash
git checkout next
git pull origin next
git checkout -b feature/your-feature-name
```

### 3. Make Your Changes

Follow our development guidelines below.

### 4. Test Everything Yourself

**Before submitting your PR**, ensure:

```bash
# Run all tests
npm test

# Check formatting
npm run format-check

# Fix formatting if needed
npm run format
```

### 5. Create a Changeset

**Required for most changes**:

```bash
npm run changeset
```

See the [Changeset Guidelines](#changeset-guidelines) below for details.

### 6. Submit Your PR

- Target the `next` branch
- Write a clear description
- Reference any related issues

## 📋 Development Guidelines

### Branch Strategy

- **`main`**: Production-ready code
- **`next`**: Development branch - **target this for PRs**
- **Feature branches**: `feature/description` or `fix/description`

### Code Quality Standards

1. **Write tests** for new functionality
2. **Follow existing patterns** in the codebase
3. **Add JSDoc comments** for functions
4. **Keep functions focused** and single-purpose

### Testing Requirements

Your PR **must pass all CI checks**:

- ✅ **Unit tests**: `npm test`
- ✅ **Format check**: `npm run format-check`

**Test your changes locally first** - this saves review time and shows you care about quality.

## 📦 Changeset Guidelines

We use [Changesets](https://github.com/changesets/changesets) to manage versioning and generate changelogs.

### When to Create a Changeset

**Always create a changeset for**:

- ✅ New features
- ✅ Bug fixes
- ✅ Breaking changes
- ✅ Performance improvements
- ✅ User-facing documentation updates
- ✅ Dependency updates that affect functionality

**Skip changesets for**:

- ❌ Internal documentation only
- ❌ Test-only changes
- ❌ Code formatting/linting
- ❌ Development tooling that doesn't affect users

### How to Create a Changeset

1. **After making your changes**:

   ```bash
   npm run changeset
   ```

2. **Choose the bump type**:

   - **Major**: Breaking changes
   - **Minor**: New features
   - **Patch**: Bug fixes, docs, performance improvements

3. **Write a clear summary**:

   ```
   Add support for custom AI models in MCP configuration
   ```

4. **Commit the changeset file** with your changes:
   ```bash
   git add .changeset/*.md
   git commit -m "feat: add custom AI model support"
   ```

### Changeset vs Git Commit Messages

- **Changeset summary**: User-facing, goes in CHANGELOG.md
- **Git commit**: Developer-facing, explains the technical change

Example:

```bash
# Changeset summary (user-facing)
"Add support for custom Ollama models"

# Git commit message (developer-facing)
"feat(models): implement custom Ollama model validation

- Add model validation for custom Ollama endpoints
- Update configuration schema to support custom models
- Add tests for new validation logic"
```

## 🔧 Development Setup

### Prerequisites

- Node.js 20+
- npm or yarn

### Environment Setup

1. **Copy environment template**:

   ```bash
   cp .env.example .env
   ```

2. **Add your API keys** (for testing AI features):
   ```bash
   ANTHROPIC_API_KEY=your_key_here
   OPENAI_API_KEY=your_key_here
   # Add others as needed
   ```

### Running Tests

```bash
# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run with coverage
npm run test:coverage

# Run E2E tests
npm run test:e2e
```

### Code Formatting

We use Prettier for consistent formatting:

```bash
# Check formatting
npm run format-check

# Fix formatting
npm run format
```

## 📝 PR Guidelines

### Before Submitting

- [ ] **Target the `next` branch**
- [ ] **Test everything locally**
- [ ] **Run the full test suite**
- [ ] **Check code formatting**
- [ ] **Create a changeset** (if needed)
- [ ] **Re-read your changes** - ensure they're clean and well-thought-out

### PR Description Template

```markdown
## Description

Brief description of what this PR does.

## Type of Change

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing

- [ ] I have tested this locally
- [ ] All existing tests pass
- [ ] I have added tests for new functionality

## Changeset

- [ ] I have created a changeset (or this change doesn't need one)

## Additional Notes

Any additional context or notes for reviewers.
```

### What We Look For

✅ **Good PRs**:

- Clear, focused changes
- Comprehensive testing
- Good commit messages
- Proper changeset (when needed)
- Self-reviewed code

❌ **Avoid**:

- Massive PRs that change everything
- Untested code
- Formatting issues
- Missing changesets for user-facing changes
- AI-generated code that wasn't reviewed

## 🏗️ Project Structure

```
claude-task-master/
├── bin/                    # CLI executables
├── mcp-server/            # MCP server implementation
├── scripts/               # Core task management logic
├── src/                   # Shared utilities and providers and well refactored code (we are slowly moving everything here)
├── tests/                 # Test files
├── docs/                  # Documentation
└── .cursor/               # Cursor IDE rules and configuration
└── assets/							   # Assets like rules and configuration for all IDEs
```

### Key Areas for Contribution

- **CLI Commands**: `scripts/modules/commands.js`
- **MCP Tools**: `mcp-server/src/tools/`
- **Core Logic**: `scripts/modules/task-manager/`
- **AI Providers**: `src/ai-providers/`
- **Tests**: `tests/`

## 🐛 Reporting Issues

### Bug Reports

Include:

- Task Master version
- Node.js version
- Operating system
- Steps to reproduce
- Expected vs actual behavior
- Error messages/logs

### Feature Requests

Include:

- Clear description of the feature
- Use case/motivation
- Proposed implementation (if you have ideas)
- Willingness to contribute

## 💬 Getting Help

- **Discord**: [Join our community](https://discord.gg/taskmasterai)
- **Issues**: [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- **Discussions**: [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

## 📄 License

By contributing, you agree that your contributions will be licensed under the same license as the project (MIT with Commons Clause).

---

**Thank you for contributing to Task Master!** 🎉

Your contributions help make AI-driven development more accessible and efficient for everyone.

## Links discovered
- [Changesets](https://github.com/changesets/changesets)
- [Join our community](https://discord.gg/taskmasterai)
- [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

--- apps/docs/getting-started/faq.mdx ---
---
title: FAQ
sidebarTitle: "FAQ"
---

Coming soon. 

## 💬 Getting Help

- **Discord**: [Join our community](https://discord.gg/taskmasterai)
- **Issues**: [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- **Discussions**: [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

## Links discovered
- [Join our community](https://discord.gg/taskmasterai)
- [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

--- packages/claude-code-plugin/commands/install-taskmaster.md ---
Check if Task Master is installed and install it if needed.

This command helps you get Task Master set up globally on your system.

## Detection and Installation Process

1. **Check Current Installation**
   ```bash
   # Check if task-master command exists
   which task-master || echo "Task Master not found"
   
   # Check npm global packages
   npm list -g task-master-ai
   ```

2. **System Requirements Check**
   ```bash
   # Verify Node.js is installed
   node --version
   
   # Verify npm is installed  
   npm --version
   
   # Check Node version (need 16+)
   ```

3. **Install Task Master Globally**
   If not installed, run:
   ```bash
   npm install -g task-master-ai
   ```

4. **Verify Installation**
   ```bash
   # Check version
   task-master --version
   
   # Verify command is available
   which task-master
   ```

5. **Initial Setup**
   ```bash
   # Initialize in current directory
   task-master init
   ```

6. **Configure AI Provider**
   Ensure you have at least one AI provider API key set:
   ```bash
   # Check current configuration
   task-master models --status
   
   # If no API keys found, guide setup
   echo "You'll need at least one API key:"
   echo "- ANTHROPIC_API_KEY for Claude"
   echo "- OPENAI_API_KEY for GPT models"
   echo "- PERPLEXITY_API_KEY for research"
   echo ""
   echo "Set them in your shell profile or .env file"
   ```

7. **Quick Test**
   ```bash
   # Create a test PRD
   echo "Build a simple hello world API" > test-prd.txt
   
   # Try parsing it
   task-master parse-prd test-prd.txt -n 3
   ```

## Troubleshooting

If installation fails:

**Permission Errors:**
```bash
# Try with sudo (macOS/Linux)
sudo npm install -g task-master-ai

# Or fix npm permissions
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
```

**Network Issues:**
```bash
# Use different registry
npm install -g task-master-ai --registry https://registry.npmjs.org/
```

**Node Version Issues:**
```bash
# Install Node 20+ via nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 20
nvm use 20
```

## Success Confirmation

Once installed, you should see:
```
✅ Task Master v0.16.2 (or higher) installed
✅ Command 'task-master' available globally
✅ AI provider configured
✅ Ready to use slash commands!

Try: /project:task-master:init your-prd.md
```

## Next Steps

After installation:
1. Run `/project:utils:check-health` to verify setup
2. Configure AI providers with `/project:task-master:models`
3. Start using Task Master commands!

--- apps/docs/archive/Installation.mdx ---
---
title: "Installation(2)"
description: "This guide walks you through setting up Task Master in your development environment."
---

## Initial Setup

<Tip>
  MCP (Model Control Protocol) provides the easiest way to get started with Task Master directly in your editor.
</Tip>

<AccordionGroup>
  <Accordion title="Option 1: Using MCP (Recommended)" icon="sparkles">
    <Steps>
      <Step title="Add the MCP config to your editor">
        <Link href="https://cursor.sh">Cursor</Link> recommended, but it works with other text editors
        ```json
        {
        	"mcpServers": {
        		"taskmaster-ai": {
        			"command": "npx",
        			"args": ["-y", "task-master-ai"],
        			"env": {
        				"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
        				"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
        				"MODEL": "claude-3-7-sonnet-20250219",
        				"PERPLEXITY_MODEL": "sonar-pro",
        				"MAX_TOKENS": 128000,
        				"TEMPERATURE": 0.2,
        				"DEFAULT_SUBTASKS": 5,
        				"DEFAULT_PRIORITY": "medium"
        			}
        		}
        	}
        }
        ```
      </Step>
      <Step title="Enable the MCP in your editor settings">
        
      </Step>
      <Step title="Prompt the AI to initialize Task Master">
        > "Can you please initialize taskmaster-ai into my project?"

        **The AI will:**

        1. Create necessary project structure
        2. Set up initial configuration files
        3. Guide you through the rest of the process
        4. Place your PRD document in the `scripts/` directory (e.g., `scripts/prd.txt`)
        5. **Use natural language commands** to interact with Task Master:

           > "Can you parse my PRD at scripts/prd.txt?"
           >
           > "What's the next task I should work on?"
           >
           > "Can you help me implement task 3?"
      </Step>
    </Steps>
  </Accordion>
  <Accordion title="Option 2: Manual Installation">
    If you prefer to use the command line interface directly:

    <Steps>
      <Step title="Install">
        <CodeGroup>

        ```bash Global
        npm install -g task-master-ai
        ```

        
        ```bash Local
        npm install task-master-ai
        ```

        </CodeGroup>
      </Step>
      <Step title="Initialize a new project">
        <CodeGroup>

        ```bash Global
        task-master init
        ```

        
        ```bash Local
        npx task-master-init
        ```

        </CodeGroup>
      </Step>
    </Steps>
    This will prompt you for project details and set up a new project with the necessary files and structure.
  </Accordion>
</AccordionGroup>

## Common Commands

<Tip>
  After setting up Task Master, you can use these commands (either via AI prompts or CLI)
</Tip>

```bash
# Parse a PRD and generate tasks
task-master parse-prd your-prd.txt

# List all tasks
task-master list

# Show the next task to work on
task-master next

# Generate task files
task-master generate 


--- packages/claude-code-plugin/commands/quick-install-taskmaster.md ---
Quick install Task Master globally if not already installed.

Execute this streamlined installation:

```bash
# Check and install in one command
task-master --version 2>/dev/null || npm install -g task-master-ai

# Verify installation
task-master --version

# Quick setup check
task-master models --status || echo "Note: You'll need to set up an AI provider API key"
```

If you see "command not found" after installation, you may need to:
1. Restart your terminal
2. Or add npm global bin to PATH: `export PATH=$(npm bin -g):$PATH`

Once installed, you can use all the Task Master commands!

Quick test: Run `/project:help` to see all available commands.

--- assets/example_prd.txt ---
<context>
# Overview  
[Provide a high-level overview of your product here. Explain what problem it solves, who it's for, and why it's valuable.]

# Core Features  
[List and describe the main features of your product. For each feature, include:
- What it does
- Why it's important
- How it works at a high level]

# User Experience  
[Describe the user journey and experience. Include:
- User personas
- Key user flows
- UI/UX considerations]
</context>
<PRD>
# Technical Architecture  
[Outline the technical implementation details:
- System components
- Data models
- APIs and integrations
- Infrastructure requirements]

# Development Roadmap  
[Break down the development process into phases:
- MVP requirements
- Future enhancements
- Do not think about timelines whatsoever -- all that matters is scope and detailing exactly what needs to be build in each phase so it can later be cut up into tasks]

# Logical Dependency Chain
[Define the logical order of development:
- Which features need to be built first (foundation)
- Getting as quickly as possible to something usable/visible front end that works
- Properly pacing and scoping each feature so it is atomic but can also be built upon and improved as development approaches]

# Risks and Mitigations  
[Identify potential risks and how they'll be addressed:
- Technical challenges
- Figuring out the MVP that we can build upon
- Resource constraints]

# Appendix  
[Include any additional information:
- Research findings
- Technical specifications]
</PRD>

--- assets/example_prd_rpg.txt ---
<rpg-method>
# Repository Planning Graph (RPG) Method - PRD Template

This template teaches you (AI or human) how to create structured, dependency-aware PRDs using the RPG methodology from Microsoft Research. The key insight: separate WHAT (functional) from HOW (structural), then connect them with explicit dependencies.

## Core Principles

1. **Dual-Semantics**: Think functional (capabilities) AND structural (code organization) separately, then map them
2. **Explicit Dependencies**: Never assume - always state what depends on what
3. **Topological Order**: Build foundation first, then layers on top
4. **Progressive Refinement**: Start broad, refine iteratively

## How to Use This Template

- Follow the instructions in each `<instruction>` block
- Look at `<example>` blocks to see good vs bad patterns
- Fill in the content sections with your project details
- The AI reading this will learn the RPG method by following along
- Task Master will parse the resulting PRD into dependency-aware tasks

## Recommended Tools for Creating PRDs

When using this template to **create** a PRD (not parse it), use **code-context-aware AI assistants** for best results:

**Why?** The AI needs to understand your existing codebase to make good architectural decisions about modules, dependencies, and integration points.

**Recommended tools:**
- **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
- **Cursor/Windsurf** - IDE integration with full codebase context
- **Gemini CLI** (gemini-cli) - Massive context window for large codebases
- **Codex/Grok CLI** - Strong code generation with context awareness

**Note:** Once your PRD is created, `task-master parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
</rpg-method>

---

<overview>
<instruction>
Start with the problem, not the solution. Be specific about:
- What pain point exists?
- Who experiences it?
- Why existing solutions don't work?
- What success looks like (measurable outcomes)?

Keep this section focused - don't jump into implementation details yet.
</instruction>

## Problem Statement
[Describe the core problem. Be concrete about user pain points.]

## Target Users
[Define personas, their workflows, and what they're trying to achieve.]

## Success Metrics
[Quantifiable outcomes. Examples: "80% task completion via autopilot", "< 5% manual intervention rate"]

</overview>

---

<functional-decomposition>
<instruction>
Now think about CAPABILITIES (what the system DOES), not code structure yet.

Step 1: Identify high-level capability domains
- Think: "What major things does this system do?"
- Examples: Data Management, Core Processing, Presentation Layer

Step 2: For each capability, enumerate specific features
- Use explore-exploit strategy:
  * Exploit: What features are REQUIRED for core value?
  * Explore: What features make this domain COMPLETE?

Step 3: For each feature, define:
- Description: What it does in one sentence
- Inputs: What data/context it needs
- Outputs: What it produces/returns
- Behavior: Key logic or transformations

<example type="good">
Capability: Data Validation
  Feature: Schema validation
    - Description: Validate JSON payloads against defined schemas
    - Inputs: JSON object, schema definition
    - Outputs: Validation result (pass/fail) + error details
    - Behavior: Iterate fields, check types, enforce constraints

  Feature: Business rule validation
    - Description: Apply domain-specific validation rules
    - Inputs: Validated data object, rule set
    - Outputs: Boolean + list of violated rules
    - Behavior: Execute rules sequentially, short-circuit on failure
</example>

<example type="bad">
Capability: validation.js
  (Problem: This is a FILE, not a CAPABILITY. Mixing structure into functional thinking.)

Capability: Validation
  Feature: Make sure data is good
  (Problem: Too vague. No inputs/outputs. Not actionable.)
</example>
</instruction>

## Capability Tree

### Capability: [Name]
[Brief description of what this capability domain covers]

#### Feature: [Name]
- **Description**: [One sentence]
- **Inputs**: [What it needs]
- **Outputs**: [What it produces]
- **Behavior**: [Key logic]

#### Feature: [Name]
- **Description**:
- **Inputs**:
- **Outputs**:
- **Behavior**:

### Capability: [Name]
...

</functional-decomposition>

---

<structural-decomposition>
<instruction>
NOW think about code organization. Map capabilities to actual file/folder structure.

Rules:
1. Each capability maps to a module (folder or file)
2. Features within a capability map to functions/classes
3. Use clear module boundaries - each module has ONE responsibility
4. Define what each module exports (public interface)

The goal: Create a clear mapping between "what it does" (functional) and "where it lives" (structural).

<example type="good">
Capability: Data Validation
  → Maps to: src/validation/
    ├── schema-validator.js      (Schema validation feature)
    ├── rule-validator.js         (Business rule validation feature)
    └── index.js                  (Public exports)

Exports:
  - validateSchema(data, schema)
  - validateRules(data, rules)
</example>

<example type="bad">
Capability: Data Validation
  → Maps to: src/utils.js
  (Problem: "utils" is not a clear module boundary. Where do I find validation logic?)

Capability: Data Validation
  → Maps to: src/validation/everything.js
  (Problem: One giant file. Features should map to separate files for maintainability.)
</example>
</instruction>

## Repository Structure

```
project-root/
├── src/
│   ├── [module-name]/       # Maps to: [Capability Name]
│   │   ├── [file].js        # Maps to: [Feature Name]
│   │   └── index.js         # Public exports
│   └── [module-name]/
├── tests/
└── docs/
```

## Module Definitions

### Module: [Name]
- **Maps to capability**: [Capability from functional decomposition]
- **Responsibility**: [Single clear purpose]
- **File structure**:
  ```
  module-name/
  ├── feature1.js
  ├── feature2.js
  └── index.js
  ```
- **Exports**:
  - `functionName()` - [what it does]
  - `ClassName` - [what it does]

</structural-decomposition>

---

<dependency-graph>
<instruction>
This is THE CRITICAL SECTION for Task Master parsing.

Define explicit dependencies between modules. This creates the topological order for task execution.

Rules:
1. List modules in dependency order (foundation first)
2. For each module, state what it depends on
3. Foundation modules should have NO dependencies
4. Every non-foundation module should depend on at least one other module
5. Think: "What must EXIST before I can build this module?"

<example type="good">
Foundation Layer (no dependencies):
  - error-handling: No dependencies
  - config-manager: No dependencies
  - base-types: No dependencies

Data Layer:
  - schema-validator: Depends on [base-types, error-handling]
  - data-ingestion: Depends on [schema-validator, config-manager]

Core Layer:
  - algorithm-engine: Depends on [base-types, error-handling]
  - pipeline-orchestrator: Depends on [algorithm-engine, data-ingestion]
</example>

<example type="bad">
- validation: Depends on API
- API: Depends on validation
(Problem: Circular dependency. This will cause build/runtime issues.)

- user-auth: Depends on everything
(Problem: Too many dependencies. Should be more focused.)
</example>
</instruction>

## Dependency Chain

### Foundation Layer (Phase 0)
No dependencies - these are built first.

- **[Module Name]**: [What it provides]
- **[Module Name]**: [What it provides]

### [Layer Name] (Phase 1)
- **[Module Name]**: Depends on [[module-from-phase-0], [module-from-phase-0]]
- **[Module Name]**: Depends on [[module-from-phase-0]]

### [Layer Name] (Phase 2)
- **[Module Name]**: Depends on [[module-from-phase-1], [module-from-foundation]]

[Continue building up layers...]

</dependency-graph>

---

<implementation-roadmap>
<instruction>
Turn the dependency graph into concrete development phases.

Each phase should:
1. Have clear entry criteria (what must exist before starting)
2. Contain tasks that can be parallelized (no inter-dependencies within phase)
3. Have clear exit criteria (how do we know phase is complete?)
4. Build toward something USABLE (not just infrastructure)

Phase ordering follows topological sort of dependency graph.

<example type="good">
Phase 0: Foundation
  Entry: Clean repository
  Tasks:
    - Implement error handling utilities
    - Create base type definitions
    - Setup configuration system
  Exit: Other modules can import foundation without errors

Phase 1: Data Layer
  Entry: Phase 0 complete
  Tasks:
    - Implement schema validator (uses: base types, error handling)
    - Build data ingestion pipeline (uses: validator, config)
  Exit: End-to-end data flow from input to validated output
</example>

<example type="bad">
Phase 1: Build Everything
  Tasks:
    - API
    - Database
    - UI
    - Tests
  (Problem: No clear focus. Too broad. Dependencies not considered.)
</example>
</instruction>

## Development Phases

### Phase 0: [Foundation Name]
**Goal**: [What foundational capability this establishes]

**Entry Criteria**: [What must be true before starting]

**Tasks**:
- [ ] [Task name] (depends on: [none or list])
  - Acceptance criteria: [How we know it's done]
  - Test strategy: [What tests prove it works]

- [ ] [Task name] (depends on: [none or list])

**Exit Criteria**: [Observable outcome that proves phase complete]

**Delivers**: [What can users/developers do after this phase?]

---

### Phase 1: [Layer Name]
**Goal**:

**Entry Criteria**: Phase 0 complete

**Tasks**:
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])

**Exit Criteria**:

**Delivers**:

---

[Continue with more phases...]

</implementation-roadmap>

---

<test-strategy>
<instruction>
Define how testing will be integrated throughout development (TDD approach).

Specify:
1. Test pyramid ratios (unit vs integration vs e2e)
2. Coverage requirements
3. Critical test scenarios
4. Test generation guidelines for Surgical Test Generator

This section guides the AI when generating tests during the RED phase of TDD.

<example type="good">
Critical Test Scenarios for Data Validation module:
  - Happy path: Valid data passes all checks
  - Edge cases: Empty strings, null values, boundary numbers
  - Error cases: Invalid types, missing required fields
  - Integration: Validator works with ingestion pipeline
</example>
</instruction>

## Test Pyramid

```
        /\
       /E2E\       ← [X]% (End-to-end, slow, comprehensive)
      /------\
     /Integration\ ← [Y]% (Module interactions)
    /------------\
   /  Unit Tests  \ ← [Z]% (Fast, isolated, deterministic)
  /----------------\
```

## Coverage Requirements
- Line coverage: [X]% minimum
- Branch coverage: [X]% minimum
- Function coverage: [X]% minimum
- Statement coverage: [X]% minimum

## Critical Test Scenarios

### [Module/Feature Name]
**Happy path**:
- [Scenario description]
- Expected: [What should happen]

**Edge cases**:
- [Scenario description]
- Expected: [What should happen]

**Error cases**:
- [Scenario description]
- Expected: [How system handles failure]

**Integration points**:
- [What interactions to test]
- Expected: [End-to-end behavior]

## Test Generation Guidelines
[Specific instructions for Surgical Test Generator about what to focus on, what patterns to follow, project-specific test conventions]

</test-strategy>

---

<architecture>
<instruction>
Describe technical architecture, data models, and key design decisions.

Keep this section AFTER functional/structural decomposition - implementation details come after understanding structure.
</instruction>

## System Components
[Major architectural pieces and their responsibilities]

## Data Models
[Core data structures, schemas, database design]

## Technology Stack
[Languages, frameworks, key libraries]

**Decision: [Technology/Pattern]**
- **Rationale**: [Why chosen]
- **Trade-offs**: [What we're giving up]
- **Alternatives considered**: [What else we looked at]

</architecture>

---

<risks>
<instruction>
Identify risks that could derail development and how to mitigate them.

Categories:
- Technical risks (complexity, unknowns)
- Dependency risks (blocking issues)
- Scope risks (creep, underestimation)
</instruction>

## Technical Risks
**Risk**: [Description]
- **Impact**: [High/Medium/Low - effect on project]
- **Likelihood**: [High/Medium/Low]
- **Mitigation**: [How to address]
- **Fallback**: [Plan B if mitigation fails]

## Dependency Risks
[External dependencies, blocking issues]

## Scope Risks
[Scope creep, underestimation, unclear requirements]

</risks>

---

<appendix>
## References
[Papers, documentation, similar systems]

## Glossary
[Domain-specific terms]

## Open Questions
[Things to resolve during development]
</appendix>

---

<task-master-integration>
# How Task Master Uses This PRD

When you run `task-master parse-prd <file>.txt`, the parser:

1. **Extracts capabilities** → Main tasks
   - Each `### Capability:` becomes a top-level task

2. **Extracts features** → Subtasks
   - Each `#### Feature:` becomes a subtask under its capability

3. **Parses dependencies** → Task dependencies
   - `Depends on: [X, Y]` sets task.dependencies = ["X", "Y"]

4. **Orders by phases** → Task priorities
   - Phase 0 tasks = highest priority
   - Phase N tasks = lower priority, properly sequenced

5. **Uses test strategy** → Test generation context
   - Feeds test scenarios to Surgical Test Generator during implementation

**Result**: A dependency-aware task graph that can be executed in topological order.

## Why RPG Structure Matters

Traditional flat PRDs lead to:
- ❌ Unclear task dependencies
- ❌ Arbitrary task ordering
- ❌ Circular dependencies discovered late
- ❌ Poorly scoped tasks

RPG-structured PRDs provide:
- ✅ Explicit dependency chains
- ✅ Topological execution order
- ✅ Clear module boundaries
- ✅ Validated task graph before implementation

## Tips for Best Results

1. **Spend time on dependency graph** - This is the most valuable section for Task Master
2. **Keep features atomic** - Each feature should be independently testable
3. **Progressive refinement** - Start broad, use `task-master expand` to break down complex tasks
4. **Use research mode** - `task-master parse-prd --research` leverages AI for better task generation
</task-master-integration>


--- .taskmaster/templates/example_prd.md ---
<context>
# Overview  
[Provide a high-level overview of your product here. Explain what problem it solves, who it's for, and why it's valuable.]

# Core Features  
[List and describe the main features of your product. For each feature, include:
- What it does
- Why it's important
- How it works at a high level]

# User Experience  
[Describe the user journey and experience. Include:
- User personas
- Key user flows
- UI/UX considerations]
</context>
<PRD>
# Technical Architecture  
[Outline the technical implementation details:
- System components
- Data models
- APIs and integrations
- Infrastructure requirements]

# Development Roadmap  
[Break down the development process into phases:
- MVP requirements
- Future enhancements
- Do not think about timelines whatsoever -- all that matters is scope and detailing exactly what needs to be build in each phase so it can later be cut up into tasks]

# Logical Dependency Chain
[Define the logical order of development:
- Which features need to be built first (foundation)
- Getting as quickly as possible to something usable/visible front end that works
- Properly pacing and scoping each feature so it is atomic but can also be built upon and improved as development approaches]

# Risks and Mitigations  
[Identify potential risks and how they'll be addressed:
- Technical challenges
- Figuring out the MVP that we can build upon
- Resource constraints]

# Appendix  
[Include any additional information:
- Research findings
- Technical specifications]
</PRD>

--- .taskmaster/templates/example_prd.txt ---
<context>
# Overview  
[Provide a high-level overview of your product here. Explain what problem it solves, who it's for, and why it's valuable.]

# Core Features  
[List and describe the main features of your product. For each feature, include:
- What it does
- Why it's important
- How it works at a high level]

# User Experience  
[Describe the user journey and experience. Include:
- User personas
- Key user flows
- UI/UX considerations]
</context>
<PRD>
# Technical Architecture  
[Outline the technical implementation details:
- System components
- Data models
- APIs and integrations
- Infrastructure requirements]

# Development Roadmap  
[Break down the development process into phases:
- MVP requirements
- Future enhancements
- Do not think about timelines whatsoever -- all that matters is scope and detailing exactly what needs to be build in each phase so it can later be cut up into tasks]

# Logical Dependency Chain
[Define the logical order of development:
- Which features need to be built first (foundation)
- Getting as quickly as possible to something usable/visible front end that works
- Properly pacing and scoping each feature so it is atomic but can also be built upon and improved as development approaches]

# Risks and Mitigations  
[Identify potential risks and how they'll be addressed:
- Technical challenges
- Figuring out the MVP that we can build upon
- Resource constraints]

# Appendix  
[Include any additional information:
- Research findings
- Technical specifications]
</PRD>

--- .taskmaster/templates/example_prd_rpg.md ---
<rpg-method>
# Repository Planning Graph (RPG) Method - PRD Template

This template teaches you (AI or human) how to create structured, dependency-aware PRDs using the RPG methodology from Microsoft Research. The key insight: separate WHAT (functional) from HOW (structural), then connect them with explicit dependencies.

## Core Principles

1. **Dual-Semantics**: Think functional (capabilities) AND structural (code organization) separately, then map them
2. **Explicit Dependencies**: Never assume - always state what depends on what
3. **Topological Order**: Build foundation first, then layers on top
4. **Progressive Refinement**: Start broad, refine iteratively

## How to Use This Template

- Follow the instructions in each `<instruction>` block
- Look at `<example>` blocks to see good vs bad patterns
- Fill in the content sections with your project details
- The AI reading this will learn the RPG method by following along
- Task Master will parse the resulting PRD into dependency-aware tasks

## Recommended Tools for Creating PRDs

When using this template to **create** a PRD (not parse it), use **code-context-aware AI assistants** for best results:

**Why?** The AI needs to understand your existing codebase to make good architectural decisions about modules, dependencies, and integration points.

**Recommended tools:**
- **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
- **Cursor/Windsurf** - IDE integration with full codebase context
- **Gemini CLI** (gemini-cli) - Massive context window for large codebases
- **Codex/Grok CLI** - Strong code generation with context awareness

**Note:** Once your PRD is created, `task-master parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
</rpg-method>

---

<overview>
<instruction>
Start with the problem, not the solution. Be specific about:
- What pain point exists?
- Who experiences it?
- Why existing solutions don't work?
- What success looks like (measurable outcomes)?

Keep this section focused - don't jump into implementation details yet.
</instruction>

## Problem Statement
[Describe the core problem. Be concrete about user pain points.]

## Target Users
[Define personas, their workflows, and what they're trying to achieve.]

## Success Metrics
[Quantifiable outcomes. Examples: "80% task completion via autopilot", "< 5% manual intervention rate"]

</overview>

---

<functional-decomposition>
<instruction>
Now think about CAPABILITIES (what the system DOES), not code structure yet.

Step 1: Identify high-level capability domains
- Think: "What major things does this system do?"
- Examples: Data Management, Core Processing, Presentation Layer

Step 2: For each capability, enumerate specific features
- Use explore-exploit strategy:
  * Exploit: What features are REQUIRED for core value?
  * Explore: What features make this domain COMPLETE?

Step 3: For each feature, define:
- Description: What it does in one sentence
- Inputs: What data/context it needs
- Outputs: What it produces/returns
- Behavior: Key logic or transformations

<example type="good">
Capability: Data Validation
  Feature: Schema validation
    - Description: Validate JSON payloads against defined schemas
    - Inputs: JSON object, schema definition
    - Outputs: Validation result (pass/fail) + error details
    - Behavior: Iterate fields, check types, enforce constraints

  Feature: Business rule validation
    - Description: Apply domain-specific validation rules
    - Inputs: Validated data object, rule set
    - Outputs: Boolean + list of violated rules
    - Behavior: Execute rules sequentially, short-circuit on failure
</example>

<example type="bad">
Capability: validation.js
  (Problem: This is a FILE, not a CAPABILITY. Mixing structure into functional thinking.)

Capability: Validation
  Feature: Make sure data is good
  (Problem: Too vague. No inputs/outputs. Not actionable.)
</example>
</instruction>

## Capability Tree

### Capability: [Name]
[Brief description of what this capability domain covers]

#### Feature: [Name]
- **Description**: [One sentence]
- **Inputs**: [What it needs]
- **Outputs**: [What it produces]
- **Behavior**: [Key logic]

#### Feature: [Name]
- **Description**:
- **Inputs**:
- **Outputs**:
- **Behavior**:

### Capability: [Name]
...

</functional-decomposition>

---

<structural-decomposition>
<instruction>
NOW think about code organization. Map capabilities to actual file/folder structure.

Rules:
1. Each capability maps to a module (folder or file)
2. Features within a capability map to functions/classes
3. Use clear module boundaries - each module has ONE responsibility
4. Define what each module exports (public interface)

The goal: Create a clear mapping between "what it does" (functional) and "where it lives" (structural).

<example type="good">
Capability: Data Validation
  → Maps to: src/validation/
    ├── schema-validator.js      (Schema validation feature)
    ├── rule-validator.js         (Business rule validation feature)
    └── index.js                  (Public exports)

Exports:
  - validateSchema(data, schema)
  - validateRules(data, rules)
</example>

<example type="bad">
Capability: Data Validation
  → Maps to: src/utils.js
  (Problem: "utils" is not a clear module boundary. Where do I find validation logic?)

Capability: Data Validation
  → Maps to: src/validation/everything.js
  (Problem: One giant file. Features should map to separate files for maintainability.)
</example>
</instruction>

## Repository Structure

```
project-root/
├── src/
│   ├── [module-name]/       # Maps to: [Capability Name]
│   │   ├── [file].js        # Maps to: [Feature Name]
│   │   └── index.js         # Public exports
│   └── [module-name]/
├── tests/
└── docs/
```

## Module Definitions

### Module: [Name]
- **Maps to capability**: [Capability from functional decomposition]
- **Responsibility**: [Single clear purpose]
- **File structure**:
  ```
  module-name/
  ├── feature1.js
  ├── feature2.js
  └── index.js
  ```
- **Exports**:
  - `functionName()` - [what it does]
  - `ClassName` - [what it does]

</structural-decomposition>

---

<dependency-graph>
<instruction>
This is THE CRITICAL SECTION for Task Master parsing.

Define explicit dependencies between modules. This creates the topological order for task execution.

Rules:
1. List modules in dependency order (foundation first)
2. For each module, state what it depends on
3. Foundation modules should have NO dependencies
4. Every non-foundation module should depend on at least one other module
5. Think: "What must EXIST before I can build this module?"

<example type="good">
Foundation Layer (no dependencies):
  - error-handling: No dependencies
  - config-manager: No dependencies
  - base-types: No dependencies

Data Layer:
  - schema-validator: Depends on [base-types, error-handling]
  - data-ingestion: Depends on [schema-validator, config-manager]

Core Layer:
  - algorithm-engine: Depends on [base-types, error-handling]
  - pipeline-orchestrator: Depends on [algorithm-engine, data-ingestion]
</example>

<example type="bad">
- validation: Depends on API
- API: Depends on validation
(Problem: Circular dependency. This will cause build/runtime issues.)

- user-auth: Depends on everything
(Problem: Too many dependencies. Should be more focused.)
</example>
</instruction>

## Dependency Chain

### Foundation Layer (Phase 0)
No dependencies - these are built first.

- **[Module Name]**: [What it provides]
- **[Module Name]**: [What it provides]

### [Layer Name] (Phase 1)
- **[Module Name]**: Depends on [[module-from-phase-0], [module-from-phase-0]]
- **[Module Name]**: Depends on [[module-from-phase-0]]

### [Layer Name] (Phase 2)
- **[Module Name]**: Depends on [[module-from-phase-1], [module-from-foundation]]

[Continue building up layers...]

</dependency-graph>

---

<implementation-roadmap>
<instruction>
Turn the dependency graph into concrete development phases.

Each phase should:
1. Have clear entry criteria (what must exist before starting)
2. Contain tasks that can be parallelized (no inter-dependencies within phase)
3. Have clear exit criteria (how do we know phase is complete?)
4. Build toward something USABLE (not just infrastructure)

Phase ordering follows topological sort of dependency graph.

<example type="good">
Phase 0: Foundation
  Entry: Clean repository
  Tasks:
    - Implement error handling utilities
    - Create base type definitions
    - Setup configuration system
  Exit: Other modules can import foundation without errors

Phase 1: Data Layer
  Entry: Phase 0 complete
  Tasks:
    - Implement schema validator (uses: base types, error handling)
    - Build data ingestion pipeline (uses: validator, config)
  Exit: End-to-end data flow from input to validated output
</example>

<example type="bad">
Phase 1: Build Everything
  Tasks:
    - API
    - Database
    - UI
    - Tests
  (Problem: No clear focus. Too broad. Dependencies not considered.)
</example>
</instruction>

## Development Phases

### Phase 0: [Foundation Name]
**Goal**: [What foundational capability this establishes]

**Entry Criteria**: [What must be true before starting]

**Tasks**:
- [ ] [Task name] (depends on: [none or list])
  - Acceptance criteria: [How we know it's done]
  - Test strategy: [What tests prove it works]

- [ ] [Task name] (depends on: [none or list])

**Exit Criteria**: [Observable outcome that proves phase complete]

**Delivers**: [What can users/developers do after this phase?]

---

### Phase 1: [Layer Name]
**Goal**:

**Entry Criteria**: Phase 0 complete

**Tasks**:
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])

**Exit Criteria**:

**Delivers**:

---

[Continue with more phases...]

</implementation-roadmap>

---

<test-strategy>
<instruction>
Define how testing will be integrated throughout development (TDD approach).

Specify:
1. Test pyramid ratios (unit vs integration vs e2e)
2. Coverage requirements
3. Critical test scenarios
4. Test generation guidelines for Surgical Test Generator

This section guides the AI when generating tests during the RED phase of TDD.

<example type="good">
Critical Test Scenarios for Data Validation module:
  - Happy path: Valid data passes all checks
  - Edge cases: Empty strings, null values, boundary numbers
  - Error cases: Invalid types, missing required fields
  - Integration: Validator works with ingestion pipeline
</example>
</instruction>

## Test Pyramid

```
        /\
       /E2E\       ← [X]% (End-to-end, slow, comprehensive)
      /------\
     /Integration\ ← [Y]% (Module interactions)
    /------------\
   /  Unit Tests  \ ← [Z]% (Fast, isolated, deterministic)
  /----------------\
```

## Coverage Requirements
- Line coverage: [X]% minimum
- Branch coverage: [X]% minimum
- Function coverage: [X]% minimum
- Statement coverage: [X]% minimum

## Critical Test Scenarios

### [Module/Feature Name]
**Happy path**:
- [Scenario description]
- Expected: [What should happen]

**Edge cases**:
- [Scenario description]
- Expected: [What should happen]

**Error cases**:
- [Scenario description]
- Expected: [How system handles failure]

**Integration points**:
- [What interactions to test]
- Expected: [End-to-end behavior]

## Test Generation Guidelines
[Specific instructions for Surgical Test Generator about what to focus on, what patterns to follow, project-specific test conventions]

</test-strategy>

---

<architecture>
<instruction>
Describe technical architecture, data models, and key design decisions.

Keep this section AFTER functional/structural decomposition - implementation details come after understanding structure.
</instruction>

## System Components
[Major architectural pieces and their responsibilities]

## Data Models
[Core data structures, schemas, database design]

## Technology Stack
[Languages, frameworks, key libraries]

**Decision: [Technology/Pattern]**
- **Rationale**: [Why chosen]
- **Trade-offs**: [What we're giving up]
- **Alternatives considered**: [What else we looked at]

</architecture>

---

<risks>
<instruction>
Identify risks that could derail development and how to mitigate them.

Categories:
- Technical risks (complexity, unknowns)
- Dependency risks (blocking issues)
- Scope risks (creep, underestimation)
</instruction>

## Technical Risks
**Risk**: [Description]
- **Impact**: [High/Medium/Low - effect on project]
- **Likelihood**: [High/Medium/Low]
- **Mitigation**: [How to address]
- **Fallback**: [Plan B if mitigation fails]

## Dependency Risks
[External dependencies, blocking issues]

## Scope Risks
[Scope creep, underestimation, unclear requirements]

</risks>

---

<appendix>
## References
[Papers, documentation, similar systems]

## Glossary
[Domain-specific terms]

## Open Questions
[Things to resolve during development]
</appendix>

---

<task-master-integration>
# How Task Master Uses This PRD

When you run `task-master parse-prd <file>.txt`, the parser:

1. **Extracts capabilities** → Main tasks
   - Each `### Capability:` becomes a top-level task

2. **Extracts features** → Subtasks
   - Each `#### Feature:` becomes a subtask under its capability

3. **Parses dependencies** → Task dependencies
   - `Depends on: [X, Y]` sets task.dependencies = ["X", "Y"]

4. **Orders by phases** → Task priorities
   - Phase 0 tasks = highest priority
   - Phase N tasks = lower priority, properly sequenced

5. **Uses test strategy** → Test generation context
   - Feeds test scenarios to Surgical Test Generator during implementation

**Result**: A dependency-aware task graph that can be executed in topological order.

## Why RPG Structure Matters

Traditional flat PRDs lead to:
- ❌ Unclear task dependencies
- ❌ Arbitrary task ordering
- ❌ Circular dependencies discovered late
- ❌ Poorly scoped tasks

RPG-structured PRDs provide:
- ✅ Explicit dependency chains
- ✅ Topological execution order
- ✅ Clear module boundaries
- ✅ Validated task graph before implementation

## Tips for Best Results

1. **Spend time on dependency graph** - This is the most valuable section for Task Master
2. **Keep features atomic** - Each feature should be independently testable
3. **Progressive refinement** - Start broad, use `task-master expand` to break down complex tasks
4. **Use research mode** - `task-master parse-prd --research` leverages AI for better task generation
</task-master-integration>


--- .taskmaster/templates/example_prd_rpg.txt ---
<rpg-method>
# Repository Planning Graph (RPG) Method - PRD Template

This template teaches you (AI or human) how to create structured, dependency-aware PRDs using the RPG methodology from Microsoft Research. The key insight: separate WHAT (functional) from HOW (structural), then connect them with explicit dependencies.

## Core Principles

1. **Dual-Semantics**: Think functional (capabilities) AND structural (code organization) separately, then map them
2. **Explicit Dependencies**: Never assume - always state what depends on what
3. **Topological Order**: Build foundation first, then layers on top
4. **Progressive Refinement**: Start broad, refine iteratively

## How to Use This Template

- Follow the instructions in each `<instruction>` block
- Look at `<example>` blocks to see good vs bad patterns
- Fill in the content sections with your project details
- The AI reading this will learn the RPG method by following along
- Task Master will parse the resulting PRD into dependency-aware tasks

## Recommended Tools for Creating PRDs

When using this template to **create** a PRD (not parse it), use **code-context-aware AI assistants** for best results:

**Why?** The AI needs to understand your existing codebase to make good architectural decisions about modules, dependencies, and integration points.

**Recommended tools:**
- **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
- **Cursor/Windsurf** - IDE integration with full codebase context
- **Gemini CLI** (gemini-cli) - Massive context window for large codebases
- **Codex/Grok CLI** - Strong code generation with context awareness

**Note:** Once your PRD is created, `task-master parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
</rpg-method>

---

<overview>
<instruction>
Start with the problem, not the solution. Be specific about:
- What pain point exists?
- Who experiences it?
- Why existing solutions don't work?
- What success looks like (measurable outcomes)?

Keep this section focused - don't jump into implementation details yet.
</instruction>

## Problem Statement
[Describe the core problem. Be concrete about user pain points.]

## Target Users
[Define personas, their workflows, and what they're trying to achieve.]

## Success Metrics
[Quantifiable outcomes. Examples: "80% task completion via autopilot", "< 5% manual intervention rate"]

</overview>

---

<functional-decomposition>
<instruction>
Now think about CAPABILITIES (what the system DOES), not code structure yet.

Step 1: Identify high-level capability domains
- Think: "What major things does this system do?"
- Examples: Data Management, Core Processing, Presentation Layer

Step 2: For each capability, enumerate specific features
- Use explore-exploit strategy:
  * Exploit: What features are REQUIRED for core value?
  * Explore: What features make this domain COMPLETE?

Step 3: For each feature, define:
- Description: What it does in one sentence
- Inputs: What data/context it needs
- Outputs: What it produces/returns
- Behavior: Key logic or transformations

<example type="good">
Capability: Data Validation
  Feature: Schema validation
    - Description: Validate JSON payloads against defined schemas
    - Inputs: JSON object, schema definition
    - Outputs: Validation result (pass/fail) + error details
    - Behavior: Iterate fields, check types, enforce constraints

  Feature: Business rule validation
    - Description: Apply domain-specific validation rules
    - Inputs: Validated data object, rule set
    - Outputs: Boolean + list of violated rules
    - Behavior: Execute rules sequentially, short-circuit on failure
</example>

<example type="bad">
Capability: validation.js
  (Problem: This is a FILE, not a CAPABILITY. Mixing structure into functional thinking.)

Capability: Validation
  Feature: Make sure data is good
  (Problem: Too vague. No inputs/outputs. Not actionable.)
</example>
</instruction>

## Capability Tree

### Capability: [Name]
[Brief description of what this capability domain covers]

#### Feature: [Name]
- **Description**: [One sentence]
- **Inputs**: [What it needs]
- **Outputs**: [What it produces]
- **Behavior**: [Key logic]

#### Feature: [Name]
- **Description**:
- **Inputs**:
- **Outputs**:
- **Behavior**:

### Capability: [Name]
...

</functional-decomposition>

---

<structural-decomposition>
<instruction>
NOW think about code organization. Map capabilities to actual file/folder structure.

Rules:
1. Each capability maps to a module (folder or file)
2. Features within a capability map to functions/classes
3. Use clear module boundaries - each module has ONE responsibility
4. Define what each module exports (public interface)

The goal: Create a clear mapping between "what it does" (functional) and "where it lives" (structural).

<example type="good">
Capability: Data Validation
  → Maps to: src/validation/
    ├── schema-validator.js      (Schema validation feature)
    ├── rule-validator.js         (Business rule validation feature)
    └── index.js                  (Public exports)

Exports:
  - validateSchema(data, schema)
  - validateRules(data, rules)
</example>

<example type="bad">
Capability: Data Validation
  → Maps to: src/utils.js
  (Problem: "utils" is not a clear module boundary. Where do I find validation logic?)

Capability: Data Validation
  → Maps to: src/validation/everything.js
  (Problem: One giant file. Features should map to separate files for maintainability.)
</example>
</instruction>

## Repository Structure

```
project-root/
├── src/
│   ├── [module-name]/       # Maps to: [Capability Name]
│   │   ├── [file].js        # Maps to: [Feature Name]
│   │   └── index.js         # Public exports
│   └── [module-name]/
├── tests/
└── docs/
```

## Module Definitions

### Module: [Name]
- **Maps to capability**: [Capability from functional decomposition]
- **Responsibility**: [Single clear purpose]
- **File structure**:
  ```
  module-name/
  ├── feature1.js
  ├── feature2.js
  └── index.js
  ```
- **Exports**:
  - `functionName()` - [what it does]
  - `ClassName` - [what it does]

</structural-decomposition>

---

<dependency-graph>
<instruction>
This is THE CRITICAL SECTION for Task Master parsing.

Define explicit dependencies between modules. This creates the topological order for task execution.

Rules:
1. List modules in dependency order (foundation first)
2. For each module, state what it depends on
3. Foundation modules should have NO dependencies
4. Every non-foundation module should depend on at least one other module
5. Think: "What must EXIST before I can build this module?"

<example type="good">
Foundation Layer (no dependencies):
  - error-handling: No dependencies
  - config-manager: No dependencies
  - base-types: No dependencies

Data Layer:
  - schema-validator: Depends on [base-types, error-handling]
  - data-ingestion: Depends on [schema-validator, config-manager]

Core Layer:
  - algorithm-engine: Depends on [base-types, error-handling]
  - pipeline-orchestrator: Depends on [algorithm-engine, data-ingestion]
</example>

<example type="bad">
- validation: Depends on API
- API: Depends on validation
(Problem: Circular dependency. This will cause build/runtime issues.)

- user-auth: Depends on everything
(Problem: Too many dependencies. Should be more focused.)
</example>
</instruction>

## Dependency Chain

### Foundation Layer (Phase 0)
No dependencies - these are built first.

- **[Module Name]**: [What it provides]
- **[Module Name]**: [What it provides]

### [Layer Name] (Phase 1)
- **[Module Name]**: Depends on [[module-from-phase-0], [module-from-phase-0]]
- **[Module Name]**: Depends on [[module-from-phase-0]]

### [Layer Name] (Phase 2)
- **[Module Name]**: Depends on [[module-from-phase-1], [module-from-foundation]]

[Continue building up layers...]

</dependency-graph>

---

<implementation-roadmap>
<instruction>
Turn the dependency graph into concrete development phases.

Each phase should:
1. Have clear entry criteria (what must exist before starting)
2. Contain tasks that can be parallelized (no inter-dependencies within phase)
3. Have clear exit criteria (how do we know phase is complete?)
4. Build toward something USABLE (not just infrastructure)

Phase ordering follows topological sort of dependency graph.

<example type="good">
Phase 0: Foundation
  Entry: Clean repository
  Tasks:
    - Implement error handling utilities
    - Create base type definitions
    - Setup configuration system
  Exit: Other modules can import foundation without errors

Phase 1: Data Layer
  Entry: Phase 0 complete
  Tasks:
    - Implement schema validator (uses: base types, error handling)
    - Build data ingestion pipeline (uses: validator, config)
  Exit: End-to-end data flow from input to validated output
</example>

<example type="bad">
Phase 1: Build Everything
  Tasks:
    - API
    - Database
    - UI
    - Tests
  (Problem: No clear focus. Too broad. Dependencies not considered.)
</example>
</instruction>

## Development Phases

### Phase 0: [Foundation Name]
**Goal**: [What foundational capability this establishes]

**Entry Criteria**: [What must be true before starting]

**Tasks**:
- [ ] [Task name] (depends on: [none or list])
  - Acceptance criteria: [How we know it's done]
  - Test strategy: [What tests prove it works]

- [ ] [Task name] (depends on: [none or list])

**Exit Criteria**: [Observable outcome that proves phase complete]

**Delivers**: [What can users/developers do after this phase?]

---

### Phase 1: [Layer Name]
**Goal**:

**Entry Criteria**: Phase 0 complete

**Tasks**:
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])
- [ ] [Task name] (depends on: [[tasks-from-phase-0]])

**Exit Criteria**:

**Delivers**:

---

[Continue with more phases...]

</implementation-roadmap>

---

<test-strategy>
<instruction>
Define how testing will be integrated throughout development (TDD approach).

Specify:
1. Test pyramid ratios (unit vs integration vs e2e)
2. Coverage requirements
3. Critical test scenarios
4. Test generation guidelines for Surgical Test Generator

This section guides the AI when generating tests during the RED phase of TDD.

<example type="good">
Critical Test Scenarios for Data Validation module:
  - Happy path: Valid data passes all checks
  - Edge cases: Empty strings, null values, boundary numbers
  - Error cases: Invalid types, missing required fields
  - Integration: Validator works with ingestion pipeline
</example>
</instruction>

## Test Pyramid

```
        /\
       /E2E\       ← [X]% (End-to-end, slow, comprehensive)
      /------\
     /Integration\ ← [Y]% (Module interactions)
    /------------\
   /  Unit Tests  \ ← [Z]% (Fast, isolated, deterministic)
  /----------------\
```

## Coverage Requirements
- Line coverage: [X]% minimum
- Branch coverage: [X]% minimum
- Function coverage: [X]% minimum
- Statement coverage: [X]% minimum

## Critical Test Scenarios

### [Module/Feature Name]
**Happy path**:
- [Scenario description]
- Expected: [What should happen]

**Edge cases**:
- [Scenario description]
- Expected: [What should happen]

**Error cases**:
- [Scenario description]
- Expected: [How system handles failure]

**Integration points**:
- [What interactions to test]
- Expected: [End-to-end behavior]

## Test Generation Guidelines
[Specific instructions for Surgical Test Generator about what to focus on, what patterns to follow, project-specific test conventions]

</test-strategy>

---

<architecture>
<instruction>
Describe technical architecture, data models, and key design decisions.

Keep this section AFTER functional/structural decomposition - implementation details come after understanding structure.
</instruction>

## System Components
[Major architectural pieces and their responsibilities]

## Data Models
[Core data structures, schemas, database design]

## Technology Stack
[Languages, frameworks, key libraries]

**Decision: [Technology/Pattern]**
- **Rationale**: [Why chosen]
- **Trade-offs**: [What we're giving up]
- **Alternatives considered**: [What else we looked at]

</architecture>

---

<risks>
<instruction>
Identify risks that could derail development and how to mitigate them.

Categories:
- Technical risks (complexity, unknowns)
- Dependency risks (blocking issues)
- Scope risks (creep, underestimation)
</instruction>

## Technical Risks
**Risk**: [Description]
- **Impact**: [High/Medium/Low - effect on project]
- **Likelihood**: [High/Medium/Low]
- **Mitigation**: [How to address]
- **Fallback**: [Plan B if mitigation fails]

## Dependency Risks
[External dependencies, blocking issues]

## Scope Risks
[Scope creep, underestimation, unclear requirements]

</risks>

---

<appendix>
## References
[Papers, documentation, similar systems]

## Glossary
[Domain-specific terms]

## Open Questions
[Things to resolve during development]
</appendix>

---

<task-master-integration>
# How Task Master Uses This PRD

When you run `task-master parse-prd <file>.txt`, the parser:

1. **Extracts capabilities** → Main tasks
   - Each `### Capability:` becomes a top-level task

2. **Extracts features** → Subtasks
   - Each `#### Feature:` becomes a subtask under its capability

3. **Parses dependencies** → Task dependencies
   - `Depends on: [X, Y]` sets task.dependencies = ["X", "Y"]

4. **Orders by phases** → Task priorities
   - Phase 0 tasks = highest priority
   - Phase N tasks = lower priority, properly sequenced

5. **Uses test strategy** → Test generation context
   - Feeds test scenarios to Surgical Test Generator during implementation

**Result**: A dependency-aware task graph that can be executed in topological order.

## Why RPG Structure Matters

Traditional flat PRDs lead to:
- ❌ Unclear task dependencies
- ❌ Arbitrary task ordering
- ❌ Circular dependencies discovered late
- ❌ Poorly scoped tasks

RPG-structured PRDs provide:
- ✅ Explicit dependency chains
- ✅ Topological execution order
- ✅ Clear module boundaries
- ✅ Validated task graph before implementation

## Tips for Best Results

1. **Spend time on dependency graph** - This is the most valuable section for Task Master
2. **Keep features atomic** - Each feature should be independently testable
3. **Progressive refinement** - Start broad, use `task-master expand` to break down complex tasks
4. **Use research mode** - `task-master parse-prd --research` leverages AI for better task generation
</task-master-integration>


--- packages/ai-sdk-provider-grok-cli/README.md ---
# AI SDK Provider for Grok CLI

A provider for the [AI SDK](https://sdk.vercel.ai) that integrates with [Grok CLI](https://docs.x.ai/api) for accessing xAI's Grok language models.

## Features

- ✅ **AI SDK v5 Compatible** - Full support for the latest AI SDK interfaces
- ✅ **Streaming & Non-streaming** - Both generation modes supported
- ✅ **Error Handling** - Comprehensive error handling with retry logic
- ✅ **Type Safety** - Full TypeScript support with proper type definitions
- ✅ **JSON Mode** - Automatic JSON extraction from responses
- ✅ **Abort Signals** - Proper cancellation support

## Installation

```bash
npm install @tm/ai-sdk-provider-grok-cli
# or
yarn add @tm/ai-sdk-provider-grok-cli
```

## Prerequisites

1. Install the Grok CLI:

   ```bash
   npm install -g grok-cli
   # or follow xAI's installation instructions
   ```

2. Set up authentication:

   ```bash
   export GROK_CLI_API_KEY="your-api-key"
   # or configure via grok CLI: grok config set api-key your-key
   ```

## Usage

### Basic Usage

```typescript
import { grokCli } from '@tm/ai-sdk-provider-grok-cli';
import { generateText } from 'ai';

const result = await generateText({
  model: grokCli('grok-3-latest'),
  prompt: 'Write a haiku about TypeScript'
});

console.log(result.text);
```

### Streaming

```typescript
import { grokCli } from '@tm/ai-sdk-provider-grok-cli';
import { streamText } from 'ai';

const { textStream } = await streamText({
  model: grokCli('grok-4-latest'),
  prompt: 'Explain quantum computing'
});

for await (const delta of textStream) {
  process.stdout.write(delta);
}
```

### JSON Mode

```typescript
import { grokCli } from '@tm/ai-sdk-provider-grok-cli';
import { generateObject } from 'ai';
import { z } from 'zod';

const result = await generateObject({
  model: grokCli('grok-3-latest'),
  schema: z.object({
    name: z.string(),
    age: z.number(),
    hobbies: z.array(z.string())
  }),
  prompt: 'Generate a person profile'
});

console.log(result.object);
```

## Supported Models

- `grok-3-latest` - Grok 3 (latest version)
- `grok-4-latest` - Grok 4 (latest version)
- `grok-4` - Grok 4 (stable)
- Custom model strings supported

## Configuration

### Provider Settings

```typescript
import { createGrokCli } from '@tm/ai-sdk-provider-grok-cli';

const grok = createGrokCli({
  apiKey: 'your-api-key', // Optional if set via env/CLI
  timeout: 120000, // 2 minutes default
  workingDirectory: '/path/to/project', // Optional
  baseURL: 'https://api.x.ai' // Optional
});
```

### Model Settings

```typescript
const model = grok('grok-4-latest', {
  timeout: 300000, // 5 minutes for grok-4
  // Other CLI-specific settings
});
```

## Error Handling

The provider includes comprehensive error handling:

```typescript
import {
  isAuthenticationError,
  isTimeoutError,
  isInstallationError
} from '@tm/ai-sdk-provider-grok-cli';

try {
  const result = await generateText({
    model: grokCli('grok-4-latest'),
    prompt: 'Hello!'
  });
} catch (error) {
  if (isAuthenticationError(error)) {
    console.error('Authentication failed:', error.message);
  } else if (isTimeoutError(error)) {
    console.error('Request timed out:', error.message);
  } else if (isInstallationError(error)) {
    console.error('Grok CLI not installed or not found in PATH');
  }
}
```

## Development

```bash
# Install dependencies
npm install

# Start development mode (keep running during development)
npm run dev

# Type check
npm run typecheck

# Run tests (requires build first)
NODE_ENV=production npm run build
npm test
```

**Important**: Always run `npm run dev` and keep it running during development. This ensures proper compilation and hot-reloading of TypeScript files.


## Links discovered
- [AI SDK](https://sdk.vercel.ai)
- [Grok CLI](https://docs.x.ai/api)

--- tests/unit/scripts/modules/commands/README.md ---
# Mock System Documentation

## Overview

The `move-cross-tag.test.js` file has been refactored to use a focused, maintainable mock system that addresses the brittleness and complexity of the original implementation.

## Key Improvements

### 1. **Focused Mocking**

- **Before**: Mocked 20+ modules, many irrelevant to cross-tag functionality
- **After**: Only mocks 5 core modules actually used in cross-tag moves

### 2. **Configuration-Driven Mocking**

```javascript
const mockConfig = {
  core: {
    moveTasksBetweenTags: true,
    generateTaskFiles: true,
    readJSON: true,
    initTaskMaster: true,
    findProjectRoot: true
  }
};
```

### 3. **Reusable Mock Factory**

```javascript
function createMockFactory(config = mockConfig) {
  const mocks = {};
  
  if (config.core?.moveTasksBetweenTags) {
    mocks.moveTasksBetweenTags = createMock('moveTasksBetweenTags');
  }
  // ... other mocks
  
  return mocks;
}
```

## Mock Configuration

### Core Mocks (Required for Cross-Tag Functionality)

- `moveTasksBetweenTags`: Core move functionality
- `generateTaskFiles`: File generation after moves
- `readJSON`: Reading task data
- `initTaskMaster`: TaskMaster initialization
- `findProjectRoot`: Project path resolution

### Optional Mocks

- Console methods: `error`, `log`, `exit`
- TaskMaster instance methods: `getCurrentTag`, `getTasksPath`, `getProjectRoot`

## Usage Examples

### Default Configuration

```javascript
const mocks = setupMocks(); // Uses default mockConfig
```

### Minimal Configuration

```javascript
const minimalConfig = {
  core: {
    moveTasksBetweenTags: true,
    generateTaskFiles: true,
    readJSON: true
  }
};
const mocks = setupMocks(minimalConfig);
```

### Selective Mocking

```javascript
const selectiveConfig = {
  core: {
    moveTasksBetweenTags: true,
    generateTaskFiles: false, // Disabled
    readJSON: true
  }
};
const mocks = setupMocks(selectiveConfig);
```

## Benefits

1. **Reduced Complexity**: From 150+ lines of mock setup to 50 lines
2. **Better Maintainability**: Clear configuration object shows dependencies
3. **Focused Testing**: Only mocks what's actually used
4. **Flexible Configuration**: Easy to enable/disable specific mocks
5. **Consistent Naming**: All mocks use `createMock()` with descriptive names

## Migration Guide

### For Other Test Files

1. Identify actual module dependencies
2. Create configuration object for required mocks
3. Use `createMockFactory()` and `setupMocks()`
4. Remove unnecessary mocks

### Example Migration

```javascript
// Before: 20+ jest.mock() calls
jest.mock('module1', () => ({ ... }));
jest.mock('module2', () => ({ ... }));
// ... many more

// After: Configuration-driven
const mockConfig = {
  core: {
    requiredFunction1: true,
    requiredFunction2: true
  }
};
const mocks = setupMocks(mockConfig);
```

## Testing the Mock System

The test suite includes validation tests:

- `should work with minimal mock configuration`
- `should allow disabling specific mocks`

These ensure the mock factory works correctly and can be configured flexibly.


--- scripts/modules/ai-services-unified.js ---
/**
 * ai-services-unified.js
 * Centralized AI service layer using provider modules and config-manager.
 */

// Vercel AI SDK functions are NOT called directly anymore.
// import { generateText, streamText, generateObject } from 'ai';

// --- Core Dependencies ---
import {
	MODEL_MAP,
	getAzureBaseURL,
	getBaseUrlForRole,
	getBedrockBaseURL,
	getDebugFlag,
	getFallbackModelId,
	getFallbackProvider,
	getMainModelId,
	getMainProvider,
	getOllamaBaseURL,
	getParametersForRole,
	getResearchModelId,
	getResearchProvider,
	getResponseLanguage,
	getUserId,
	getVertexLocation,
	getVertexProjectId
} from './config-manager.js';
import {
	findProjectRoot,
	getCurrentTag,
	log,
	resolveEnvVariable
} from './utils.js';

// Import provider classes
import {
	AnthropicAIProvider,
	AzureProvider,
	BedrockAIProvider,
	ClaudeCodeProvider,
	CodexCliProvider,
	GeminiCliProvider,
	GoogleAIProvider,
	GrokCliProvider,
	GroqProvider,
	LMStudioProvider,
	OllamaAIProvider,
	OpenAICompatibleProvider,
	OpenAIProvider,
	OpenRouterAIProvider,
	PerplexityAIProvider,
	VertexAIProvider,
	XAIProvider,
	ZAICodingProvider,
	ZAIProvider
} from '../../src/ai-providers/index.js';

// Import the provider registry
import ProviderRegistry from '../../src/provider-registry/index.js';

// Create provider instances
const PROVIDERS = {
	anthropic: new AnthropicAIProvider(),
	perplexity: new PerplexityAIProvider(),
	google: new GoogleAIProvider(),
	zai: new ZAIProvider(),
	'zai-coding': new ZAICodingProvider(),
	lmstudio: new LMStudioProvider(),
	openai: new OpenAIProvider(),
	xai: new XAIProvider(),
	groq: new GroqProvider(),
	openrouter: new OpenRouterAIProvider(),
	ollama: new OllamaAIProvider(),
	'openai-compatible': new OpenAICompatibleProvider({
		name: 'OpenAI Compatible',
		apiKeyEnvVar: 'OPENAI_COMPATIBLE_API_KEY',
		requiresApiKey: true
		// baseURL will be set per-role from config
	}),
	bedrock: new BedrockAIProvider(),
	azure: new AzureProvider(),
	vertex: new VertexAIProvider(),
	'claude-code': new ClaudeCodeProvider(),
	'codex-cli': new CodexCliProvider(),
	'gemini-cli': new GeminiCliProvider(),
	'grok-cli': new GrokCliProvider()
};

function _getProvider(providerName) {
	// First check the static PROVIDERS object
	if (PROVIDERS[providerName]) {
		return PROVIDERS[providerName];
	}

	// If not found, check the provider registry
	const providerRegistry = ProviderRegistry.getInstance();
	if (providerRegistry.hasProvider(providerName)) {
		log('debug', `Provider "${providerName}" found in dynamic registry`);
		return providerRegistry.getProvider(providerName);
	}

	// Provider not found in either location
	return null;
}

// Helper function to get cost for a specific model
function _getCostForModel(providerName, modelId) {
	const DEFAULT_COST = {
		inputCost: 0,
		outputCost: 0,
		currency: 'USD',
		isUnknown: false
	};

	if (!MODEL_MAP || !MODEL_MAP[providerName]) {
		log(
			'warn',
			`Provider "${providerName}" not found in MODEL_MAP. Cannot determine cost for model ${modelId}.`
		);
		return { ...DEFAULT_COST, isUnknown: true };
	}

	const modelData = MODEL_MAP[providerName].find((m) => m.id === modelId);

	if (!modelData) {
		log(
			'debug',
			`Model "${modelId}" not found under provider "${providerName}". Assuming unknown cost.`
		);
		return { ...DEFAULT_COST, isUnknown: true };
	}

	// Check if cost_per_1m_tokens is explicitly null (unknown pricing)
	if (modelData.cost_per_1m_tokens === null) {
		log(
			'debug',
			`Cost data is null for model "${modelId}" under provider "${providerName}". Pricing unknown.`
		);
		return { ...DEFAULT_COST, isUnknown: true };
	}

	// Check if cost_per_1m_tokens is missing/undefined (also unknown)
	if (modelData.cost_per_1m_tokens === undefined) {
		log(
			'debug',
			`Cost data not found for model "${modelId}" under provider "${providerName}". Pricing unknown.`
		);
		return { ...DEFAULT_COST, isUnknown: true };
	}

	const costs = modelData.cost_per_1m_tokens;
	return {
		inputCost: costs.input || 0,
		outputCost: costs.output || 0,
		currency: costs.currency || 'USD',
		isUnknown: false
	};
}

/**
 * Calculate cost from token counts and cost per million
 * @param {number} inputTokens - Number of input tokens
 * @param {number} outputTokens - Number of output tokens
 * @param {number} inputCost - Cost per million input tokens
 * @param {number} outputCost - Cost per million output tokens
 * @returns {number} Total calculated cost
 */
function _calculateCost(inputTokens, outputTokens, inputCost, outputCost) {
	const calculatedCost =
		((inputTokens || 0) / 1_000_000) * inputCost +
		((outputTokens || 0) / 1_000_000) * outputCost;
	return parseFloat(calculatedCost.toFixed(6));
}

// Helper function to get tag information for responses
function _getTagInfo(projectRoot) {
	const DEFAULT_TAG_INFO = { currentTag: 'master', availableTags: ['master'] };

	try {
		if (!projectRoot) {
			return DEFAULT_TAG_INFO;
		}

		const currentTag = getCurrentTag(projectRoot) || 'master';
		const availableTags = _readAvailableTags(projectRoot);

		return { currentTag, availableTags };
	} catch (error) {
		if (getDebugFlag()) {
			log('debug', `Error getting tag information: ${error.message}`);
		}
		return DEFAULT_TAG_INFO;
	}
}

// Extract method for reading available tags
function _readAvailableTags(projectRoot) {
	const DEFAULT_TAGS = ['master'];

	try {
		const path = require('path');
		const fs = require('fs');
		const tasksPath = path.join(
			projectRoot,
			'.taskmaster',
			'tasks',
			'tasks.json'
		);

		if (!fs.existsSync(tasksPath)) {
			return DEFAULT_TAGS;
		}

		const tasksData = JSON.parse(fs.readFileSync(tasksPath, 'utf8'));
		if (!tasksData || typeof tasksData !== 'object') {
			return DEFAULT_TAGS;
		}

		// Check if it's tagged format (has tag-like keys with tasks arrays)
		const potentialTags = Object.keys(tasksData).filter((key) =>
			_isValidTaggedTask(tasksData[key])
		);

		return potentialTags.length > 0 ? potentialTags : DEFAULT_TAGS;
	} catch (readError) {
		if (getDebugFlag()) {
			log(
				'debug',
				`Could not read tasks file for available tags: ${readError.message}`
			);
		}
		return DEFAULT_TAGS;
	}
}

// Helper to validate tagged task structure
function _isValidTaggedTask(taskData) {
	return (
		taskData && typeof taskData === 'object' && Array.isArray(taskData.tasks)
	);
}

// --- Configuration for Retries ---
const MAX_RETRIES = 2;
const INITIAL_RETRY_DELAY_MS = 1000;

// Helper function to check if an error is retryable
function isRetryableError(error) {
	const errorMessage = error.message?.toLowerCase() || '';
	return (
		errorMessage.includes('rate limit') ||
		errorMessage.includes('overloaded') ||
		errorMessage.includes('service temporarily unavailable') ||
		errorMessage.includes('timeout') ||
		errorMessage.includes('network error') ||
		error.status === 429 ||
		error.status >= 500
	);
}

/**
 * Extracts a user-friendly error message from a potentially complex AI error object.
 * Prioritizes nested messages and falls back to the top-level message.
 * @param {Error | object | any} error - The error object.
 * @returns {string} A concise error message.
 */
function _extractErrorMessage(error) {
	try {
		// Attempt 1: Look for Vercel SDK specific nested structure (common)
		if (error?.data?.error?.message) {
			return error.data.error.message;
		}

		// Attempt 2: Look for nested error message directly in the error object
		if (error?.error?.message) {
			return error.error.message;
		}

		// Attempt 3: Look for nested error message in response body if it's JSON string
		if (typeof error?.responseBody === 'string') {
			try {
				const body = JSON.parse(error.responseBody);
				if (body?.error?.message) {
					return body.error.message;
				}
			} catch (parseError) {
				// Ignore if responseBody is not valid JSON
			}
		}

		// Attempt 4: Use the top-level message if it exists
		if (typeof error?.message === 'string' && error.message) {
			return error.message;
		}

		// Attempt 5: Handle simple string errors
		if (typeof error === 'string') {
			return error;
		}

		// Fallback
		return 'An unknown AI service error occurred.';
	} catch (e) {
		// Safety net
		return 'Failed to extract error message.';
	}
}

/**
 * Get role configuration (provider and model) based on role type
 * @param {string} role - The role ('main', 'research', 'fallback')
 * @param {string} projectRoot - Project root path
 * @returns {Object|null} Configuration object with provider and modelId
 */
function _getRoleConfiguration(role, projectRoot) {
	const roleConfigs = {
		main: {
			provider: getMainProvider(projectRoot),
			modelId: getMainModelId(projectRoot)
		},
		research: {
			provider: getResearchProvider(projectRoot),
			modelId: getResearchModelId(projectRoot)
		},
		fallback: {
			provider: getFallbackProvider(projectRoot),
			modelId: getFallbackModelId(projectRoot)
		}
	};

	return roleConfigs[role] || null;
}

/**
 * Get Vertex AI specific configuration
 * @param {string} projectRoot - Project root path
 * @param {Object} session - Session object
 * @returns {Object} Vertex AI configuration parameters
 */
function _getVertexConfiguration(projectRoot, session) {
	const projectId =
		getVertexProjectId(projectRoot) ||
		resolveEnvVariable('VERTEX_PROJECT_ID', session, projectRoot);

	const location =
		getVertexLocation(projectRoot) ||
		resolveEnvVariable('VERTEX_LOCATION', session, projectRoot) ||
		'us-central1';

	const credentialsPath = resolveEnvVariable(
		'GOOGLE_APPLICATION_CREDENTIALS',
		session,
		projectRoot
	);

	log(
		'debug',
		`Using Vertex AI configuration: Project ID=${projectId}, Location=${location}`
	);

	const credentials = credentialsPath
		? { keyFile: credentialsPath }
		: undefined;

	return {
		projectId,
		location,
		...(credentials && { credentials })
	};
}

/**
 * Internal helper to resolve the API key for a given provider.
 * @param {string} providerName - The name of the provider (lowercase).
 * @param {object|null} session - Optional MCP session object.
 * @param {string|null} projectRoot - Optional project root path for .env fallback.
 * @returns {string|null} The API key or null if not found/needed.
 * @throws {Error} If a required API key is missing.
 */
function _resolveApiKey(providerName, session, projectRoot = null) {
	// Get provider instance
	const provider = _getProvider(providerName);
	if (!provider) {
		throw new Error(
			`Unknown provider '${providerName}' for API key resolution.`
		);
	}

	// All providers must implement getRequiredApiKeyName()
	const envVarName = provider.getRequiredApiKeyName();

	// If envVarName is null (like for MCP), return null directly
	if (envVarName === null) {
		return null;
	}

	const apiKey = resolveEnvVariable(envVarName, session, projectRoot);

	// Special handling for providers that can use alternative auth or no API key
	if (!provider.isRequiredApiKey()) {
		return apiKey || null;
	}

	if (!apiKey) {
		throw new Error(
			`Required API key ${envVarName} for provider '${providerName}' is not set in environment, session, or .env file.`
		);
	}
	return apiKey;
}

/**
 * Internal helper to attempt a provider-specific AI API call with retries.
 *
 * @param {function} providerApiFn - The specific provider function to call (e.g., generateAnthropicText).
 * @param {object} callParams - Parameters object for the provider function.
 * @param {string} providerName - Name of the provider (for logging).
 * @param {string} modelId - Specific model ID (for logging).
 * @param {string} attemptRole - The role being attempted (for logging).
 * @returns {Promise<object>} The result from the successful API call.
 * @throws {Error} If the call fails after all retries.
 */
async function _attemptProviderCallWithRetries(
	provider,
	serviceType,
	callParams,
	providerName,
	modelId,
	attemptRole
) {
	let retries = 0;
	const fnName = serviceType;

	while (retries <= MAX_RETRIES) {
		try {
			if (getDebugFlag()) {
				log(
					'info',
					`Attempt ${retries + 1}/${MAX_RETRIES + 1} calling ${fnName} (Provider: ${providerName}, Model: ${modelId}, Role: ${attemptRole})`
				);
			}

			// Call the appropriate method on the provider instance
			const result = await provider[serviceType](callParams);

			if (getDebugFlag()) {
				log(
					'info',
					`${fnName} succeeded for role ${attemptRole} (Provider: ${providerName}) on attempt ${retries + 1}`
				);
			}
			return result;
		} catch (error) {
			log(
				'warn',
				`Attempt ${retries + 1} failed for role ${attemptRole} (${fnName} / ${providerName}): ${error.message}`
			);

			if (isRetryableError(error) && retries < MAX_RETRIES) {
				retries++;
				const delay = INITIAL_RETRY_DELAY_MS * 2 ** (retries - 1);
				log(
					'info',
					`Something went wrong on the provider side. Retrying in ${delay / 1000}s...`
				);
				await new Promise((resolve) => setTimeout(resolve, delay));
			} else {
				log(
					'error',
					`Something went wrong on the provider side. Max retries reached for role ${attemptRole} (${fnName} / ${providerName}).`
				);
				throw error;
			}
		}
	}
	// Should not be reached due to throw in the else block
	throw new Error(
		`Exhausted all retries for role ${attemptRole} (${fnName} / ${providerName})`
	);
}

/**
 * Base logic for unified service functions.
 * @param {string} serviceType - Type of service ('generateText', 'streamText', 'generateObject').
 * @param {object} params - Original parameters passed to the service function.
 * @param {string} params.role - The initial client role.
 * @param {object} [params.session=null] - Optional MCP session object.
 * @param {string} [params.projectRoot] - Optional project root path.
 * @param {string} params.commandName - Name of the command invoking the service.
 * @param {string} params.outputType - 'cli' or 'mcp'.
 * @param {string} [params.systemPrompt] - Optional system prompt.
 * @param {string} [params.prompt] - The prompt for the AI.
 * @param {string} [params.schema] - The Zod schema for the expected object.
 * @param {string} [params.objectName] - Name for object/tool.
 * @returns {Promise<any>} Result from the underlying provider call.
 */
async function _unifiedServiceRunner(serviceType, params) {
	const {
		role: initialRole,
		session,
		projectRoot,
		systemPrompt,
		prompt,
		schema,
		objectName,
		commandName,
		outputType,
		experimental_transform,
		...restApiParams
	} = params;
	if (getDebugFlag()) {
		log('info', `${serviceType}Service called`, {
			role: initialRole,
			commandName,
			outputType,
			projectRoot
		});
	}

	const effectiveProjectRoot = projectRoot || findProjectRoot();
	const userId = getUserId(effectiveProjectRoot);

	// Extract Hamster context from session if authenticated
	const hamsterUserId = session?.user?.id || session?.userId;
	const hamsterBriefId = session?.context?.briefId || session?.briefId;

	let sequence;
	if (initialRole === 'main') {
		sequence = ['main', 'fallback', 'research'];
	} else if (initialRole === 'research') {
		sequence = ['research', 'fallback', 'main'];
	} else if (initialRole === 'fallback') {
		sequence = ['fallback', 'main', 'research'];
	} else {
		log(
			'warn',
			`Unknown initial role: ${initialRole}. Defaulting to main -> fallback -> research sequence.`
		);
		sequence = ['main', 'fallback', 'research'];
	}

	let lastError = null;
	let lastCleanErrorMessage =
		'AI service call failed for all configured roles.';

	for (const currentRole of sequence) {
		let providerName;
		let modelId;
		let apiKey;
		let roleParams;
		let provider;
		let baseURL;
		let providerResponse;
		let telemetryData = null;

		try {
			log('debug', `New AI service call with role: ${currentRole}`);

			const roleConfig = _getRoleConfiguration(
				currentRole,
				effectiveProjectRoot
			);
			if (!roleConfig) {
				log(
					'error',
					`Unknown role encountered in _unifiedServiceRunner: ${currentRole}`
				);
				lastError =
					lastError || new Error(`Unknown AI role specified: ${currentRole}`);
				continue;
			}
			providerName = roleConfig.provider;
			modelId = roleConfig.modelId;

			if (!providerName || !modelId) {
				log(
					'warn',
					`Skipping role '${currentRole}': Provider or Model ID not configured.`
				);
				lastError =
					lastError ||
					new Error(
						`Configuration missing for role '${currentRole}'. Provider: ${providerName}, Model: ${modelId}`
					);
				continue;
			}

			// Get provider instance
			provider = _getProvider(providerName?.toLowerCase());
			if (!provider) {
				log(
					'warn',
					`Skipping role '${currentRole}': Provider '${providerName}' not supported.`
				);
				lastError =
					lastError ||
					new Error(`Unsupported provider configured: ${providerName}`);
				continue;
			}

			// Get base URL if configured (optional for most providers)
			baseURL = getBaseUrlForRole(currentRole, effectiveProjectRoot);

			// For Azure, use the global Azure base URL if role-specific URL is not configured
			if (providerName?.toLowerCase() === 'azure' && !baseURL) {
				baseURL = getAzureBaseURL(effectiveProjectRoot);
				log('debug', `Using global Azure base URL: ${baseURL}`);
			} else if (providerName?.toLowerCase() === 'ollama' && !baseURL) {
				// For Ollama, use the global Ollama base URL if role-specific URL is not configured
				baseURL = getOllamaBaseURL(effectiveProjectRoot);
				log('debug', `Using global Ollama base URL: ${baseURL}`);
			} else if (providerName?.toLowerCase() === 'bedrock' && !baseURL) {
				// For Bedrock, use the global Bedrock base URL if role-specific URL is not configured
				baseURL = getBedrockBaseURL(effectiveProjectRoot);
				log('debug', `Using global Bedrock base URL: ${baseURL}`);
			}

			// Get AI parameters for the current role
			roleParams = getParametersForRole(currentRole, effectiveProjectRoot);
			apiKey = _resolveApiKey(
				providerName?.toLowerCase(),
				session,
				effectiveProjectRoot
			);

			// Prepare provider-specific configuration
			let providerSpecificParams = {};

			// Handle Vertex AI specific configuration
			if (providerName?.toLowerCase() === 'vertex') {
				providerSpecificParams = _getVertexConfiguration(
					effectiveProjectRoot,
					session
				);
			}

			const messages = [];
			const responseLanguage = getResponseLanguage(effectiveProjectRoot);
			const systemPromptWithLanguage = `${systemPrompt} \n\n Always respond in ${responseLanguage}.`;
			messages.push({
				role: 'system',
				content: systemPromptWithLanguage.trim()
			});

			// IN THE FUTURE WHEN DOING CONTEXT IMPROVEMENTS
			// {
			//     type: 'text',
			//     text: 'Large cached context here like a tasks json',
			//     providerOptions: {
			//       anthropic: { cacheControl: { type: 'ephemeral' } }
			//     }
			//   }

			// Example
			// if (params.context) { // context is a json string of a tasks object or some other stu
			//     messages.push({
			//         type: 'text',
			//         text: params.context,
			//         providerOptions: { anthropic: { cacheControl: { type: 'ephemeral' } } }
			//     });
			// }

			if (prompt) {
				messages.push({ role: 'user', content: prompt });
			} else {
				throw new Error('User prompt content is missing.');
			}

			const callParams = {
				apiKey,
				modelId,
				maxTokens: roleParams.maxTokens,
				temperature: roleParams.temperature,
				messages,
				...(baseURL && { baseURL }),
				...((serviceType === 'generateObject' ||
					serviceType === 'streamObject') && { schema, objectName }),
				...(commandName && { commandName }), // Pass commandName for Sentry telemetry functionId
				...(outputType && { outputType }), // Pass outputType for Sentry telemetry metadata
				...(projectRoot && { projectRoot }), // Pass projectRoot for Sentry telemetry hashing
				...(hamsterUserId && { userId: hamsterUserId }), // Pass Hamster userId if authenticated
				...(hamsterBriefId && { briefId: hamsterBriefId }), // Pass Hamster briefId if connected
				...(experimental_transform && { experimental_transform }), // Pass smoothStream or other transforms
				...providerSpecificParams,
				...restApiParams
			};

			providerResponse = await _attemptProviderCallWithRetries(
				provider,
				serviceType,
				callParams,
				providerName,
				modelId,
				currentRole
			);

			if (userId && providerResponse && providerResponse.usage) {
				try {
					telemetryData = await logAiUsage({
						userId,
						commandName,
						providerName,
						modelId,
						inputTokens: providerResponse.usage.inputTokens,
						outputTokens: providerResponse.usage.outputTokens,
						outputType
					});
				} catch (telemetryError) {
					// logAiUsage already logs its own errors and returns null on failure
					// No need to log again here, telemetryData will remain null
				}
			} else if (userId && providerResponse && !providerResponse.usage) {
				log(
					'warn',
					`Cannot log telemetry for ${commandName} (${providerName}/${modelId}): AI result missing 'usage' data. (May be expected for streams)`
				);
			}

			let finalMainResult;
			if (serviceType === 'generateText') {
				finalMainResult = providerResponse.text;
			} else if (serviceType === 'generateObject') {
				finalMainResult = providerResponse.object;
			} else if (
				serviceType === 'streamText' ||
				serviceType === 'streamObject'
			) {
				finalMainResult = providerResponse;
			} else {
				log(
					'error',
					`Unknown serviceType in _unifiedServiceRunner: ${serviceType}`
				);
				finalMainResult = providerResponse;
			}

			// Get tag information for the response
			const tagInfo = _getTagInfo(effectiveProjectRoot);

			return {
				mainResult: finalMainResult,
				telemetryData: telemetryData,
				tagInfo: tagInfo,
				providerName: providerName,
				modelId: modelId
			};
		} catch (error) {
			const cleanMessage = _extractErrorMessage(error);
			log(
				'error',
				`Service call failed for role ${currentRole} (Provider: ${providerName || 'unknown'}, Model: ${modelId || 'unknown'}): ${cleanMessage}`
			);
			lastError = error;
			lastCleanErrorMessage = cleanMessage;

			if (serviceType === 'generateObject') {
				const lowerCaseMessage = cleanMessage.toLowerCase();
				if (
					lowerCaseMessage.includes(
						'no endpoints found that support tool use'
					) ||
					lowerCaseMessage.includes('does not support tool_use') ||
					lowerCaseMessage.includes('tool use is not supported') ||
					lowerCaseMessage.includes('tools are not supported') ||
					lowerCaseMessage.includes('function calling is not supported') ||
					lowerCaseMessage.includes('tool use is not supported')
				) {
					const specificErrorMsg = `Model '${modelId || 'unknown'}' via provider '${providerName || 'unknown'}' does not support the 'tool use' required by generateObjectService. Please configure a model that supports tool/function calling for the '${currentRole}' role, or use generateTextService if structured output is not strictly required.`;
					log('error', `[Tool Support Error] ${specificErrorMsg}`);
					throw new Error(specificErrorMsg);
				}
			}
		}
	}

	log('error', `All roles in the sequence [${sequence.join(', ')}] failed.`);
	throw new Error(lastCleanErrorMessage);
}

/**
 * Unified service function for generating text.
 * Handles client retrieval, retries, and fallback sequence.
 *
 * @param {object} params - Parameters for the service call.
 * @param {string} params.role - The initial client role ('main', 'research', 'fallback').
 * @param {object} [params.session=null] - Optional MCP session object.
 * @param {string} [params.projectRoot=null] - Optional project root path for .env fallback.
 * @param {string} params.prompt - The prompt for the AI.
 * @param {string} [params.systemPrompt] - Optional system prompt.
 * @param {string} params.commandName - Name of the command invoking the service.
 * @param {string} [params.outputType='cli'] - 'cli' or 'mcp'.
 * @returns {Promise<object>} Result object containing generated text and usage data.
 */
async function generateTextService(params) {
	// Ensure default outputType if not provided
	const defaults = { outputType: 'cli' };
	const combinedParams = { ...defaults, ...params };
	// TODO: Validate commandName exists?
	return _unifiedServiceRunner('generateText', combinedParams);
}

/**
 * Unified service function for streaming text.
 * Handles client retrieval, retries, and fallback sequence.
 *
 * @param {object} params - Parameters for the service call.
 * @param {string} params.role - The initial client role ('main', 'research', 'fallback').
 * @param {object} [params.session=null] - Optional MCP session object.
 * @param {string} [params.projectRoot=null] - Optional project root path for .env fallback.
 * @param {string} params.prompt - The prompt for the AI.
 * @param {string} [params.systemPrompt] - Optional system prompt.
 * @param {string} params.commandName - Name of the command invoking the service.
 * @param {string} [params.outputType='cli'] - 'cli' or 'mcp'.
 * @returns {Promise<object>} Result object containing the stream and usage data.
 */
async function streamTextService(params) {
	const defaults = { outputType: 'cli' };
	const combinedParams = { ...defaults, ...params };
	// TODO: Validate commandName exists?
	// NOTE: Telemetry for streaming might be tricky as usage data often comes at the end.
	// The current implementation logs *after* the stream is returned.
	// We might need to adjust how usage is captured/logged for streams.
	return _unifiedServiceRunner('streamText', combinedParams);
}

/**
 * Unified service function for streaming structured objects.
 * Uses Vercel AI SDK's streamObject for proper JSON streaming.
 *
 * @param {object} params - Parameters for the service call.
 * @param {string} params.role - The initial client role ('main', 'research', 'fallback').
 * @param {object} [params.session=null] - Optional MCP session object.
 * @param {string} [params.projectRoot=null] - Optional project root path for .env fallback.
 * @param {import('zod').ZodSchema} params.schema - The Zod schema for the expected object.
 * @param {string} params.prompt - The prompt for the AI.
 * @param {string} [params.systemPrompt] - Optional system prompt.
 * @param {string} params.commandName - Name of the command invoking the service.
 * @param {string} [params.outputType='cli'] - 'cli' or 'mcp'.
 * @returns {Promise<object>} Result object containing the stream and usage data.
 */
async function streamObjectService(params) {
	const defaults = { outputType: 'cli' };
	const combinedParams = { ...defaults, ...params };
	// Stream object requires a schema
	if (!combinedParams.schema) {
		throw new Error('streamObjectService requires a schema parameter');
	}
	return _unifiedServiceRunner('streamObject', combinedParams);
}

/**
 * Unified service function for generating structured objects.
 * Handles client retrieval, retries, and fallback sequence.
 *
 * @param {object} params - Parameters for the service call.
 * @param {string} params.role - The initial client role ('main', 'research', 'fallback').
 * @param {object} [params.session=null] - Optional MCP session object.
 * @param {string} [params.projectRoot=null] - Optional project root path for .env fallback.
 * @param {import('zod').ZodSchema} params.schema - The Zod schema for the expected object.
 * @param {string} params.prompt - The prompt for the AI.
 * @param {string} [params.systemPrompt] - Optional system prompt.
 * @param {string} [params.objectName='generated_object'] - Name for object/tool.
 * @param {number} [params.maxRetries=3] - Max retries for object generation.
 * @param {string} params.commandName - Name of the command invoking the service.
 * @param {string} [params.outputType='cli'] - 'cli' or 'mcp'.
 * @returns {Promise<object>} Result object containing the generated object and usage data.
 */
async function generateObjectService(params) {
	const defaults = {
		objectName: 'generated_object',
		maxRetries: 3,
		outputType: 'cli'
	};
	const combinedParams = { ...defaults, ...params };
	// TODO: Validate commandName exists?
	return _unifiedServiceRunner('generateObject', combinedParams);
}

// --- Telemetry Function ---
/**
 * Logs AI usage telemetry data.
 * For now, it just logs to the console. Sending will be implemented later.
 * @param {object} params - Telemetry parameters.
 * @param {string} params.userId - Unique user identifier.
 * @param {string} params.commandName - The command that triggered the AI call.
 * @param {string} params.providerName - The AI provider used (e.g., 'openai').
 * @param {string} params.modelId - The specific AI model ID used.
 * @param {number} params.inputTokens - Number of input tokens.
 * @param {number} params.outputTokens - Number of output tokens.
 */
async function logAiUsage({
	userId,
	commandName,
	providerName,
	modelId,
	inputTokens,
	outputTokens,
	outputType
}) {
	try {
		const isMCP = outputType === 'mcp';
		const timestamp = new Date().toISOString();
		const totalTokens = (inputTokens || 0) + (outputTokens || 0);

		// Destructure currency along with costs and unknown flag
		const { inputCost, outputCost, currency, isUnknown } = _getCostForModel(
			providerName,
			modelId
		);

		const totalCost = _calculateCost(
			inputTokens,
			outputTokens,
			inputCost,
			outputCost
		);

		const telemetryData = {
			timestamp,
			userId,
			commandName,
			modelUsed: modelId, // Consistent field name from requirements
			providerName, // Keep provider name for context
			inputTokens: inputTokens || 0,
			outputTokens: outputTokens || 0,
			totalTokens,
			totalCost,
			currency, // Add currency to the telemetry data
			isUnknownCost: isUnknown // Flag to indicate if pricing is unknown
		};

		if (getDebugFlag()) {
			log('info', 'AI Usage Telemetry:', telemetryData);
		}

		// TODO (Subtask 77.2): Send telemetryData securely to the external endpoint.

		return telemetryData;
	} catch (error) {
		log('error', `Failed to log AI usage telemetry: ${error.message}`, {
			error
		});
		// Don't re-throw; telemetry failure shouldn't block core functionality.
		return null;
	}
}

export {
	generateTextService,
	streamTextService,
	streamObjectService,
	generateObjectService,
	logAiUsage
};


## Links discovered
- [serviceType](https://github.com/eyaltoledano/claude-task-master/blob/main/scripts/modules/callParams.md)

--- scripts/modules/bridge-utils.js ---
import { getDebugFlag } from './config-manager.js';
import { log as consoleLog, isSilentMode } from './utils.js';

/**
 * Create a unified logger and report function for bridge operations
 * Handles both MCP and CLI contexts consistently
 *
 * @param {Object} mcpLog - Optional MCP logger object
 * @param {Object} [session] - Optional session object for debug flag checking
 * @returns {Object} Object containing logger, report function, and isMCP flag
 */
export function createBridgeLogger(mcpLog, session) {
	const isMCP = !!mcpLog;

	// Create logger that works in both contexts
	const logger = mcpLog || {
		info: (msg) => !isSilentMode() && consoleLog('info', msg),
		warn: (msg) => !isSilentMode() && consoleLog('warn', msg),
		error: (msg) => !isSilentMode() && consoleLog('error', msg),
		debug: (msg) =>
			!isSilentMode() && getDebugFlag(session) && consoleLog('debug', msg)
	};

	// Create report function compatible with bridge
	const report = (level, ...args) => {
		if (isMCP) {
			if (typeof logger[level] === 'function') logger[level](...args);
			else logger.info(...args);
		} else if (!isSilentMode()) {
			consoleLog(level, ...args);
		}
	};

	return { logger, report, isMCP };
}


## Links discovered
- [level](https://github.com/eyaltoledano/claude-task-master/blob/main/scripts/modules/...args)

--- packages/ai-sdk-provider-grok-cli/CHANGELOG.md ---
# @tm/ai-sdk-provider-grok-cli

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null


--- scripts/modules/commands.js ---
/**
 * commands.js
 * Command-line interface for the Task Master CLI
 */

import fs from 'fs';
import path from 'path';
import boxen from 'boxen';
import chalk from 'chalk';
import { Command } from 'commander';
import inquirer from 'inquirer';

// Import command registry and utilities from @tm/cli
import {
	checkForUpdate,
	displayError,
	displayUpgradeNotification,
	performAutoUpdate,
	registerAllCommands,
	restartWithNewVersion,
	runInteractiveSetup
} from '@tm/cli';
import { findProjectRoot, log, readJSON } from './utils.js';

import {
	addSubtask,
	addTask,
	analyzeTaskComplexity,
	clearSubtasks,
	expandAllTasks,
	expandTask,
	findTaskById,
	migrateProject,
	moveTask,
	parsePRD,
	removeSubtask,
	removeTask,
	scopeDownTask,
	scopeUpTask,
	setResponseLanguage,
	taskExists,
	updateSubtaskById,
	updateTaskById,
	updateTasks,
	validateStrength
} from './task-manager.js';

import { moveTasksBetweenTags } from './task-manager/move-task.js';

import {
	getApiKeyStatusReport,
	getAvailableModelsList,
	getModelConfiguration,
	setModel
} from './task-manager/models.js';

import {
	copyTag,
	createTag,
	deleteTag,
	renameTag,
	tags,
	useTag
} from './task-manager/tag-management.js';

import {
	addDependency,
	fixDependenciesCommand,
	removeDependency,
	validateDependenciesCommand
} from './dependency-manager.js';

import { checkAndBlockIfAuthenticated, ensureOrgSelected } from '@tm/cli';
import { LOCAL_ONLY_COMMANDS } from '@tm/core';

import {
	ConfigurationError,
	getConfig,
	getDebugFlag,
	getDefaultNumTasks,
	getOperatingMode,
	isApiKeySet,
	isConfigFilePresent,
	setSuppressConfigWarnings
} from './config-manager.js';

import {
	displayFormattedError,
	displayInfo,
	displaySuccess,
	displayWarning
} from './error-formatter.js';

import {
	AuthDomain,
	AuthManager,
	CUSTOM_PROVIDERS,
	createTmCore
} from '@tm/core';

import {
	COMPLEXITY_REPORT_FILE,
	TASKMASTER_DOCS_DIR,
	TASKMASTER_TASKS_FILE
} from '../../src/constants/paths.js';

import { initTaskMaster } from '../../src/task-master.js';

import {
	confirmProfilesRemove,
	confirmRemoveAllRemainingProfiles
} from '../../src/ui/confirm.js';
import {
	getInstalledProfiles,
	wouldRemovalLeaveNoProfiles
} from '../../src/utils/profiles.js';
import {
	confirmTaskOverwrite,
	displayApiKeyStatus,
	displayAvailableModels,
	displayBanner,
	displayComplexityReport,
	displayCrossTagDependencyError,
	displayCurrentTagIndicator,
	displayDependencyValidationHints,
	displayHelp,
	displayInvalidTagCombinationError,
	displayModelConfiguration,
	displaySubtaskMoveError,
	displayTaggedTasksFYI,
	getStatusWithColor,
	startLoadingIndicator,
	stopLoadingIndicator
} from './ui.js';

import { RULE_PROFILES } from '../../src/constants/profiles.js';
import {
	RULES_ACTIONS,
	RULES_SETUP_ACTION,
	isValidRulesAction
} from '../../src/constants/rules-actions.js';
import { getTaskMasterVersion } from '../../src/utils/getVersion.js';
import {
	categorizeProfileResults,
	categorizeRemovalResults,
	generateProfileRemovalSummary,
	generateProfileSummary,
	processRuleProfiles,
	runInteractiveProfilesSetup
} from '../../src/utils/profiles.js';
import { detectInstalledIDEs } from '@tm/profiles';
import {
	convertAllRulesToProfileRules,
	getRulesProfile,
	isValidProfile,
	removeProfileRules
} from '../../src/utils/rule-transformer.js';
import { initializeProject } from '../init.js';

/**
 * Check if the user is connected to a Hamster brief
 * @returns {boolean} True if connected to Hamster (has brief context OR has API storage configured)
 */
function isConnectedToHamster() {
	try {
		const authManager = AuthManager.getInstance();
		const context = authManager.getContext();

		// Check if user has a brief context
		if (context && context.briefId) {
			return true;
		}

		// Fallback: Check if storage type is 'api' (user selected Hamster during init)
		// Suppress warnings during this check since we're detecting API mode
		setSuppressConfigWarnings(true);
		try {
			const config = getConfig(null, false, { storageType: 'api' });
			if (config?.storage?.type === 'api') {
				return true;
			}
		} catch {
			// Config check failed, continue
		} finally {
			setSuppressConfigWarnings(false);
		}

		return false;
	} catch {
		return false;
	}
}

/**
 * Prompt user about using Hamster for collaborative PRD management
 * Only shown to users who are not already connected to Hamster
 * @returns {Promise<'local'|'hamster'>} User's choice
 */
async function promptHamsterCollaboration() {
	// Skip prompt in non-interactive mode only
	if (!process.stdin.isTTY) {
		return 'local';
	}

	console.log(
		'\n' +
			chalk.bold.white(
				'Your tasks are only as good as the context behind them.'
			) +
			'\n\n' +
			chalk.dim(
				'Parse locally and tasks will be stored in a JSON file. Bring it to Hamster and your brief\nbecomes part of a living system connected to your team, your codebase and your agents.\nNow your entire team can go as fast as you can with Taskmaster.'
			) +
			'\n'
	);

	const { choice } = await inquirer.prompt([
		{
			type: 'list',
			name: 'choice',
			message: chalk.cyan('How would you like to parse your PRD?\n'),
			choices: [
				{
					name: [
						chalk.bold('Parse locally'),
						'',
						chalk.white(
							'   • Your PRD becomes a task list in a local JSON file'
						),
						chalk.white(
							'   • Great for quick prototyping and for vibing on your own'
						),
						chalk.white('   • You can always export to Hamster later'),
						''
					].join('\n'),
					value: 'local',
					short: 'Parse locally'
				},
				{
					name: [
						chalk.bold('Bring it to Hamster'),
						'',
						chalk.white(
							'   • Your PRD will become a living brief you can refine with your team'
						),
						chalk.white(
							'   • Hamster will generate tasks automatically, ready to execute in Taskmaster'
						),
						chalk.white(
							'   • Hamster will automatically analyze complexity and expand tasks as needed'
						),
						chalk.white(
							'   • Invite your teammates to collaborate on a single source of truth'
						),
						chalk.white(
							'   • AI inference handled by Hamster, no API keys needed - just a Hamster account!'
						),
						''
					].join('\n'),
					value: 'hamster',
					short: 'Bring it to Hamster'
				}
			],
			default: 'local',
			pageSize: 20
		}
	]);

	return choice;
}

/**
 * Handle parsing PRD to Hamster
 * Creates a brief from the PRD content and sets context
 * @param {string} prdPath - Path to the PRD file
 */
async function handleParsePrdToHamster(prdPath) {
	const ora = (await import('ora')).default;
	const open = (await import('open')).default;
	let spinner;
	let authSpinner;

	try {
		// Check if user is authenticated
		const authDomain = new AuthDomain();
		const isAuthenticated = await authDomain.hasValidSession();

		if (!isAuthenticated) {
			console.log('');
			console.log(chalk.yellow('🔒 Authentication Required'));
			console.log('');

			const { shouldLogin } = await inquirer.prompt([
				{
					type: 'confirm',
					name: 'shouldLogin',
					message: "You're not logged in. Log in to create a brief on Hamster?",
					default: true
				}
			]);

			if (!shouldLogin) {
				console.log(chalk.gray('\n  Cancelled.\n'));
				return;
			}

			// 10 minute timeout to allow for email confirmation during sign-up
			const AUTH_TIMEOUT_MS = 10 * 60 * 1000;
			let countdownInterval = null;

			const startCountdown = (totalMs) => {
				const startTime = Date.now();
				const endTime = startTime + totalMs;

				const updateCountdown = () => {
					const remaining = Math.max(0, endTime - Date.now());
					const mins = Math.floor(remaining / 60000);
					const secs = Math.floor((remaining % 60000) / 1000);
					const timeStr = `${mins}:${secs.toString().padStart(2, '0')}`;

					if (authSpinner) {
						authSpinner.text = `Waiting for authentication... ${chalk.cyan(timeStr)} remaining`;
					}

					if (remaining <= 0 && countdownInterval) {
						clearInterval(countdownInterval);
					}
				};

				authSpinner = ora({
					text: `Waiting for authentication... ${chalk.cyan('10:00')} remaining`,
					spinner: 'dots'
				}).start();

				countdownInterval = setInterval(updateCountdown, 1000);
			};

			const stopCountdown = (success) => {
				if (countdownInterval) {
					clearInterval(countdownInterval);
					countdownInterval = null;
				}
				if (authSpinner) {
					if (success) {
						authSpinner.succeed('Authentication successful!');
					} else {
						authSpinner.fail('Authentication failed');
					}
					authSpinner = null;
				}
			};

			// Trigger OAuth flow
			try {
				await authDomain.authenticateWithOAuth({
					openBrowser: async (authUrl) => {
						await open(authUrl);
					},
					timeout: AUTH_TIMEOUT_MS,
					onAuthUrl: (authUrl) => {
						console.log(chalk.blue.bold('\n[auth] Browser Authentication\n'));
						console.log(
							chalk.white('  Opening your browser to authenticate...')
						);
						console.log(chalk.gray("  If the browser doesn't open, visit:"));
						console.log(chalk.cyan.underline(`  ${authUrl}\n`));
					},
					onWaitingForAuth: () => {
						console.log(
							chalk.dim(
								'  If you signed up, check your email to confirm your account.'
							)
						);
						console.log(
							chalk.dim(
								'  The CLI will automatically detect when you log in.\n'
							)
						);
						startCountdown(AUTH_TIMEOUT_MS);
					},
					onSuccess: () => {
						stopCountdown(true);
					},
					onError: () => {
						stopCountdown(false);
					}
				});
			} catch (authError) {
				stopCountdown(false);
				console.error(
					chalk.red(
						`\n  Authentication failed: ${authError.message || 'Unknown error'}\n`
					)
				);
				return;
			}
		}

		const authManager = AuthManager.getInstance();

		// Always prompt for organization selection for parse-prd
		// This allows users to choose which org to create the brief in
		// even if they have one already selected in context
		const orgResult = await ensureOrgSelected(authManager, {
			promptMessage: 'Select an organization to create the brief in:',
			forceSelection: true
		});
		if (!orgResult.success) {
			console.error(
				chalk.red(
					`\n  ${orgResult.message || 'Organization selection cancelled.'}\n`
				)
			);
			return;
		}

		// Read PRD file content
		const prdContent = fs.readFileSync(prdPath, 'utf-8');
		if (!prdContent.trim()) {
			console.error(chalk.red('\n  PRD file is empty.\n'));
			return;
		}

		// Initialize TmCore
		const projectRoot = findProjectRoot() || process.cwd();
		const tmCore = await createTmCore({ projectPath: projectRoot });

		// Ask about inviting collaborators BEFORE creating brief
		let inviteEmails = [];
		const { wantsToInvite } = await inquirer.prompt([
			{
				type: 'confirm',
				name: 'wantsToInvite',
				message: 'Want to invite teammates to collaborate on this brief?',
				default: false
			}
		]);

		if (wantsToInvite) {
			const { emails } = await inquirer.prompt([
				{
					type: 'input',
					name: 'emails',
					message: 'Enter email addresses to invite (comma-separated, max 10):',
					validate: (input) => {
						if (!input.trim()) return true;
						const emailList = input
							.split(',')
							.map((e) => e.trim())
							.filter(Boolean);
						if (emailList.length > 10) {
							return 'Maximum 10 email addresses allowed';
						}
						return true;
					}
				}
			]);
			inviteEmails = emails
				.split(',')
				.map((e) => e.trim())
				.filter(Boolean)
				.slice(0, 10);
		}

		// Create brief from PRD (invitations are sent separately now)
		spinner = ora('Creating brief from your PRD...').start();

		const result = await tmCore.integration.generateBriefFromPrd({
			prdContent,
			options: {
				generateTitle: true,
				generateDescription: true
			}
		});

		if (!result.success || !result.brief) {
			spinner.fail('Failed to create brief');
			const errorMsg = result.error?.message || 'Unknown error occurred';
			console.error(chalk.red(`\n  ${errorMsg}\n`));
			return;
		}

		// Brief created! Show it immediately
		spinner.succeed('Brief created!');
		console.log('');
		console.log(
			chalk.green('  ✓ ') + chalk.white.bold(result.brief.title || 'New Brief')
		);
		console.log('');
		// Create clickable URL
		const briefUrl = result.brief.url;
		// ANSI hyperlink: \x1b]8;;URL\x07TEXT\x1b]8;;\x07
		const clickableUrl = `\x1b]8;;${briefUrl}\x07${chalk.cyan.underline(briefUrl)}\x1b]8;;\x07`;
		console.log(`  ${clickableUrl}`);
		console.log('');

		// Send invitations immediately after brief creation (before polling)
		// Extract org slug from brief URL for invitations
		const urlMatch = result.brief.url.match(
			/^(https?:\/\/[^/]+)\/home\/([^/]+)\/briefs\//
		);
		const orgSlug = urlMatch ? urlMatch[2] : null;

		if (inviteEmails.length > 0 && orgSlug) {
			const inviteSpinner = ora('Sending invitations...').start();
			try {
				const inviteResult = await tmCore.integration.sendTeamInvitations(
					orgSlug,
					inviteEmails,
					'member'
				);

				if (inviteResult.success && inviteResult.invitations) {
					inviteSpinner.succeed('Invitations sent!');
					console.log('');
					console.log(chalk.cyan('  Team Invitations:'));
					for (const inv of inviteResult.invitations) {
						if (inv.status === 'sent') {
							console.log(chalk.green(`    ${inv.email}: Invitation sent`));
						} else if (inv.status === 'already_member') {
							console.log(
								chalk.gray(`    ${inv.email}: Already a team member`)
							);
						} else if (inv.status === 'failed') {
							console.log(chalk.red(`    ${inv.email}: Failed to send`));
						} else if (inv.status === 'already_invited') {
							console.log(chalk.gray(`    ${inv.email}: Already invited`));
						}
					}
					console.log('');
				} else {
					inviteSpinner.fail('Failed to send invitations');
					const errorMsg =
						inviteResult.error?.message || 'Unknown error occurred';
					console.error(chalk.red(`  ${errorMsg}`));
					console.log('');
				}
			} catch (inviteError) {
				inviteSpinner.fail('Failed to send invitations');
				console.error(chalk.red(`  ${inviteError.message}`));
				console.log('');
			}
		}

		// Now poll for task generation
		spinner = ora('Generating tasks from your PRD...').start();
		const briefId = result.brief.id;
		const maxWait = 180000; // 3 minutes
		const pollInterval = 3000; // 3 seconds between polls
		const startTime = Date.now();
		let taskCount = 0;
		let briefStatus = result.brief.status;

		// Progress calculation helper
		const calculateProgress = (prog) => {
			if (!prog) return 0;
			const phase = prog.phase || prog.currentPhase || '';
			const parentGen =
				prog.parentTasksGenerated || prog.progress?.parentTasksGenerated || 0;
			const parentProc =
				prog.parentTasksProcessed || prog.progress?.parentTasksProcessed || 0;
			const totalParent =
				prog.totalParentTasks || prog.progress?.totalParentTasks || 0;

			if (phase === 'queued') return 0;
			if (phase === 'analyzing') return 5;
			if (phase === 'generating_tasks' && totalParent > 0) {
				return 10 + Math.floor((parentGen / totalParent) * 40);
			}
			if (phase === 'processing_tasks' && totalParent > 0) {
				return 50 + Math.floor((parentProc / totalParent) * 40);
			}
			if (phase === 'generating_subtasks') return 90;
			if (phase === 'complete') return 100;
			return 0;
		};

		// Progress bar renderer
		const renderProgressBar = (percent, width = 30) => {
			const filled = Math.floor((percent / 100) * width);
			const empty = width - filled;
			return chalk.cyan('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
		};

		// Poll until status is 'ready' or 'failed' or we timeout
		const isStillGenerating = (s) =>
			s === 'generating' || s === 'pending' || s === 'pending_plan';

		while (isStillGenerating(briefStatus) && Date.now() - startTime < maxWait) {
			await new Promise((resolve) => setTimeout(resolve, pollInterval));

			try {
				const statusResult = await tmCore.integration.getBriefStatus(briefId);
				if (statusResult.success && statusResult.status) {
					const status = statusResult.status;
					briefStatus = status.status;

					// Update spinner with progress bar
					if (status.progress) {
						const prog = status.progress;
						const parentGen =
							prog.parentTasksGenerated ||
							prog.progress?.parentTasksGenerated ||
							0;
						const parentProc =
							prog.parentTasksProcessed ||
							prog.progress?.parentTasksProcessed ||
							0;
						const totalParent =
							prog.totalParentTasks || prog.progress?.totalParentTasks || 0;
						const subtaskGen =
							prog.subtasksGenerated || prog.progress?.subtasksGenerated || 0;
						taskCount = parentGen + subtaskGen;

						const percent = calculateProgress(prog);
						const progressBar = renderProgressBar(percent);
						const phase = prog.phase || prog.currentPhase || 'generating';

						let statusText = `${progressBar} ${percent}%`;
						if (phase === 'generating_tasks' && totalParent > 0) {
							statusText += ` • Generating tasks (${parentGen}/${totalParent})`;
						} else if (phase === 'processing_tasks' && totalParent > 0) {
							statusText += ` • Processing (${parentProc}/${totalParent})`;
							if (subtaskGen > 0) {
								statusText += ` • ${subtaskGen} subtasks`;
							}
						} else if (phase === 'generating_subtasks') {
							statusText += ` • ${subtaskGen} subtasks generated`;
						} else if (prog.message) {
							statusText += ` • ${prog.message}`;
						}

						spinner.text = statusText;
					}

					// Check for completion states
					if (status.status === 'ready' || status.status === 'completed') {
						break;
					}
					if (status.status === 'failed') {
						spinner.fail('Task generation failed');
						const errorMsg =
							status.error || 'Task generation failed on Hamster.';
						console.error(chalk.red(`\n  ${errorMsg}\n`));
						return;
					}
				}
			} catch {
				// Continue polling on error
			}
		}

		// Check if we timed out while still generating
		if (isStillGenerating(briefStatus)) {
			spinner.warn('Task generation is still in progress');
			console.log('');
			console.log(
				chalk.yellow('  Tasks are still being generated in the background.')
			);
			console.log(chalk.white('  Check the brief URL above for progress.'));
		} else {
			spinner.succeed(
				taskCount > 0
					? `Done! ${taskCount} tasks generated`
					: 'Task generation complete'
			);
		}
		console.log('');

		// Show invite URL for adding more teammates later (orgSlug already extracted above)
		if (orgSlug) {
			const urlParts = result.brief.url.match(/^(https?:\/\/[^/]+)/);
			const baseUrl = urlParts ? urlParts[1] : '';
			const membersUrl = `${baseUrl}/home/${orgSlug}/members`;
			const clickableMembersUrl = `\x1b]8;;${membersUrl}\x07${chalk.cyan.underline(membersUrl)}\x1b]8;;\x07`;
			console.log(
				chalk.gray('  Invite more teammates: ') + clickableMembersUrl
			);
			console.log('');
		}

		// Set context to the new brief using resolveBrief (same as tm context <url>)
		try {
			const brief = await tmCore.tasks.resolveBrief(result.brief.url);
			const briefName =
				brief.document?.title || `Brief ${brief.id.slice(0, 8)}`;

			// Get org info for complete context
			let orgName;
			try {
				const org = await authManager.getOrganization(brief.accountId);
				orgName = org?.name;
			} catch {
				// Non-fatal if org lookup fails
			}

			await authManager.updateContext({
				orgId: brief.accountId,
				orgName,
				orgSlug,
				briefId: brief.id,
				briefName,
				briefStatus: brief.status,
				briefUpdatedAt: brief.updatedAt
			});

			console.log(
				chalk.green('  ✓ ') +
					chalk.white('Context set! Run ') +
					chalk.cyan('tm list') +
					chalk.white(' to see your tasks.')
			);
		} catch (contextError) {
			// Log the actual error for debugging
			log('debug', `Context auto-set failed: ${contextError.message}`);
			console.log(
				chalk.yellow('  Could not auto-set context. Run ') +
					chalk.cyan(`tm context ${result.brief.url}`) +
					chalk.yellow(' to connect.')
			);
		}
		console.log('');
	} catch (error) {
		if (spinner?.isSpinning) spinner.fail('Failed');
		console.error(chalk.red(`\n  Error: ${error.message}\n`));
	}
}

/**
 * Helper to create aligned command entries
 */
function createCommandEntry(command, description, indent = '  ') {
	const cmdColumn = 47; // Fixed column width for commands
	const paddingNeeded = Math.max(1, cmdColumn - indent.length - command.length);
	return (
		chalk.cyan(indent + command) +
		' '.repeat(paddingNeeded) +
		chalk.gray(description)
	);
}

/**
 * Display Hamster-specific help (simplified command list)
 */
function displayHamsterHelp() {
	// Calculate box width (use 90% of terminal width, min 80, max 120)
	const terminalWidth = process.stdout.columns || 80;
	const boxWidth = Math.min(120, Math.max(80, Math.floor(terminalWidth * 0.9)));

	console.log(
		boxen(
			chalk.cyan.bold('Taskmaster CLI - Connected to Hamster\n\n') +
				chalk.white(
					'Taskmaster syncs tasks from your Hamster brief and provides a CLI\n'
				) +
				chalk.white(
					'interface to execute the plan. Commands can be used by humans or AI agents.\n\n'
				) +
				chalk.dim(
					'Tasks are managed in Hamster Studio. Changes sync automatically.\n'
				) +
				chalk.dim(
					'Use these commands to view tasks and update their status:\n\n'
				) +
				boxen('  Task Management  ', {
					padding: 0,
					borderStyle: 'round',
					borderColor: 'yellow'
				}) +
				'\n' +
				createCommandEntry('list', 'View all tasks from the brief\n') +
				createCommandEntry(
					'list <status>',
					'Filter by status (e.g., pending, done, in-progress)\n'
				) +
				createCommandEntry(
					'list all',
					'View all tasks with subtasks expanded\n'
				) +
				createCommandEntry('show <id>', 'Show detailed task/subtask info\n') +
				createCommandEntry('next', 'See the next task to work on\n') +
				createCommandEntry(
					'set-status|status <id> <status>',
					'Update task status (pending, in-progress, done)\n'
				) +
				createCommandEntry(
					'update-task <id> <prompt>',
					'Add information to a task\n'
				) +
				'\n' +
				boxen('  Authentication & Context  ', {
					padding: 0,
					borderStyle: 'round',
					borderColor: 'yellow'
				}) +
				'\n' +
				createCommandEntry('auth login', 'Log in to Hamster\n') +
				createCommandEntry('auth logout', 'Log out from Hamster\n') +
				createCommandEntry('auth refresh', 'Refresh authentication token\n') +
				createCommandEntry('auth status', 'Check authentication status\n') +
				createCommandEntry('briefs', 'View and select from your briefs\n') +
				createCommandEntry('context', 'Show current brief context\n') +
				createCommandEntry('context org', 'Switch organization\n') +
				createCommandEntry(
					'context brief <url>',
					'Switch to a different brief\n'
				) +
				'\n' +
				boxen('  Configuration  ', {
					padding: 0,
					borderStyle: 'round',
					borderColor: 'yellow'
				}) +
				'\n' +
				createCommandEntry(
					'rules --setup',
					'Configure AI IDE rules for better integration\n\n'
				) +
				boxen('  Examples  ', {
					padding: 0,
					borderStyle: 'round',
					borderColor: 'yellow'
				}) +
				'\n' +
				createCommandEntry('tm list', 'See all tasks\n', '  ').replace(
					chalk.cyan('  tm'),
					chalk.dim('  tm')
				) +
				createCommandEntry(
					'tm list done',
					'See completed tasks\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm list in-progress',
					'See tasks in progress\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm list all',
					'View with all subtasks\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm show HAM-1,HAM-2',
					'View multiple tasks\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm status HAM-1,HAM-2 in-progress',
					'Start tasks\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm status HAM-1 done',
					'Mark task complete\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm update-task HAM-1 <content>',
					'Add info/context/breadcrumbs to task\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				createCommandEntry(
					'tm briefs',
					'View briefs and select one\n\n',
					'  '
				).replace(chalk.cyan('  tm'), chalk.dim('  tm')) +
				chalk.white.bold('» Need more commands?\n') +
				chalk.gray(
					'Advanced features (models, tags, PRD parsing) are managed in Hamster Studio.'
				),
			{
				padding: 1,
				margin: { top: 1 },
				borderStyle: 'round',
				borderColor: 'cyan',
				width: boxWidth
			}
		)
	);
}

/**
 * Configure and register CLI commands
 * @param {Object} program - Commander program instance
 */
function registerCommands(programInstance) {
	// Add global error handler for unknown options
	programInstance.on('option:unknown', function (unknownOption) {
		const commandName = this._name || 'unknown';
		displayFormattedError(new Error(`Unknown option '${unknownOption}'`), {
			context: `Running command: ${commandName}`,
			command: `task-master ${commandName}`,
			debug: getDebugFlag()
		});
		process.exit(1);
	});

	// Add help command alias - context-aware (Hamster vs Local)
	programInstance
		.command('help')
		.description('Show help information (Hamster-aware)')
		.action(() => {
			if (isConnectedToHamster()) {
				displayHamsterHelp();
			} else {
				programInstance.help();
			}
		});

	// Override default help to be Hamster-aware
	programInstance.configureHelp({
		helpWidth: 120,
		sortSubcommands: false
	});
	const originalHelp = programInstance.help.bind(programInstance);
	programInstance.help = function () {
		if (isConnectedToHamster()) {
			displayHamsterHelp();
		} else {
			originalHelp();
		}
	};

	// Add global command guard for local-only commands
	programInstance.hook('preAction', async (thisCommand, actionCommand) => {
		const commandName = actionCommand.name();

		// Only check if it's a local-only command
		if (LOCAL_ONLY_COMMANDS.includes(commandName)) {
			const taskMaster = initTaskMaster(actionCommand.opts());
			const isBlocked = await checkAndBlockIfAuthenticated(
				commandName,
				taskMaster.getProjectRoot()
			);
			if (isBlocked) {
				process.exit(1);
			}
		}
	});

	// parse-prd command
	programInstance
		.command('parse-prd')
		.description('Parse a PRD file and generate tasks')
		.argument('[file]', 'Path to the PRD file')
		.option(
			'-i, --input <file>',
			'Path to the PRD file (alternative to positional argument)'
		)
		.option('-o, --output <file>', 'Output file path')
		.option(
			'-n, --num-tasks <number>',
			'Number of tasks to generate',
			getDefaultNumTasks()
		)
		.option('-f, --force', 'Skip confirmation when overwriting existing tasks')
		.option(
			'--append',
			'Append new tasks to existing tasks.json instead of overwriting'
		)
		.option(
			'-r, --research',
			'Use Perplexity AI for research-backed task generation, providing more comprehensive and accurate task breakdown'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (file, options) => {
			// Resolve PRD path: prioritize --input option, then positional argument
			const prdPath = options.input || file;

			// Initialize TaskMaster
			let taskMaster;
			try {
				const initOptions = {
					prdPath: prdPath || true,
					tag: options.tag
				};
				// Only include tasksPath if output is explicitly specified
				if (options.output) {
					initOptions.tasksPath = options.output;
				}
				taskMaster = initTaskMaster(initOptions);
			} catch (error) {
				displayFormattedError(error, {
					context: 'Initializing Task Master for PRD parsing',
					command: 'task-master parse-prd',
					debug: getDebugFlag()
				});

				// Show usage help after error
				displayInfo(
					`${chalk.cyan('Usage:')}\n  task-master parse-prd <prd-file.txt> [options]\n\n${chalk.cyan('Options:')}\n  -i, --input <file>       Path to the PRD file\n  -o, --output <file>      Output file path\n  -n, --num-tasks <number> Number of tasks to generate\n  -f, --force              Skip confirmation\n  --append                 Append to existing tasks\n  -r, --research           Use Perplexity AI\n\n${chalk.cyan('Examples:')}\n  task-master parse-prd requirements.txt --num-tasks 15\n  task-master parse-prd --input=requirements.txt\n  task-master parse-prd requirements.txt --research`,
					'Parse PRD Help'
				);
				process.exit(1);
			}

			const numTasks = parseInt(options.numTasks, 10);
			const force = options.force || false;
			const append = options.append || false;
			const research = options.research || false;
			let useForce = force;
			const useAppend = append;

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			// Prompt about Hamster collaboration (only for local users)
			const collaborationChoice = await promptHamsterCollaboration();
			if (collaborationChoice === 'hamster') {
				// User chose Hamster - send PRD to Hamster for brief creation
				await handleParsePrdToHamster(taskMaster.getPrdPath());
				return;
			}

			// Helper function to check if there are existing tasks in the target tag and confirm overwrite
			async function confirmOverwriteIfNeeded() {
				// Check if there are existing tasks in the target tag
				let hasExistingTasksInTag = false;
				const tasksPath = taskMaster.getTasksPath();
				if (fs.existsSync(tasksPath)) {
					try {
						// Read the entire file to check if the tag exists
						const existingFileContent = fs.readFileSync(tasksPath, 'utf8');
						const allData = JSON.parse(existingFileContent);

						// Check if the target tag exists and has tasks
						if (
							allData[tag] &&
							Array.isArray(allData[tag].tasks) &&
							allData[tag].tasks.length > 0
						) {
							hasExistingTasksInTag = true;
						}
					} catch (error) {
						// If we can't read the file or parse it, assume no existing tasks in this tag
						hasExistingTasksInTag = false;
					}
				}

				// Only show confirmation if there are existing tasks in the target tag
				if (hasExistingTasksInTag && !useForce && !useAppend) {
					const overwrite = await confirmTaskOverwrite(tasksPath);
					if (!overwrite) {
						log('info', 'Operation cancelled.');
						return false;
					}
					// If user confirms 'y', we should set useForce = true for the parsePRD call
					// Only overwrite if not appending
					useForce = true;
				}
				return true;
			}

			try {
				if (!(await confirmOverwriteIfNeeded())) return;

				console.log(chalk.blue(`Parsing PRD file: ${taskMaster.getPrdPath()}`));
				console.log(chalk.blue(`Generating ${numTasks} tasks...`));
				if (append) {
					console.log(chalk.blue('Appending to existing tasks...'));
				}
				if (research) {
					console.log(
						chalk.blue(
							'Using Perplexity AI for research-backed task generation'
						)
					);
				}

				// Handle case where getTasksPath() returns null
				const outputPath =
					taskMaster.getTasksPath() ||
					path.join(taskMaster.getProjectRoot(), TASKMASTER_TASKS_FILE);
				await parsePRD(taskMaster.getPrdPath(), outputPath, numTasks, {
					append: useAppend,
					force: useForce,
					research: research,
					projectRoot: taskMaster.getProjectRoot(),
					tag: tag
				});
			} catch (error) {
				console.error(chalk.red(`Error parsing PRD: ${error.message}`));
				process.exit(1);
			}
		});

	// update command
	programInstance
		.command('update')
		.description(
			'Update multiple tasks with ID >= "from" based on new information or implementation changes'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'--from <id>',
			'Task ID to start updating from (tasks with ID >= this value will be updated)',
			'1'
		)
		.option(
			'-p, --prompt <text>',
			'Prompt explaining the changes or new context (required)'
		)
		.option(
			'-r, --research',
			'Use Perplexity AI for research-backed task updates'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const fromId = parseInt(options.from, 10); // Validation happens here
			const prompt = options.prompt;
			const useResearch = options.research || false;

			const tasksPath = taskMaster.getTasksPath();

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			// Check if there's an 'id' option which is a common mistake (instead of 'from')
			if (
				process.argv.includes('--id') ||
				process.argv.some((arg) => arg.startsWith('--id='))
			) {
				console.error(
					chalk.red('Error: The update command uses --from=<id>, not --id=<id>')
				);
				console.log(chalk.yellow('\nTo update multiple tasks:'));
				console.log(
					`  task-master update --from=${fromId} --prompt="Your prompt here"`
				);
				console.log(
					chalk.yellow(
						'\nTo update a single specific task, use the update-task command instead:'
					)
				);
				console.log(
					`  task-master update-task --id=<id> --prompt="Your prompt here"`
				);
				process.exit(1);
			}

			if (!prompt) {
				console.error(
					chalk.red(
						'Error: --prompt parameter is required. Please provide information about the changes.'
					)
				);
				process.exit(1);
			}

			console.log(
				chalk.blue(
					`Updating tasks from ID >= ${fromId} with prompt: "${prompt}"`
				)
			);

			// Only show tasks file path for local storage
			if (!isConnectedToHamster()) {
				console.log(chalk.blue(`Tasks file: ${tasksPath}`));
			}

			if (useResearch) {
				console.log(
					chalk.blue('Using Perplexity AI for research-backed task updates')
				);
			}

			// Call core updateTasks, passing context for CLI
			await updateTasks(
				taskMaster.getTasksPath(),
				fromId,
				prompt,
				useResearch,
				{ projectRoot: taskMaster.getProjectRoot(), tag } // Pass context with projectRoot and tag
			);
		});

	// update-task command
	programInstance
		.command('update-task')
		.description('Update a single specific task by ID with new information')
		.argument('[id]', 'Task ID to update (e.g., 1, 1.1, TAS-123)')
		.argument('[prompt...]', 'Update prompt - multiple words, no quotes needed')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-i, --id <id>',
			'Task ID to update (fallback if not using positional)'
		)
		.option('-p, --prompt <text>', 'Prompt (fallback if not using positional)')
		.option(
			'-r, --research',
			'Use Perplexity AI for research-backed task updates'
		)
		.option(
			'--append',
			'Append timestamped information to task details instead of full update'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (idArg, promptWords, options) => {
			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true,
					tag: options.tag
				});
				const tasksPath = taskMaster.getTasksPath();

				// Resolve tag using standard pattern
				const tag = taskMaster.getCurrentTag();

				// Show current tag context
				await displayCurrentTagIndicator(tag);

				// Prioritize positional arguments over options
				const taskId = idArg || options.id;
				const prompt =
					promptWords.length > 0 ? promptWords.join(' ') : options.prompt;

				// Validate required parameters
				if (!taskId) {
					console.error(chalk.red('Error: Task ID is required'));
					console.log(
						chalk.yellow(
							'Usage examples:\n' +
								'  tm update-task 1 Added implementation details\n' +
								'  tm update-task TAS-123 Fixed the auth bug\n' +
								'  tm update-task --id=23 --prompt="Update with new information"'
						)
					);
					process.exit(1);
				}

				// Parse the task ID and validate it's a number or a string like ham-123 or tas-456
				// Accept valid task IDs:
				// - positive integers (e.g. 1,2,3)
				// - strings like ham-123, ham-1, tas-456, etc
				// Disallow decimals and invalid formats
				const validId =
					/^\d+$/.test(taskId) || // plain positive integer
					/^[a-z]+-\d+$/i.test(taskId); // label-number format (e.g., ham-123)

				if (!validId) {
					console.error(
						chalk.red(
							`Error: Invalid task ID: ${taskId}. Task ID must be a positive integer or in the form "ham-123".`
						)
					);
					console.log(
						chalk.yellow(
							'Usage examples:\n' +
								'  tm update-task 1 Added implementation details\n' +
								'  tm update-task TAS-123 Fixed the auth bug'
						)
					);
					process.exit(1);
				}

				if (!prompt) {
					console.error(
						chalk.red(
							'Error: Prompt is required. Please provide information about the changes.'
						)
					);
					console.log(
						chalk.yellow(
							'Usage examples:\n' +
								'  tm update-task 1 Added implementation details\n' +
								'  tm update-task 23 "Update with new information"'
						)
					);
					process.exit(1);
				}
				const useResearch = options.research || false;

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					if (tasksPath === TASKMASTER_TASKS_FILE) {
						console.log(
							chalk.yellow(
								'Hint: Run task-master init or task-master parse-prd to create tasks.json first'
							)
						);
					} else {
						console.log(
							chalk.yellow(
								`Hint: Check if the file path is correct: ${tasksPath}`
							)
						);
					}
					process.exit(1);
				}

				console.log(
					chalk.blue(`Updating task ${taskId} with prompt: "${prompt}"`)
				);

				// Only show tasks file path for local storage
				if (!isConnectedToHamster()) {
					console.log(chalk.blue(`Tasks file: ${tasksPath}`));
				}

				if (useResearch) {
					// Verify Perplexity API key exists if using research
					if (!isApiKeySet('perplexity')) {
						console.log(
							chalk.yellow(
								'Warning: PERPLEXITY_API_KEY environment variable is missing. Research-backed updates will not be available.'
							)
						);
						console.log(
							chalk.yellow('Falling back to Claude AI for task update.')
						);
					} else {
						console.log(
							chalk.blue('Using Perplexity AI for research-backed task update')
						);
					}
				}

				// Force append mode when connected to Hamster
				const shouldAppend = isConnectedToHamster()
					? true
					: options.append || false;

				const result = await updateTaskById(
					taskMaster.getTasksPath(),
					taskId,
					prompt,
					useResearch,
					{ projectRoot: taskMaster.getProjectRoot(), tag },
					'text',
					shouldAppend
				);

				// If the task wasn't updated (e.g., if it was already marked as done)
				if (!result) {
					console.log(
						chalk.yellow(
							'\nTask update was not completed. Review the messages above for details.'
						)
					);
				}
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));

				// Provide more helpful error messages for common issues
				if (
					error.message.includes('task') &&
					error.message.includes('not found')
				) {
					console.log(chalk.yellow('\nTo fix this issue:'));
					console.log(
						'  1. Run task-master list to see all available task IDs'
					);
					console.log('  2. Use a valid task ID with the --id parameter');
				} else if (error.message.includes('API key')) {
					console.log(
						chalk.yellow(
							'\nThis error is related to API keys. Check your environment variables.'
						)
					);
				}

				// Use getDebugFlag getter instead of CONFIG.debug
				if (getDebugFlag()) {
					console.error(error);
				}

				process.exit(1);
			}
		});

	// update-subtask command
	programInstance
		.command('update-subtask')
		.description(
			'Update a subtask by appending additional timestamped information'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('-i, --id <id>', 'Subtask ID to update (required)')
		.option(
			'-p, --prompt <text>',
			'Prompt explaining what information to add (required)'
		)
		.option('-r, --research', 'Use Perplexity AI for research-backed updates')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true,
					tag: options.tag
				});
				const tasksPath = taskMaster.getTasksPath();

				// Resolve tag using standard pattern
				const tag = taskMaster.getCurrentTag();

				// Show current tag context
				await displayCurrentTagIndicator(tag);

				// Validate required parameters
				if (!options.id) {
					console.error(chalk.red('Error: --id parameter is required'));
					console.log(
						chalk.yellow(
							'Usage example: task-master update-subtask --id=5.2 --prompt="Add more details about the API endpoint"'
						)
					);
					process.exit(1);
				}

				// Get subtask ID - validation happens in the core function
				// In API storage, subtask IDs like "HAM-2611" are valid
				// In file storage, subtask IDs must be in format "parentId.subtaskId"
				const subtaskId = options.id;

				if (!options.prompt) {
					console.error(
						chalk.red(
							'Error: --prompt parameter is required. Please provide information to add to the subtask.'
						)
					);
					console.log(
						chalk.yellow(
							'Usage example: task-master update-subtask --id=5.2 --prompt="Add more details about the API endpoint"'
						)
					);
					process.exit(1);
				}

				const prompt = options.prompt;
				const useResearch = options.research || false;

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					if (tasksPath === TASKMASTER_TASKS_FILE) {
						console.log(
							chalk.yellow(
								'Hint: Run task-master init or task-master parse-prd to create tasks.json first'
							)
						);
					} else {
						console.log(
							chalk.yellow(
								`Hint: Check if the file path is correct: ${tasksPath}`
							)
						);
					}
					process.exit(1);
				}

				console.log(
					chalk.blue(`Updating subtask ${subtaskId} with prompt: "${prompt}"`)
				);

				// Only show tasks file path for local storage
				if (!isConnectedToHamster()) {
					console.log(chalk.blue(`Tasks file: ${tasksPath}`));
				}

				if (useResearch) {
					// Verify Perplexity API key exists if using research
					if (!isApiKeySet('perplexity')) {
						console.log(
							chalk.yellow(
								'Warning: PERPLEXITY_API_KEY environment variable is missing. Research-backed updates will not be available.'
							)
						);
						console.log(
							chalk.yellow('Falling back to Claude AI for subtask update.')
						);
					} else {
						console.log(
							chalk.blue(
								'Using Perplexity AI for research-backed subtask update'
							)
						);
					}
				}

				const result = await updateSubtaskById(
					taskMaster.getTasksPath(),
					subtaskId,
					prompt,
					useResearch,
					{ projectRoot: taskMaster.getProjectRoot(), tag }
				);

				if (!result) {
					console.log(
						chalk.yellow(
							'\nSubtask update was not completed. Review the messages above for details.'
						)
					);
				}
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));

				// Provide more helpful error messages for common issues
				if (
					error.message.includes('subtask') &&
					error.message.includes('not found')
				) {
					console.log(chalk.yellow('\nTo fix this issue:'));
					console.log(
						'  1. Run task-master list --with-subtasks to see all available subtask IDs'
					);
					console.log(
						'  2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"'
					);
				} else if (error.message.includes('API key')) {
					console.log(
						chalk.yellow(
							'\nThis error is related to API keys. Check your environment variables.'
						)
					);
				}

				// Use getDebugFlag getter instead of CONFIG.debug
				if (getDebugFlag()) {
					console.error(error);
				}

				process.exit(1);
			}
		});

	// scope-up command
	programInstance
		.command('scope-up')
		.description('Increase task complexity with AI assistance')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-i, --id <ids>',
			'Comma-separated task/subtask IDs to scope up (required)'
		)
		.option(
			'-s, --strength <level>',
			'Complexity increase strength: light, regular, heavy',
			'regular'
		)
		.option(
			'-p, --prompt <text>',
			'Custom instructions for targeted scope adjustments'
		)
		.option('-r, --research', 'Use research AI for more informed adjustments')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true,
					tag: options.tag
				});
				const tasksPath = taskMaster.getTasksPath();
				const tag = taskMaster.getCurrentTag();

				// Show current tag context
				await displayCurrentTagIndicator(tag);

				// Validate required parameters
				if (!options.id) {
					console.error(chalk.red('Error: --id parameter is required'));
					console.log(
						chalk.yellow(
							'Usage example: task-master scope-up --id=1,2,3 --strength=regular'
						)
					);
					process.exit(1);
				}

				// Parse and validate task IDs
				const taskIds = options.id.split(',').map((id) => {
					const parsed = parseInt(id.trim(), 10);
					if (Number.isNaN(parsed) || parsed <= 0) {
						console.error(chalk.red(`Error: Invalid task ID: ${id.trim()}`));
						process.exit(1);
					}
					return parsed;
				});

				// Validate strength level
				if (!validateStrength(options.strength)) {
					console.error(
						chalk.red(
							`Error: Invalid strength level: ${options.strength}. Must be one of: light, regular, heavy`
						)
					);
					process.exit(1);
				}

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				console.log(
					chalk.blue(
						`Scoping up ${taskIds.length} task(s): ${taskIds.join(', ')}`
					)
				);
				console.log(chalk.blue(`Strength level: ${options.strength}`));
				if (options.prompt) {
					console.log(chalk.blue(`Custom instructions: ${options.prompt}`));
				}

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					tag,
					commandName: 'scope-up',
					outputType: 'cli',
					research: options.research || false
				};

				const result = await scopeUpTask(
					tasksPath,
					taskIds,
					options.strength,
					options.prompt || null,
					context,
					'text'
				);

				console.log(
					chalk.green(
						`✅ Successfully scoped up ${result.updatedTasks.length} task(s)`
					)
				);
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));

				if (error.message.includes('not found')) {
					console.log(chalk.yellow('\nTo fix this issue:'));
					console.log(
						'  1. Run task-master list to see all available task IDs'
					);
					console.log('  2. Use valid task IDs with the --id parameter');
				}

				if (getDebugFlag()) {
					console.error(error);
				}

				process.exit(1);
			}
		});

	// scope-down command
	programInstance
		.command('scope-down')
		.description('Decrease task complexity with AI assistance')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-i, --id <ids>',
			'Comma-separated task/subtask IDs to scope down (required)'
		)
		.option(
			'-s, --strength <level>',
			'Complexity decrease strength: light, regular, heavy',
			'regular'
		)
		.option(
			'-p, --prompt <text>',
			'Custom instructions for targeted scope adjustments'
		)
		.option('-r, --research', 'Use research AI for more informed adjustments')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true,
					tag: options.tag
				});
				const tasksPath = taskMaster.getTasksPath();
				const tag = taskMaster.getCurrentTag();

				// Show current tag context
				await displayCurrentTagIndicator(tag);

				// Validate required parameters
				if (!options.id) {
					console.error(chalk.red('Error: --id parameter is required'));
					console.log(
						chalk.yellow(
							'Usage example: task-master scope-down --id=1,2,3 --strength=regular'
						)
					);
					process.exit(1);
				}

				// Parse and validate task IDs
				const taskIds = options.id.split(',').map((id) => {
					const parsed = parseInt(id.trim(), 10);
					if (Number.isNaN(parsed) || parsed <= 0) {
						console.error(chalk.red(`Error: Invalid task ID: ${id.trim()}`));
						process.exit(1);
					}
					return parsed;
				});

				// Validate strength level
				if (!validateStrength(options.strength)) {
					console.error(
						chalk.red(
							`Error: Invalid strength level: ${options.strength}. Must be one of: light, regular, heavy`
						)
					);
					process.exit(1);
				}

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				console.log(
					chalk.blue(
						`Scoping down ${taskIds.length} task(s): ${taskIds.join(', ')}`
					)
				);
				console.log(chalk.blue(`Strength level: ${options.strength}`));
				if (options.prompt) {
					console.log(chalk.blue(`Custom instructions: ${options.prompt}`));
				}

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					tag,
					commandName: 'scope-down',
					outputType: 'cli',
					research: options.research || false
				};

				const result = await scopeDownTask(
					tasksPath,
					taskIds,
					options.strength,
					options.prompt || null,
					context,
					'text'
				);

				console.log(
					chalk.green(
						`✅ Successfully scoped down ${result.updatedTasks.length} task(s)`
					)
				);
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));

				if (error.message.includes('not found')) {
					console.log(chalk.yellow('\nTo fix this issue:'));
					console.log(
						'  1. Run task-master list to see all available task IDs'
					);
					console.log('  2. Use valid task IDs with the --id parameter');
				}

				if (getDebugFlag()) {
					console.error(error);
				}

				process.exit(1);
			}
		});

	// ========================================
	// Register All Commands from @tm/cli
	// ========================================
	// Use the centralized command registry to register all CLI commands
	// This replaces individual command registrations and reduces duplication
	registerAllCommands(programInstance);

	// expand command
	programInstance
		.command('expand')
		.description('Expand a task into subtasks using AI')
		.option('-i, --id <id>', 'ID of the task to expand')
		.option(
			'-a, --all',
			'Expand all pending tasks based on complexity analysis'
		)
		.option(
			'-n, --num <number>',
			'Number of subtasks to generate (uses complexity analysis by default if available)'
		)
		.option(
			'-r, --research',
			'Enable research-backed generation (e.g., using Perplexity)',
			false
		)
		.option('-p, --prompt <text>', 'Additional context for subtask generation')
		.option('-f, --force', 'Force expansion even if subtasks exist', false) // Ensure force option exists
		.option(
			'--file <file>',
			'Path to the tasks file (relative to project root)',
			TASKMASTER_TASKS_FILE // Allow file override
		) // Allow file override
		.option(
			'-cr, --complexity-report <file>',
			'Path to the complexity report file (use this to specify the complexity report, not --file)'
			// Removed default value to allow tag-specific auto-detection
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			if (options.complexityReport) {
				initOptions.complexityReportPath = options.complexityReport;
			}

			const taskMaster = initTaskMaster(initOptions);

			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (options.all) {
				// --- Handle expand --all ---
				console.log(chalk.blue('Expanding all pending tasks...'));
				// Updated call to the refactored expandAllTasks
				try {
					const result = await expandAllTasks(
						taskMaster.getTasksPath(),
						options.num, // Pass num
						options.research, // Pass research flag
						options.prompt, // Pass additional context
						options.force, // Pass force flag
						{
							projectRoot: taskMaster.getProjectRoot(),
							tag,
							complexityReportPath: taskMaster.getComplexityReportPath()
						} // Pass context with projectRoot and tag
						// outputFormat defaults to 'text' in expandAllTasks for CLI
					);
				} catch (error) {
					console.error(
						chalk.red(`Error expanding all tasks: ${error.message}`)
					);
					process.exit(1);
				}
			} else if (options.id) {
				// --- Handle expand --id <id> (Should be correct from previous refactor) ---
				if (!options.id) {
					console.error(
						chalk.red('Error: Task ID is required unless using --all.')
					);
					process.exit(1);
				}

				console.log(chalk.blue(`Expanding task ${options.id}...`));
				try {
					// Call the refactored expandTask function
					await expandTask(
						taskMaster.getTasksPath(),
						options.id,
						options.num,
						options.research,
						options.prompt,
						{
							projectRoot: taskMaster.getProjectRoot(),
							tag,
							complexityReportPath: taskMaster.getComplexityReportPath()
						}, // Pass context with projectRoot and tag
						options.force // Pass the force flag down
					);
					// expandTask logs its own success/failure for single task
				} catch (error) {
					console.error(
						chalk.red(`Error expanding task ${options.id}: ${error.message}`)
					);
					process.exit(1);
				}
			} else {
				console.error(
					chalk.red('Error: You must specify either a task ID (--id) or --all.')
				);
				programInstance.help(); // Show help
			}
		});

	// analyze-complexity command
	programInstance
		.command('analyze-complexity')
		.description(
			`Analyze tasks and generate expansion recommendations${chalk.reset('')}`
		)
		.option('-o, --output <file>', 'Output file path for the report')
		.option(
			'-m, --model <model>',
			'LLM model to use for analysis (defaults to configured model)'
		)
		.option(
			'-t, --threshold <number>',
			'Minimum complexity score to recommend expansion (1-10)',
			'5'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-r, --research',
			'Use configured research model for research-backed complexity analysis'
		)
		.option(
			'-i, --id <ids>',
			'Comma-separated list of specific task IDs to analyze (e.g., "1,3,5")'
		)
		.option('--from <id>', 'Starting task ID in a range to analyze')
		.option('--to <id>', 'Ending task ID in a range to analyze')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const initOptions = {
				tasksPath: options.file || true, // Tasks file is required to analyze
				tag: options.tag
			};
			// Only include complexityReportPath if output is explicitly specified
			if (options.output) {
				initOptions.complexityReportPath = options.output;
			}

			const taskMaster = initTaskMaster(initOptions);

			const modelOverride = options.model;
			const thresholdScore = parseFloat(options.threshold);
			const useResearch = options.research || false;

			// Use the provided tag, or the current active tag, or default to 'master'
			const targetTag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(targetTag);

			// Use user's explicit output path if provided, otherwise use tag-aware default
			const outputPath = taskMaster.getComplexityReportPath();

			console.log(
				chalk.blue(
					`Analyzing task complexity from: ${taskMaster.getTasksPath()}`
				)
			);
			console.log(chalk.blue(`Output report will be saved to: ${outputPath}`));

			if (options.id) {
				console.log(chalk.blue(`Analyzing specific task IDs: ${options.id}`));
			} else if (options.from || options.to) {
				const fromStr = options.from ? options.from : 'first';
				const toStr = options.to ? options.to : 'last';
				console.log(
					chalk.blue(`Analyzing tasks in range: ${fromStr} to ${toStr}`)
				);
			}

			if (useResearch) {
				console.log(
					chalk.blue(
						'Using Perplexity AI for research-backed complexity analysis'
					)
				);
			}

			// Update options with tag-aware output path and context
			const updatedOptions = {
				...options,
				output: outputPath,
				tag: targetTag,
				projectRoot: taskMaster.getProjectRoot(),
				file: taskMaster.getTasksPath()
			};

			await analyzeTaskComplexity(updatedOptions);
		});

	// research command
	programInstance
		.command('research')
		.description('Perform AI-powered research queries with project context')
		.argument('[prompt]', 'Research prompt to investigate')
		.option('--file <file>', 'Path to the tasks file')
		.option(
			'-i, --id <ids>',
			'Comma-separated task/subtask IDs to include as context (e.g., "15,16.2")'
		)
		.option(
			'-f, --files <paths>',
			'Comma-separated file paths to include as context'
		)
		.option(
			'-c, --context <text>',
			'Additional custom context to include in the research prompt'
		)
		.option(
			'-t, --tree',
			'Include project file tree structure in the research context'
		)
		.option(
			'-s, --save <file>',
			'Save research results to the specified task/subtask(s)'
		)
		.option(
			'-d, --detail <level>',
			'Output detail level: low, medium, high',
			'medium'
		)
		.option(
			'--save-to <id>',
			'Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")'
		)
		.option(
			'--save-file',
			'Save research results to .taskmaster/docs/research/ directory'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (prompt, options) => {
			// Initialize TaskMaster
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			const taskMaster = initTaskMaster(initOptions);

			// Parameter validation
			if (!prompt || typeof prompt !== 'string' || prompt.trim().length === 0) {
				console.error(
					chalk.red('Error: Research prompt is required and cannot be empty')
				);
				showResearchHelp();
				process.exit(1);
			}

			// Validate detail level
			const validDetailLevels = ['low', 'medium', 'high'];
			if (
				options.detail &&
				!validDetailLevels.includes(options.detail.toLowerCase())
			) {
				console.error(
					chalk.red(
						`Error: Detail level must be one of: ${validDetailLevels.join(', ')}`
					)
				);
				process.exit(1);
			}

			// Validate and parse task IDs if provided
			let taskIds = [];
			if (options.id) {
				try {
					taskIds = options.id.split(',').map((id) => {
						const trimmedId = id.trim();
						// Support both task IDs (e.g., "15") and subtask IDs (e.g., "15.2")
						if (!/^\d+(\.\d+)?$/.test(trimmedId)) {
							throw new Error(
								`Invalid task ID format: "${trimmedId}". Expected format: "15" or "15.2"`
							);
						}
						return trimmedId;
					});
				} catch (error) {
					console.error(chalk.red(`Error parsing task IDs: ${error.message}`));
					process.exit(1);
				}
			}

			// Validate and parse file paths if provided
			let filePaths = [];
			if (options.files) {
				try {
					filePaths = options.files.split(',').map((filePath) => {
						const trimmedPath = filePath.trim();
						if (trimmedPath.length === 0) {
							throw new Error('Empty file path provided');
						}
						return trimmedPath;
					});
				} catch (error) {
					console.error(
						chalk.red(`Error parsing file paths: ${error.message}`)
					);
					process.exit(1);
				}
			}

			// Validate save-to option if provided
			if (options.saveTo) {
				const saveToId = options.saveTo.trim();
				if (saveToId.length === 0) {
					console.error(chalk.red('Error: Save-to ID cannot be empty'));
					process.exit(1);
				}
				// Validate ID format: number or number.number
				if (!/^\d+(\.\d+)?$/.test(saveToId)) {
					console.error(
						chalk.red(
							'Error: Save-to ID must be in format "15" for task or "15.2" for subtask'
						)
					);
					process.exit(1);
				}
			}

			// Validate save option if provided (legacy file save)
			if (options.save) {
				const saveTarget = options.save.trim();
				if (saveTarget.length === 0) {
					console.error(chalk.red('Error: Save target cannot be empty'));
					process.exit(1);
				}
				// Check if it's a valid file path (basic validation)
				if (saveTarget.includes('..') || saveTarget.startsWith('/')) {
					console.error(
						chalk.red(
							'Error: Save path must be relative and cannot contain ".."'
						)
					);
					process.exit(1);
				}
			}

			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			// Validate tasks file exists if task IDs are specified
			if (taskIds.length > 0) {
				try {
					const tasksData = readJSON(
						taskMaster.getTasksPath(),
						taskMaster.getProjectRoot(),
						tag
					);
					if (!tasksData || !tasksData.tasks) {
						console.error(
							chalk.red(
								`Error: No valid tasks found in ${taskMaster.getTasksPath()} for tag '${tag}'`
							)
						);
						process.exit(1);
					}
				} catch (error) {
					console.error(
						chalk.red(`Error reading tasks file: ${error.message}`)
					);
					process.exit(1);
				}
			}

			// Validate file paths exist if specified
			if (filePaths.length > 0) {
				for (const filePath of filePaths) {
					const fullPath = path.isAbsolute(filePath)
						? filePath
						: path.join(taskMaster.getProjectRoot(), filePath);
					if (!fs.existsSync(fullPath)) {
						console.error(chalk.red(`Error: File not found: ${filePath}`));
						process.exit(1);
					}
				}
			}

			// Create validated parameters object
			const validatedParams = {
				prompt: prompt.trim(),
				taskIds: taskIds,
				filePaths: filePaths,
				customContext: options.context ? options.context.trim() : null,
				includeProjectTree: !!options.tree,
				saveTarget: options.save ? options.save.trim() : null,
				saveToId: options.saveTo ? options.saveTo.trim() : null,
				allowFollowUp: true, // Always allow follow-up in CLI
				detailLevel: options.detail ? options.detail.toLowerCase() : 'medium',
				tasksPath: taskMaster.getTasksPath(),
				projectRoot: taskMaster.getProjectRoot()
			};

			// Display what we're about to do
			console.log(chalk.blue(`Researching: "${validatedParams.prompt}"`));

			if (validatedParams.taskIds.length > 0) {
				console.log(
					chalk.gray(`Task context: ${validatedParams.taskIds.join(', ')}`)
				);
			}

			if (validatedParams.filePaths.length > 0) {
				console.log(
					chalk.gray(`File context: ${validatedParams.filePaths.join(', ')}`)
				);
			}

			if (validatedParams.customContext) {
				console.log(
					chalk.gray(
						`Custom context: ${validatedParams.customContext.substring(0, 50)}${validatedParams.customContext.length > 50 ? '...' : ''}`
					)
				);
			}

			if (validatedParams.includeProjectTree) {
				console.log(chalk.gray('Including project file tree'));
			}

			console.log(chalk.gray(`Detail level: ${validatedParams.detailLevel}`));

			try {
				// Import the research function
				const { performResearch } = await import('./task-manager/research.js');

				// Prepare research options
				const researchOptions = {
					taskIds: validatedParams.taskIds,
					filePaths: validatedParams.filePaths,
					customContext: validatedParams.customContext || '',
					includeProjectTree: validatedParams.includeProjectTree,
					detailLevel: validatedParams.detailLevel,
					projectRoot: validatedParams.projectRoot,
					saveToFile: !!options.saveFile,
					tag: tag
				};

				// Execute research
				const result = await performResearch(
					validatedParams.prompt,
					researchOptions,
					{
						commandName: 'research',
						outputType: 'cli',
						tag: tag
					},
					'text',
					validatedParams.allowFollowUp // Pass follow-up flag
				);

				// Auto-save to task/subtask if requested and no interactive save occurred
				if (validatedParams.saveToId && !result.interactiveSaveOccurred) {
					try {
						const isSubtask = validatedParams.saveToId.includes('.');

						// Format research content for saving
						const researchContent = `## Research Query: ${validatedParams.prompt}

**Detail Level:** ${result.detailLevel}
**Context Size:** ${result.contextSize} characters
**Timestamp:** ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}

### Results

${result.result}`;

						if (isSubtask) {
							// Save to subtask
							const { updateSubtaskById } = await import(
								'./task-manager/update-subtask-by-id.js'
							);

							await updateSubtaskById(
								validatedParams.tasksPath,
								validatedParams.saveToId,
								researchContent,
								false, // useResearch = false for simple append
								{
									commandName: 'research-save',
									outputType: 'cli',
									projectRoot: validatedParams.projectRoot,
									tag: tag
								},
								'text'
							);

							console.log(
								chalk.green(
									`✅ Research saved to subtask ${validatedParams.saveToId}`
								)
							);
						} else {
							// Save to task
							const updateTaskById = (
								await import('./task-manager/update-task-by-id.js')
							).default;

							const taskIdNum = parseInt(validatedParams.saveToId, 10);
							await updateTaskById(
								validatedParams.tasksPath,
								taskIdNum,
								researchContent,
								false, // useResearch = false for simple append
								{
									commandName: 'research-save',
									outputType: 'cli',
									projectRoot: validatedParams.projectRoot,
									tag: tag
								},
								'text',
								true // appendMode = true
							);

							console.log(
								chalk.green(
									`✅ Research saved to task ${validatedParams.saveToId}`
								)
							);
						}
					} catch (saveError) {
						console.log(
							chalk.red(`❌ Error saving to task/subtask: ${saveError.message}`)
						);
					}
				}

				// Save results to file if requested (legacy)
				if (validatedParams.saveTarget) {
					const saveContent = `# Research Query: ${validatedParams.prompt}

**Detail Level:** ${result.detailLevel}
**Context Size:** ${result.contextSize} characters
**Timestamp:** ${new Date().toISOString()}

## Results

${result.result}
`;

					fs.writeFileSync(validatedParams.saveTarget, saveContent, 'utf-8');
					console.log(
						chalk.green(`\n💾 Results saved to: ${validatedParams.saveTarget}`)
					);
				}
			} catch (error) {
				console.error(chalk.red(`\n❌ Research failed: ${error.message}`));
				process.exit(1);
			}
		});

	// clear-subtasks command
	programInstance
		.command('clear-subtasks')
		.description('Clear subtasks from specified tasks')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-i, --id <ids>',
			'Task IDs (comma-separated) to clear subtasks from'
		)
		.option('--all', 'Clear subtasks from all tasks')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const taskIds = options.id;
			const all = options.all;

			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (!taskIds && !all) {
				console.error(
					chalk.red(
						'Error: Please specify task IDs with --id=<ids> or use --all to clear all tasks'
					)
				);
				process.exit(1);
			}

			if (all) {
				// If --all is specified, get all task IDs
				const data = readJSON(
					taskMaster.getTasksPath(),
					taskMaster.getProjectRoot(),
					tag
				);
				if (!data || !data.tasks) {
					console.error(chalk.red('Error: No valid tasks found'));
					process.exit(1);
				}
				const allIds = data.tasks.map((t) => t.id).join(',');
				clearSubtasks(taskMaster.getTasksPath(), allIds, {
					projectRoot: taskMaster.getProjectRoot(),
					tag
				});
			} else {
				clearSubtasks(taskMaster.getTasksPath(), taskIds, {
					projectRoot: taskMaster.getProjectRoot(),
					tag
				});
			}
		});

	// add-task command
	programInstance
		.command('add-task')
		.description('Add a new task using AI, optionally providing manual details')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-p, --prompt <prompt>',
			'Description of the task to add (required if not using manual fields)'
		)
		.option('-t, --title <title>', 'Task title (for manual task creation)')
		.option(
			'-d, --description <description>',
			'Task description (for manual task creation)'
		)
		.option(
			'--details <details>',
			'Implementation details (for manual task creation)'
		)
		.option(
			'--dependencies <dependencies>',
			'Comma-separated list of task IDs this task depends on'
		)
		.option(
			'--priority <priority>',
			'Task priority (high, medium, low)',
			'medium'
		)
		.option(
			'-r, --research',
			'Whether to use research capabilities for task creation'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const isManualCreation = options.title && options.description;

			// Validate that either prompt or title+description are provided
			if (!options.prompt && !isManualCreation) {
				console.error(
					chalk.red(
						'Error: Either --prompt or both --title and --description must be provided'
					)
				);
				process.exit(1);
			}

			const tasksPath = options.file || TASKMASTER_TASKS_FILE;

			if (!fs.existsSync(tasksPath)) {
				console.error(
					`❌ No tasks.json file found. Please run "task-master init" or create a tasks.json file at ${TASKMASTER_TASKS_FILE}`
				);
				process.exit(1);
			}

			// Correctly determine projectRoot
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const projectRoot = taskMaster.getProjectRoot();

			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			let manualTaskData = null;
			if (isManualCreation) {
				manualTaskData = {
					title: options.title,
					description: options.description,
					details: options.details || '',
					testStrategy: options.testStrategy || ''
				};
				// Restore specific logging for manual creation
				console.log(
					chalk.blue(`Creating task manually with title: "${options.title}"`)
				);
			} else {
				// Restore specific logging for AI creation
				console.log(
					chalk.blue(`Creating task with AI using prompt: "${options.prompt}"`)
				);
			}

			// Log dependencies and priority if provided (restored)
			const dependenciesArray = options.dependencies
				? options.dependencies.split(',').map((id) => id.trim())
				: [];
			if (dependenciesArray.length > 0) {
				console.log(
					chalk.blue(`Dependencies: [${dependenciesArray.join(', ')}]`)
				);
			}
			if (options.priority) {
				console.log(chalk.blue(`Priority: ${options.priority}`));
			}

			const context = {
				projectRoot,
				tag,
				commandName: 'add-task',
				outputType: 'cli'
			};

			try {
				const { newTaskId, telemetryData } = await addTask(
					taskMaster.getTasksPath(),
					options.prompt,
					dependenciesArray,
					options.priority,
					context,
					'text',
					manualTaskData,
					options.research
				);

				// addTask handles detailed CLI success logging AND telemetry display when outputFormat is 'text'
				// No need to call displayAiUsageSummary here anymore.
			} catch (error) {
				console.error(chalk.red(`Error adding task: ${error.message}`));
				if (error.details) {
					console.error(chalk.red(error.details));
				}
				process.exit(1);
			}
		});

	// add-dependency command
	programInstance
		.command('add-dependency')
		.description('Add a dependency to a task')
		.option('-i, --id <id>', 'Task ID to add dependency to')
		.option('-d, --depends-on <id>', 'Task ID that will become a dependency')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			// Initialize TaskMaster
			const taskMaster = initTaskMaster(initOptions);

			const taskId = options.id;
			const dependencyId = options.dependsOn;

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (!taskId || !dependencyId) {
				console.error(
					chalk.red('Error: Both --id and --depends-on are required')
				);
				process.exit(1);
			}

			// Handle subtask IDs correctly by preserving the string format for IDs containing dots
			// Only use parseInt for simple numeric IDs
			const formattedTaskId = taskId.includes('.')
				? taskId
				: parseInt(taskId, 10);
			const formattedDependencyId = dependencyId.includes('.')
				? dependencyId
				: parseInt(dependencyId, 10);

			await addDependency(
				taskMaster.getTasksPath(),
				formattedTaskId,
				formattedDependencyId,
				{
					projectRoot: taskMaster.getProjectRoot(),
					tag
				}
			);
		});

	// remove-dependency command
	programInstance
		.command('remove-dependency')
		.description('Remove a dependency from a task')
		.option('-i, --id <id>', 'Task ID to remove dependency from')
		.option('-d, --depends-on <id>', 'Task ID to remove as a dependency')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			// Initialize TaskMaster
			const taskMaster = initTaskMaster(initOptions);

			const taskId = options.id;
			const dependencyId = options.dependsOn;

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (!taskId || !dependencyId) {
				console.error(
					chalk.red('Error: Both --id and --depends-on are required')
				);
				process.exit(1);
			}

			// Handle subtask IDs correctly by preserving the string format for IDs containing dots
			// Only use parseInt for simple numeric IDs
			const formattedTaskId = taskId.includes('.')
				? taskId
				: parseInt(taskId, 10);
			const formattedDependencyId = dependencyId.includes('.')
				? dependencyId
				: parseInt(dependencyId, 10);

			await removeDependency(
				taskMaster.getTasksPath(),
				formattedTaskId,
				formattedDependencyId,
				{
					projectRoot: taskMaster.getProjectRoot(),
					tag
				}
			);
		});

	// validate-dependencies command
	programInstance
		.command('validate-dependencies')
		.description(
			`Identify invalid dependencies without fixing them${chalk.reset('')}`
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			// Initialize TaskMaster
			const taskMaster = initTaskMaster(initOptions);

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			await validateDependenciesCommand(taskMaster.getTasksPath(), {
				context: { projectRoot: taskMaster.getProjectRoot(), tag }
			});
		});

	// fix-dependencies command
	programInstance
		.command('fix-dependencies')
		.description(`Fix invalid dependencies automatically${chalk.reset('')}`)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const initOptions = {
				tasksPath: options.file || true,
				tag: options.tag
			};

			// Initialize TaskMaster
			const taskMaster = initTaskMaster(initOptions);

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			await fixDependenciesCommand(taskMaster.getTasksPath(), {
				context: { projectRoot: taskMaster.getProjectRoot(), tag }
			});
		});

	// complexity-report command
	programInstance
		.command('complexity-report')
		.description(`Display the complexity analysis report${chalk.reset('')}`)
		.option(
			'-f, --file <file>',
			'Path to the report file',
			COMPLEXITY_REPORT_FILE
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			const initOptions = {
				tag: options.tag
			};

			if (options.file && options.file !== COMPLEXITY_REPORT_FILE) {
				initOptions.complexityReportPath = options.file;
			}

			// Initialize TaskMaster
			const taskMaster = initTaskMaster(initOptions);

			// Show current tag context
			await displayCurrentTagIndicator(taskMaster.getCurrentTag());

			await displayComplexityReport(taskMaster.getComplexityReportPath());
		});

	// add-subtask command
	programInstance
		.command('add-subtask')
		.description('Add a subtask to an existing task')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('-p, --parent <id>', 'Parent task ID (required)')
		.option('-i, --task-id <id>', 'Existing task ID to convert to subtask')
		.option(
			'-t, --title <title>',
			'Title for the new subtask (when creating a new subtask)'
		)
		.option('-d, --description <text>', 'Description for the new subtask')
		.option('--details <text>', 'Implementation details for the new subtask')
		.option(
			'--dependencies <ids>',
			'Comma-separated list of dependency IDs for the new subtask'
		)
		.option('-s, --status <status>', 'Status for the new subtask', 'pending')
		.option('--generate', 'Regenerate task files after adding subtask')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const parentId = options.parent;
			const existingTaskId = options.taskId;
			const generateFiles = options.generate || false;

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (!parentId) {
				console.error(
					chalk.red(
						'Error: --parent parameter is required. Please provide a parent task ID.'
					)
				);
				showAddSubtaskHelp();
				process.exit(1);
			}

			// Parse dependencies if provided
			let dependencies = [];
			if (options.dependencies) {
				dependencies = options.dependencies.split(',').map((id) => {
					// Handle both regular IDs and dot notation
					return id.includes('.') ? id.trim() : parseInt(id.trim(), 10);
				});
			}

			try {
				if (existingTaskId) {
					// Convert existing task to subtask
					console.log(
						chalk.blue(
							`Converting task ${existingTaskId} to a subtask of ${parentId}...`
						)
					);
					await addSubtask(
						taskMaster.getTasksPath(),
						parentId,
						existingTaskId,
						null,
						generateFiles,
						{ projectRoot: taskMaster.getProjectRoot(), tag }
					);
					console.log(
						chalk.green(
							`✓ Task ${existingTaskId} successfully converted to a subtask of task ${parentId}`
						)
					);
				} else if (options.title) {
					// Create new subtask with provided data
					console.log(
						chalk.blue(`Creating new subtask for parent task ${parentId}...`)
					);

					const newSubtaskData = {
						title: options.title,
						description: options.description || '',
						details: options.details || '',
						status: options.status || 'pending',
						dependencies: dependencies
					};

					const subtask = await addSubtask(
						taskMaster.getTasksPath(),
						parentId,
						null,
						newSubtaskData,
						generateFiles,
						{ projectRoot: taskMaster.getProjectRoot(), tag }
					);
					console.log(
						chalk.green(
							`✓ New subtask ${parentId}.${subtask.id} successfully created`
						)
					);

					// Display success message and suggested next steps
					console.log(
						boxen(
							chalk.white.bold(
								`Subtask ${parentId}.${subtask.id} Added Successfully`
							) +
								'\n\n' +
								chalk.white(`Title: ${subtask.title}`) +
								'\n' +
								chalk.white(`Status: ${getStatusWithColor(subtask.status)}`) +
								'\n' +
								(dependencies.length > 0
									? chalk.white(`Dependencies: ${dependencies.join(', ')}`) +
										'\n'
									: '') +
								'\n' +
								chalk.white.bold('Next Steps:') +
								'\n' +
								chalk.cyan(
									`1. Run ${chalk.yellow(`task-master show ${parentId}`)} to see the parent task with all subtasks`
								) +
								'\n' +
								chalk.cyan(
									`2. Run ${chalk.yellow(`tm set-status ${parentId}.${subtask.id} in-progress`)} to start working on it`
								),
							{
								padding: 1,
								borderColor: 'green',
								borderStyle: 'round',
								margin: { top: 1 }
							}
						)
					);
				} else {
					console.error(
						chalk.red('Error: Either --task-id or --title must be provided.')
					);
					console.log(
						boxen(
							chalk.white.bold('Usage Examples:') +
								'\n\n' +
								chalk.white('Convert existing task to subtask:') +
								'\n' +
								chalk.yellow(
									`  task-master add-subtask --parent=5 --task-id=8`
								) +
								'\n\n' +
								chalk.white('Create new subtask:') +
								'\n' +
								chalk.yellow(
									`  task-master add-subtask --parent=5 --title="Implement login UI" --description="Create the login form"`
								) +
								'\n\n',
							{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
						)
					);
					process.exit(1);
				}
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));
				showAddSubtaskHelp();
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			showAddSubtaskHelp();
			process.exit(1);
		});

	// Helper function to show add-subtask command help
	function showAddSubtaskHelp() {
		console.log(
			boxen(
				`${chalk.white.bold('Add Subtask Command Help')}\n\n${chalk.cyan('Usage:')}\n  task-master add-subtask --parent=<id> [options]\n\n${chalk.cyan('Options:')}\n  -p, --parent <id>         Parent task ID (required)\n  -i, --task-id <id>        Existing task ID to convert to subtask\n  -t, --title <title>       Title for the new subtask\n  -d, --description <text>  Description for the new subtask\n  --details <text>          Implementation details for the new subtask\n  --dependencies <ids>      Comma-separated list of dependency IDs\n  -s, --status <status>     Status for the new subtask (default: "pending")\n  -f, --file <file>         Path to the tasks file (default: "${TASKMASTER_TASKS_FILE}")\n  --generate                Regenerate task files after adding subtask\n\n${chalk.cyan('Examples:')}\n  task-master add-subtask --parent=5 --task-id=8\n  task-master add-subtask -p 5 -t "Implement login UI" -d "Create the login form" --generate`,
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// remove-subtask command
	programInstance
		.command('remove-subtask')
		.description('Remove a subtask from its parent task')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'-i, --id <id>',
			'Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated for multiple subtasks)'
		)
		.option(
			'-c, --convert',
			'Convert the subtask to a standalone task instead of deleting it'
		)
		.option('--generate', 'Regenerate task files after removing subtask')
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const subtaskIds = options.id;
			const convertToTask = options.convert || false;
			const generateFiles = options.generate || false;
			const tag = taskMaster.getCurrentTag();

			if (!subtaskIds) {
				console.error(
					chalk.red(
						'Error: --id parameter is required. Please provide subtask ID(s) in format "parentId.subtaskId".'
					)
				);
				showRemoveSubtaskHelp();
				process.exit(1);
			}

			try {
				// Split by comma to support multiple subtask IDs
				const subtaskIdArray = subtaskIds.split(',').map((id) => id.trim());

				for (const subtaskId of subtaskIdArray) {
					// Validate subtask ID format
					if (!subtaskId.includes('.')) {
						console.error(
							chalk.red(
								`Error: Subtask ID "${subtaskId}" must be in format "parentId.subtaskId"`
							)
						);
						showRemoveSubtaskHelp();
						process.exit(1);
					}

					console.log(chalk.blue(`Removing subtask ${subtaskId}...`));
					if (convertToTask) {
						console.log(
							chalk.blue('The subtask will be converted to a standalone task')
						);
					}

					const result = await removeSubtask(
						taskMaster.getTasksPath(),
						subtaskId,
						convertToTask,
						generateFiles,
						{ projectRoot: taskMaster.getProjectRoot(), tag }
					);

					if (convertToTask && result) {
						// Display success message and next steps for converted task
						console.log(
							boxen(
								chalk.white.bold(
									`Subtask ${subtaskId} Converted to Task #${result.id}`
								) +
									'\n\n' +
									chalk.white(`Title: ${result.title}`) +
									'\n' +
									chalk.white(`Status: ${getStatusWithColor(result.status)}`) +
									'\n' +
									chalk.white(
										`Dependencies: ${result.dependencies.join(', ')}`
									) +
									'\n\n' +
									chalk.white.bold('Next Steps:') +
									'\n' +
									chalk.cyan(
										`1. Run ${chalk.yellow(`task-master show ${result.id}`)} to see details of the new task`
									) +
									'\n' +
									chalk.cyan(
										`2. Run ${chalk.yellow(`tm set-status ${result.id} in-progress`)} to start working on it`
									),
								{
									padding: 1,
									borderColor: 'green',
									borderStyle: 'round',
									margin: { top: 1 }
								}
							)
						);
					} else {
						// Display success message for deleted subtask
						console.log(
							boxen(
								chalk.white.bold(`Subtask ${subtaskId} Removed`) +
									'\n\n' +
									chalk.white('The subtask has been successfully deleted.'),
								{
									padding: 1,
									borderColor: 'green',
									borderStyle: 'round',
									margin: { top: 1 }
								}
							)
						);
					}
				}
			} catch (error) {
				console.error(chalk.red(`Error: ${error.message}`));
				showRemoveSubtaskHelp();
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			showRemoveSubtaskHelp();
			process.exit(1);
		});

	// Helper function to show remove-subtask command help
	function showRemoveSubtaskHelp() {
		console.log(
			boxen(
				chalk.white.bold('Remove Subtask Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master remove-subtask --id=<parentId.subtaskId> [options]\n\n` +
					chalk.cyan('Options:') +
					'\n' +
					'  -i, --id <id>       Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated, required)\n' +
					'  -c, --convert       Convert the subtask to a standalone task instead of deleting it\n' +
					'  -f, --file <file>   Path to the tasks file (default: "' +
					TASKMASTER_TASKS_FILE +
					'")\n' +
					'  --skip-generate     Skip regenerating task files\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master remove-subtask --id=5.2\n' +
					'  task-master remove-subtask --id=5.2,6.3,7.1\n' +
					'  task-master remove-subtask --id=5.2 --convert',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// Helper function to show tags command help
	function showTagsHelp() {
		console.log(
			boxen(
				chalk.white.bold('Tags Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master tags [options]\n\n` +
					chalk.cyan('Options:') +
					'\n' +
					'  -f, --file <file>   Path to the tasks file (default: "' +
					TASKMASTER_TASKS_FILE +
					'")\n' +
					'  --show-metadata     Show detailed metadata for each tag\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master tags\n' +
					'  task-master tags --show-metadata\n\n' +
					chalk.cyan('Related Commands:') +
					'\n' +
					'  task-master add-tag <name>      Create a new tag\n' +
					'  task-master use-tag <name>      Switch to a tag\n' +
					'  task-master delete-tag <name>   Delete a tag',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// Helper function to show add-tag command help
	function showAddTagHelp() {
		console.log(
			boxen(
				chalk.white.bold('Add Tag Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master add-tag <tagName> [options]\n\n` +
					chalk.cyan('Options:') +
					'\n' +
					'  -f, --file <file>        Path to the tasks file (default: "' +
					TASKMASTER_TASKS_FILE +
					'")\n' +
					'  --copy-from-current      Copy tasks from the current tag to the new tag\n' +
					'  --copy-from <tag>        Copy tasks from the specified tag to the new tag\n' +
					'  -d, --description <text> Optional description for the tag\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master add-tag feature-xyz\n' +
					'  task-master add-tag feature-xyz --copy-from-current\n' +
					'  task-master add-tag feature-xyz --copy-from master\n' +
					'  task-master add-tag feature-xyz -d "Feature XYZ development"',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// Helper function to show delete-tag command help
	function showDeleteTagHelp() {
		console.log(
			boxen(
				chalk.white.bold('Delete Tag Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master delete-tag <tagName> [options]\n\n` +
					chalk.cyan('Options:') +
					'\n' +
					'  -f, --file <file>   Path to the tasks file (default: "' +
					TASKMASTER_TASKS_FILE +
					'")\n' +
					'  -y, --yes           Skip confirmation prompts\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master delete-tag feature-xyz\n' +
					'  task-master delete-tag feature-xyz --yes\n\n' +
					chalk.yellow('Warning:') +
					'\n' +
					'  This will permanently delete the tag and all its tasks!',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// Helper function to show use-tag command help
	function showUseTagHelp() {
		console.log(
			boxen(
				chalk.white.bold('Use Tag Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master use-tag <tagName> [options]\n\n` +
					chalk.cyan('Options:') +
					'\n' +
					'  -f, --file <file>   Path to the tasks file (default: "' +
					TASKMASTER_TASKS_FILE +
					'")\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master use-tag feature-xyz\n' +
					'  task-master use-tag master\n\n' +
					chalk.cyan('Related Commands:') +
					'\n' +
					'  task-master tags                 List all available tags\n' +
					'  task-master add-tag <name>       Create a new tag',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// Helper function to show research command help
	function showResearchHelp() {
		console.log(
			boxen(
				chalk.white.bold('Research Command Help') +
					'\n\n' +
					chalk.cyan('Usage:') +
					'\n' +
					`  task-master research "<query>" [options]\n\n` +
					chalk.cyan('Required:') +
					'\n' +
					'  <query>             Research question or prompt (required)\n\n' +
					chalk.cyan('Context Options:') +
					'\n' +
					'  -i, --id <ids>      Comma-separated task/subtask IDs for context (e.g., "15,23.2")\n' +
					'  -f, --files <paths> Comma-separated file paths for context\n' +
					'  -c, --context <text> Additional custom context text\n' +
					'  --tree              Include project file tree structure\n\n' +
					chalk.cyan('Output Options:') +
					'\n' +
					'  -d, --detail <level> Detail level: low, medium, high (default: medium)\n' +
					'  --save-to <id>      Auto-save results to task/subtask ID (e.g., "15" or "15.2")\n' +
					'  --tag <tag>         Specify tag context for task operations\n\n' +
					chalk.cyan('Examples:') +
					'\n' +
					'  task-master research "How should I implement user authentication?"\n' +
					'  task-master research "What\'s the best approach?" --id=15,23.2\n' +
					'  task-master research "How does auth work?" --files=src/auth.js --tree\n' +
					'  task-master research "Implementation steps?" --save-to=15.2 --detail=high',
				{ padding: 1, borderColor: 'blue', borderStyle: 'round' }
			)
		);
	}

	// remove-task command
	programInstance
		.command('remove-task')
		.description('Remove one or more tasks or subtasks permanently')
		.option(
			'-i, --id <ids>',
			'ID(s) of the task(s) or subtask(s) to remove (e.g., "5", "5.2", or "5,6.1,7")'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('-y, --yes', 'Skip confirmation prompt', false)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const taskIdsString = options.id;

			// Resolve tag using standard pattern
			const tag = taskMaster.getCurrentTag();

			// Show current tag context
			await displayCurrentTagIndicator(tag);

			if (!taskIdsString) {
				console.error(chalk.red('Error: Task ID(s) are required'));
				console.error(
					chalk.yellow(
						'Usage: task-master remove-task --id=<taskId1,taskId2...>'
					)
				);
				process.exit(1);
			}

			const taskIdsToRemove = taskIdsString
				.split(',')
				.map((id) => id.trim())
				.filter(Boolean);

			if (taskIdsToRemove.length === 0) {
				console.error(chalk.red('Error: No valid task IDs provided.'));
				process.exit(1);
			}

			try {
				// Read data once for checks and confirmation
				const tasksPath = taskMaster.getTasksPath();
				const data = readJSON(tasksPath, taskMaster.getProjectRoot(), tag);
				if (!data || !data.tasks) {
					console.error(
						chalk.red(`Error: No valid tasks found in ${tasksPath}`)
					);
					process.exit(1);
				}

				const existingTasksToRemove = [];
				const nonExistentIds = [];
				let totalSubtasksToDelete = 0;
				const dependentTaskMessages = [];

				for (const taskId of taskIdsToRemove) {
					if (!taskExists(data.tasks, taskId)) {
						nonExistentIds.push(taskId);
					} else {
						// Correctly extract the task object from the result of findTaskById
						const findResult = findTaskById(data.tasks, taskId);
						const taskObject = findResult.task; // Get the actual task/subtask object

						if (taskObject) {
							existingTasksToRemove.push({ id: taskId, task: taskObject }); // Push the actual task object

							// If it's a main task, count its subtasks and check dependents
							if (!taskObject.isSubtask) {
								// Check the actual task object
								if (taskObject.subtasks && taskObject.subtasks.length > 0) {
									totalSubtasksToDelete += taskObject.subtasks.length;
								}
								const dependentTasks = data.tasks.filter(
									(t) =>
										t.dependencies &&
										t.dependencies.includes(parseInt(taskId, 10))
								);
								if (dependentTasks.length > 0) {
									dependentTaskMessages.push(
										`  - Task ${taskId}: ${dependentTasks.length} dependent tasks (${dependentTasks.map((t) => t.id).join(', ')})`
									);
								}
							}
						} else {
							// Handle case where findTaskById returned null for the task property (should be rare)
							nonExistentIds.push(`${taskId} (error finding details)`);
						}
					}
				}

				if (nonExistentIds.length > 0) {
					console.warn(
						chalk.yellow(
							`Warning: The following task IDs were not found: ${nonExistentIds.join(', ')}`
						)
					);
				}

				if (existingTasksToRemove.length === 0) {
					console.log(chalk.blue('No existing tasks found to remove.'));
					process.exit(0);
				}

				// Skip confirmation if --yes flag is provided
				if (!options.yes) {
					console.log();
					console.log(
						chalk.red.bold(
							`⚠️ WARNING: This will permanently delete the following ${existingTasksToRemove.length} item(s):`
						)
					);
					console.log();

					existingTasksToRemove.forEach(({ id, task }) => {
						if (!task) return; // Should not happen due to taskExists check, but safeguard
						if (task.isSubtask) {
							// Subtask - title is directly on the task object
							console.log(
								chalk.white(`  Subtask ${id}: ${task.title || '(no title)'}`)
							);
							// Optionally show parent context if available
							if (task.parentTask) {
								console.log(
									chalk.gray(
										`    (Parent: ${task.parentTask.id} - ${task.parentTask.title || '(no title)'})`
									)
								);
							}
						} else {
							// Main task - title is directly on the task object
							console.log(
								chalk.white.bold(`  Task ${id}: ${task.title || '(no title)'}`)
							);
						}
					});

					if (totalSubtasksToDelete > 0) {
						console.log(
							chalk.yellow(
								`⚠️ This will also delete ${totalSubtasksToDelete} subtasks associated with the selected main tasks!`
							)
						);
					}

					if (dependentTaskMessages.length > 0) {
						console.log(
							chalk.yellow(
								'⚠️ Warning: Dependencies on the following tasks will be removed:'
							)
						);
						dependentTaskMessages.forEach((msg) =>
							console.log(chalk.yellow(msg))
						);
					}

					console.log();

					const { confirm } = await inquirer.prompt([
						{
							type: 'confirm',
							name: 'confirm',
							message: chalk.red.bold(
								`Are you sure you want to permanently delete these ${existingTasksToRemove.length} item(s)?`
							),
							default: false
						}
					]);

					if (!confirm) {
						console.log(chalk.blue('Task deletion cancelled.'));
						process.exit(0);
					}
				}

				const indicator = startLoadingIndicator(
					`Removing ${existingTasksToRemove.length} task(s)/subtask(s)...`
				);

				// Use the string of existing IDs for the core function
				const existingIdsString = existingTasksToRemove
					.map(({ id }) => id)
					.join(',');
				const result = await removeTask(
					taskMaster.getTasksPath(),
					existingIdsString,
					{
						projectRoot: taskMaster.getProjectRoot(),
						tag
					}
				);

				stopLoadingIndicator(indicator);

				if (result.success) {
					console.log(
						boxen(
							chalk.green(
								`Successfully removed ${result.removedTasks.length} task(s)/subtask(s).`
							) +
								(result.message ? `\n\nDetails:\n${result.message}` : '') +
								(result.error
									? `\n\nWarnings:\n${chalk.yellow(result.error)}`
									: ''),
							{ padding: 1, borderColor: 'green', borderStyle: 'round' }
						)
					);
				} else {
					console.error(
						boxen(
							chalk.red(
								`Operation completed with errors. Removed ${result.removedTasks.length} task(s)/subtask(s).`
							) +
								(result.message ? `\n\nDetails:\n${result.message}` : '') +
								(result.error ? `\n\nErrors:\n${chalk.red(result.error)}` : ''),
							{
								padding: 1,
								borderColor: 'red',
								borderStyle: 'round'
							}
						)
					);
					process.exit(1); // Exit with error code if any part failed
				}

				// Log any initially non-existent IDs again for clarity
				if (nonExistentIds.length > 0) {
					console.warn(
						chalk.yellow(
							`Note: The following IDs were not found initially and were skipped: ${nonExistentIds.join(', ')}`
						)
					);

					// Exit with error if any removals failed
					if (result.removedTasks.length === 0) {
						process.exit(1);
					}
				}
			} catch (error) {
				console.error(
					chalk.red(`Error: ${error.message || 'An unknown error occurred'}`)
				);
				process.exit(1);
			}
		});

	// init command (Directly calls the implementation from init.js)
	programInstance
		.command('init')
		.description('Initialize a new project with Task Master structure')
		.option('-y, --yes', 'Skip prompts and use default values')
		.option('-n, --name <name>', 'Project name')
		.option('-d, --description <description>', 'Project description')
		.option('-v, --version <version>', 'Project version', '0.1.0') // Set default here
		.option('-a, --author <author>', 'Author name')
		.option(
			'-r, --rules <rules...>',
			'List of rules to add (roo, windsurf, cursor, ...). Accepts comma or space separated values.'
		)
		.option('--skip-install', 'Skip installing dependencies')
		.option('--dry-run', 'Show what would be done without making changes')
		.option('--aliases', 'Add shell aliases (tm, taskmaster, hamster, ham)')
		.option('--no-aliases', 'Skip shell aliases (tm, taskmaster, hamster, ham)')
		.option('--git', 'Initialize Git repository')
		.option('--no-git', 'Skip Git repository initialization')
		.option('--git-tasks', 'Store tasks in Git')
		.option('--no-git-tasks', 'No Git storage of tasks')
		.action(async (cmdOptions) => {
			// cmdOptions contains parsed arguments
			// Parse rules: accept space or comma separated, default to all available rules
			let selectedProfiles = RULE_PROFILES;
			let rulesExplicitlyProvided = false;

			if (cmdOptions.rules && Array.isArray(cmdOptions.rules)) {
				const userSpecifiedProfiles = cmdOptions.rules
					.flatMap((r) => r.split(','))
					.map((r) => r.trim())
					.filter(Boolean);
				// Only override defaults if user specified valid rules
				if (userSpecifiedProfiles.length > 0) {
					selectedProfiles = userSpecifiedProfiles;
					rulesExplicitlyProvided = true;
				}
			}

			cmdOptions.rules = selectedProfiles;
			cmdOptions.rulesExplicitlyProvided = rulesExplicitlyProvided;

			try {
				// Directly call the initializeProject function, passing the parsed options
				await initializeProject(cmdOptions);
				// initializeProject handles its own flow, including potential process.exit()
			} catch (error) {
				console.error(
					chalk.red(`Error during initialization: ${error.message}`)
				);
				process.exit(1);
			}
		});

	// models command
	programInstance
		.command('models')
		.description('Manage AI model configurations')
		.option(
			'--set-main <model_id>',
			'Set the primary model for task generation/updates'
		)
		.option(
			'--set-research <model_id>',
			'Set the model for research-backed operations'
		)
		.option(
			'--set-fallback <model_id>',
			'Set the model to use if the primary fails'
		)
		.option('--setup', 'Run interactive setup to configure models')
		.option(
			'--openrouter',
			'Allow setting a custom OpenRouter model ID (use with --set-*) '
		)
		.option(
			'--ollama',
			'Allow setting a custom Ollama model ID (use with --set-*) '
		)
		.option(
			'--bedrock',
			'Allow setting a custom Bedrock model ID (use with --set-*) '
		)
		.option(
			'--claude-code',
			'Allow setting a Claude Code model ID (use with --set-*)'
		)
		.option(
			'--azure',
			'Allow setting a custom Azure OpenAI model ID (use with --set-*) '
		)
		.option(
			'--vertex',
			'Allow setting a custom Vertex AI model ID (use with --set-*) '
		)
		.option(
			'--gemini-cli',
			'Allow setting a Gemini CLI model ID (use with --set-*)'
		)
		.option(
			'--codex-cli',
			'Allow setting a Codex CLI model ID (use with --set-*)'
		)
		.option(
			'--lmstudio',
			'Allow setting a custom LM Studio model ID (use with --set-*)'
		)
		.option(
			'--openai-compatible',
			'Allow setting a custom OpenAI-compatible model ID (use with --set-*)'
		)
		.option(
			'--baseURL <url>',
			'Custom base URL for openai-compatible, lmstudio, or ollama providers (e.g., http://localhost:8000/v1)'
		)
		.addHelpText(
			'after',
			`
Examples:
  $ task-master models                              # View current configuration
  $ task-master models --set-main gpt-4o             # Set main model (provider inferred)
  $ task-master models --set-research sonar-pro       # Set research model
  $ task-master models --set-fallback claude-3-5-sonnet-20241022 # Set fallback
  $ task-master models --set-main my-custom-model --ollama  # Set custom Ollama model for main role
  $ task-master models --set-main anthropic.claude-3-sonnet-20240229-v1:0 --bedrock # Set custom Bedrock model for main role
  $ task-master models --set-main some/other-model --openrouter # Set custom OpenRouter model for main role
  $ task-master models --set-main sonnet --claude-code           # Set Claude Code model for main role
  $ task-master models --set-main gpt-4o --azure # Set custom Azure OpenAI model for main role
  $ task-master models --set-main claude-3-5-sonnet@20241022 --vertex # Set custom Vertex AI model for main role
  $ task-master models --set-main gemini-2.5-pro --gemini-cli # Set Gemini CLI model for main role
  $ task-master models --set-main gpt-5-codex --codex-cli     # Set Codex CLI model for main role
  $ task-master models --set-main qwen3-vl-4b --lmstudio      # Set LM Studio model for main role (defaults to http://localhost:1234/v1)
  $ task-master models --set-main qwen3-vl-4b --lmstudio --baseURL http://localhost:8000/v1 # Set LM Studio model with custom base URL
  $ task-master models --set-main my-model --openai-compatible --baseURL http://localhost:8000/v1 # Set custom OpenAI-compatible model with custom endpoint
  $ task-master models --setup                            # Run interactive setup`
		)
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || false
			});

			const projectRoot = taskMaster.getProjectRoot();

			// Validate flags: cannot use multiple provider flags simultaneously
			const providerFlags = [
				options.openrouter,
				options.ollama,
				options.bedrock,
				options.claudeCode,
				options.geminiCli,
				options.codexCli,
				options.lmstudio,
				options.openaiCompatible
			].filter(Boolean).length;
			if (providerFlags > 1) {
				console.error(
					chalk.red(
						'Error: Cannot use multiple provider flags (--openrouter, --ollama, --bedrock, --claude-code, --gemini-cli, --codex-cli, --lmstudio, --openai-compatible) simultaneously.'
					)
				);
				process.exit(1);
			}

			// Determine the primary action based on flags
			const isSetup = options.setup;
			const isSetOperation =
				options.setMain || options.setResearch || options.setFallback;

			// --- Execute Action ---

			if (isSetup) {
				// Action 1: Run Interactive Setup
				console.log(chalk.blue('Starting interactive model setup...')); // Added feedback
				try {
					await runInteractiveSetup(taskMaster.getProjectRoot());
					// runInteractiveSetup logs its own completion/error messages
				} catch (setupError) {
					console.error(
						chalk.red('\\nInteractive setup failed unexpectedly:'),
						setupError.message
					);
				}
				// --- IMPORTANT: Exit after setup ---
				return; // Stop execution here
			}

			if (isSetOperation) {
				// Action 2: Perform Direct Set Operations
				let updateOccurred = false; // Track if any update actually happened

				if (options.setMain) {
					const result = await setModel('main', options.setMain, {
						projectRoot,
						providerHint: options.openrouter
							? 'openrouter'
							: options.ollama
								? 'ollama'
								: options.bedrock
									? 'bedrock'
									: options.claudeCode
										? 'claude-code'
										: options.geminiCli
											? 'gemini-cli'
											: options.codexCli
												? 'codex-cli'
												: options.lmstudio
													? 'lmstudio'
													: options.openaiCompatible
														? 'openai-compatible'
														: undefined,
						baseURL: options.baseURL
					});
					if (result.success) {
						console.log(chalk.green(`✅ ${result.data.message}`));
						if (result.data.warning)
							console.log(chalk.yellow(result.data.warning));
						updateOccurred = true;
					} else {
						console.error(
							chalk.red(`❌ Error setting main model: ${result.error.message}`)
						);
					}
				}
				if (options.setResearch) {
					const result = await setModel('research', options.setResearch, {
						projectRoot,
						providerHint: options.openrouter
							? 'openrouter'
							: options.ollama
								? 'ollama'
								: options.bedrock
									? 'bedrock'
									: options.claudeCode
										? 'claude-code'
										: options.geminiCli
											? 'gemini-cli'
											: options.codexCli
												? 'codex-cli'
												: options.lmstudio
													? 'lmstudio'
													: options.openaiCompatible
														? 'openai-compatible'
														: undefined,
						baseURL: options.baseURL
					});
					if (result.success) {
						console.log(chalk.green(`✅ ${result.data.message}`));
						if (result.data.warning)
							console.log(chalk.yellow(result.data.warning));
						updateOccurred = true;
					} else {
						console.error(
							chalk.red(
								`❌ Error setting research model: ${result.error.message}`
							)
						);
					}
				}
				if (options.setFallback) {
					const result = await setModel('fallback', options.setFallback, {
						projectRoot,
						providerHint: options.openrouter
							? 'openrouter'
							: options.ollama
								? 'ollama'
								: options.bedrock
									? 'bedrock'
									: options.claudeCode
										? 'claude-code'
										: options.geminiCli
											? 'gemini-cli'
											: options.codexCli
												? 'codex-cli'
												: options.lmstudio
													? 'lmstudio'
													: options.openaiCompatible
														? 'openai-compatible'
														: undefined,
						baseURL: options.baseURL
					});
					if (result.success) {
						console.log(chalk.green(`✅ ${result.data.message}`));
						if (result.data.warning)
							console.log(chalk.yellow(result.data.warning));
						updateOccurred = true;
					} else {
						console.error(
							chalk.red(
								`❌ Error setting fallback model: ${result.error.message}`
							)
						);
					}
				}

				// Optional: Add a final confirmation if any update occurred
				if (updateOccurred) {
					console.log(chalk.blue('\nModel configuration updated.'));
				} else {
					console.log(
						chalk.yellow(
							'\nNo model configuration changes were made (or errors occurred).'
						)
					);
				}

				// --- IMPORTANT: Exit after set operations ---
				return; // Stop execution here
			}

			// Action 3: Display Full Status (Only runs if no setup and no set flags)
			console.log(chalk.blue('Fetching current model configuration...')); // Added feedback
			const configResult = await getModelConfiguration({ projectRoot });
			const availableResult = await getAvailableModelsList({ projectRoot });
			const apiKeyStatusResult = await getApiKeyStatusReport({ projectRoot });

			// 1. Display Active Models
			if (!configResult.success) {
				console.error(
					chalk.red(
						`❌ Error fetching configuration: ${configResult.error.message}`
					)
				);
			} else {
				displayModelConfiguration(
					configResult.data,
					availableResult.data?.models || []
				);
			}

			// 2. Display API Key Status
			if (apiKeyStatusResult.success) {
				displayApiKeyStatus(apiKeyStatusResult.data.report);
			} else {
				console.error(
					chalk.yellow(
						`⚠️ Warning: Could not display API Key status: ${apiKeyStatusResult.error.message}`
					)
				);
			}

			// 3. Display Other Available Models (Filtered)
			if (availableResult.success) {
				const activeIds = configResult.success
					? [
							configResult.data.activeModels.main.modelId,
							configResult.data.activeModels.research.modelId,
							configResult.data.activeModels.fallback?.modelId
						].filter(Boolean)
					: [];
				const displayableAvailable = availableResult.data.models.filter(
					(m) => !activeIds.includes(m.modelId) && !m.modelId.startsWith('[')
				);
				displayAvailableModels(displayableAvailable);
			} else {
				console.error(
					chalk.yellow(
						`⚠️ Warning: Could not display available models: ${availableResult.error.message}`
					)
				);
			}

			// 4. Conditional Hint if Config File is Missing
			const configExists = isConfigFilePresent(projectRoot);
			if (!configExists) {
				console.log(
					chalk.yellow(
						"\\nHint: Run 'task-master models --setup' to create or update your configuration."
					)
				);
			}
			// --- IMPORTANT: Exit after displaying status ---
			return; // Stop execution here
		});

	// response-language command
	programInstance
		.command('lang')
		.description('Manage response language settings')
		.option('--response <response_language>', 'Set the response language')
		.option('--setup', 'Run interactive setup to configure response language')
		.action(async (options) => {
			const taskMaster = initTaskMaster({});
			const projectRoot = taskMaster.getProjectRoot(); // Find project root for context
			const { response, setup } = options;
			let responseLanguage = response !== undefined ? response : 'English';
			if (setup) {
				console.log(
					chalk.blue('Starting interactive response language setup...')
				);
				try {
					const userResponse = await inquirer.prompt([
						{
							type: 'input',
							name: 'responseLanguage',
							message: 'Input your preferred response language',
							default: 'English'
						}
					]);

					console.log(
						chalk.blue(
							'Response language set to:',
							userResponse.responseLanguage
						)
					);
					responseLanguage = userResponse.responseLanguage;
				} catch (setupError) {
					console.error(
						chalk.red('\\nInteractive setup failed unexpectedly:'),
						setupError.message
					);
				}
			}

			const result = setResponseLanguage(responseLanguage, {
				projectRoot
			});

			if (result.success) {
				console.log(chalk.green(`✅ ${result.data.message}`));
			} else {
				console.error(
					chalk.red(
						`❌ Error setting response language: ${result.error.message}`
					)
				);
				process.exit(1);
			}
		});

	// move-task command
	programInstance
		.command('move')
		.description(
			'Move tasks between tags or reorder within tags. Supports cross-tag moves with dependency resolution options.'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'--from <id>',
			'ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated to move multiple tasks (e.g., "5,6,7")'
		)
		.option(
			'--to <id>',
			'ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated'
		)
		.option('--tag <tag>', 'Specify tag context for task operations')
		.option('--from-tag <tag>', 'Source tag for cross-tag moves')
		.option('--to-tag <tag>', 'Target tag for cross-tag moves')
		.option('--with-dependencies', 'Move dependent tasks along with main task')
		.option('--ignore-dependencies', 'Break cross-tag dependencies during move')
		.action(async (options) => {
			// Helper function to show move command help - defined in scope for proper encapsulation
			function showMoveHelp() {
				console.log(
					chalk.white.bold('Move Command Help') +
						'\n\n' +
						chalk.cyan('Move tasks between tags or reorder within tags.') +
						'\n\n' +
						chalk.yellow.bold('Within-Tag Moves:') +
						'\n' +
						chalk.white('  task-master move --from=5 --to=7') +
						'\n' +
						chalk.white('  task-master move --from=5.2 --to=7.3') +
						'\n' +
						chalk.white('  task-master move --from=5,6,7 --to=10,11,12') +
						'\n\n' +
						chalk.yellow.bold('Cross-Tag Moves:') +
						'\n' +
						chalk.white(
							'  task-master move --from=5 --from-tag=backlog --to-tag=in-progress'
						) +
						'\n' +
						chalk.white(
							'  task-master move --from=5,6 --from-tag=backlog --to-tag=done'
						) +
						'\n\n' +
						chalk.yellow.bold('Dependency Resolution:') +
						'\n' +
						chalk.white('  # Move with dependencies') +
						'\n' +
						chalk.white(
							'  task-master move --from=5 --from-tag=backlog --to-tag=in-progress --with-dependencies'
						) +
						'\n\n' +
						chalk.white('  # Break dependencies') +
						'\n' +
						chalk.white(
							'  task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies'
						) +
						'\n\n' +
						'\n' +
						chalk.yellow.bold('Best Practices:') +
						'\n' +
						chalk.white(
							'  • Use --with-dependencies to move dependent tasks together'
						) +
						'\n' +
						chalk.white(
							'  • Use --ignore-dependencies to break cross-tag dependencies'
						) +
						'\n' +
						chalk.white(
							'  • Check dependencies first: task-master validate-dependencies'
						) +
						'\n' +
						chalk.white(
							'  • Fix dependency issues: task-master fix-dependencies'
						) +
						'\n\n' +
						chalk.yellow.bold('Error Resolution:') +
						'\n' +
						chalk.white(
							'  • Cross-tag dependency conflicts: Use --with-dependencies or --ignore-dependencies'
						) +
						'\n' +
						chalk.white(
							'  • Subtask movement: Promote subtask first with remove-subtask --convert'
						) +
						'\n' +
						chalk.white(
							'  • Invalid tags: Check available tags with task-master tags'
						) +
						'\n\n' +
						chalk.gray('For more help, run: task-master move --help')
				);
			}

			// Helper function to handle cross-tag move logic
			async function handleCrossTagMove(moveContext, options) {
				const { sourceId, sourceTag, toTag, taskMaster } = moveContext;

				if (!sourceId) {
					console.error(
						chalk.red('Error: --from parameter is required for cross-tag moves')
					);
					showMoveHelp();
					process.exit(1);
				}

				const sourceIds = sourceId.split(',').map((id) => id.trim());
				const moveOptions = {
					withDependencies: options.withDependencies || false,
					ignoreDependencies: options.ignoreDependencies || false
				};

				console.log(
					chalk.blue(
						`Moving tasks ${sourceIds.join(', ')} from "${sourceTag}" to "${toTag}"...`
					)
				);

				const result = await moveTasksBetweenTags(
					taskMaster.getTasksPath(),
					sourceIds,
					sourceTag,
					toTag,
					moveOptions,
					{ projectRoot: taskMaster.getProjectRoot() }
				);

				console.log(chalk.green(`✓ ${result.message}`));

				// Print any tips returned from the move operation (e.g., after ignoring dependencies)
				if (Array.isArray(result.tips) && result.tips.length > 0) {
					console.log('\n' + chalk.yellow.bold('Next Steps:'));
					result.tips.forEach((t) => console.log(chalk.white(`  • ${t}`)));
				}
			}

			// Helper function to handle within-tag move logic
			async function handleWithinTagMove(moveContext) {
				const { sourceId, destinationId, tag, taskMaster } = moveContext;

				if (!sourceId || !destinationId) {
					console.error(
						chalk.red(
							'Error: Both --from and --to parameters are required for within-tag moves'
						)
					);
					console.log(
						chalk.yellow(
							'Usage: task-master move --from=<sourceId> --to=<destinationId>'
						)
					);
					process.exit(1);
				}

				// Check if we're moving multiple tasks (comma-separated IDs)
				const sourceIds = sourceId.split(',').map((id) => id.trim());
				const destinationIds = destinationId.split(',').map((id) => id.trim());

				// Validate that the number of source and destination IDs match
				if (sourceIds.length !== destinationIds.length) {
					console.error(
						chalk.red(
							'Error: The number of source and destination IDs must match'
						)
					);
					console.log(
						chalk.yellow('Example: task-master move --from=5,6,7 --to=10,11,12')
					);
					process.exit(1);
				}

				// If moving multiple tasks
				if (sourceIds.length > 1) {
					console.log(
						chalk.blue(
							`Moving multiple tasks: ${sourceIds.join(', ')} to ${destinationIds.join(', ')}...`
						)
					);

					// Read tasks data once to validate destination IDs
					const tasksData = readJSON(
						taskMaster.getTasksPath(),
						taskMaster.getProjectRoot(),
						tag
					);
					if (!tasksData || !tasksData.tasks) {
						console.error(
							chalk.red(
								`Error: Invalid or missing tasks file at ${taskMaster.getTasksPath()}`
							)
						);
						process.exit(1);
					}

					// Collect errors during move attempts
					const moveErrors = [];
					const successfulMoves = [];

					// Move tasks one by one
					for (let i = 0; i < sourceIds.length; i++) {
						const fromId = sourceIds[i];
						const toId = destinationIds[i];

						// Skip if source and destination are the same
						if (fromId === toId) {
							console.log(
								chalk.yellow(`Skipping ${fromId} -> ${toId} (same ID)`)
							);
							continue;
						}

						console.log(
							chalk.blue(`Moving task/subtask ${fromId} to ${toId}...`)
						);
						try {
							await moveTask(
								taskMaster.getTasksPath(),
								fromId,
								toId,
								i === sourceIds.length - 1,
								{ projectRoot: taskMaster.getProjectRoot(), tag }
							);
							console.log(
								chalk.green(
									`✓ Successfully moved task/subtask ${fromId} to ${toId}`
								)
							);
							successfulMoves.push({ fromId, toId });
						} catch (error) {
							const errorInfo = {
								fromId,
								toId,
								error: error.message
							};
							moveErrors.push(errorInfo);
							console.error(
								chalk.red(`Error moving ${fromId} to ${toId}: ${error.message}`)
							);
							// Continue with the next task rather than exiting
						}
					}

					// Display summary after all moves are attempted
					if (moveErrors.length > 0) {
						console.log(chalk.yellow('\n--- Move Operation Summary ---'));
						console.log(
							chalk.green(
								`✓ Successfully moved: ${successfulMoves.length} tasks`
							)
						);
						console.log(
							chalk.red(`✗ Failed to move: ${moveErrors.length} tasks`)
						);

						if (successfulMoves.length > 0) {
							console.log(chalk.cyan('\nSuccessful moves:'));
							successfulMoves.forEach(({ fromId, toId }) => {
								console.log(chalk.cyan(`  ${fromId} → ${toId}`));
							});
						}

						console.log(chalk.red('\nFailed moves:'));
						moveErrors.forEach(({ fromId, toId, error }) => {
							console.log(chalk.red(`  ${fromId} → ${toId}: ${error}`));
						});

						console.log(
							chalk.yellow(
								'\nNote: Some tasks were moved successfully. Check the errors above for failed moves.'
							)
						);
					} else {
						console.log(chalk.green('\n✓ All tasks moved successfully!'));
					}
				} else {
					// Moving a single task (existing logic)
					console.log(
						chalk.blue(`Moving task/subtask ${sourceId} to ${destinationId}...`)
					);

					const result = await moveTask(
						taskMaster.getTasksPath(),
						sourceId,
						destinationId,
						true,
						{ projectRoot: taskMaster.getProjectRoot(), tag }
					);
					console.log(
						chalk.green(
							`✓ Successfully moved task/subtask ${sourceId} to ${destinationId}`
						)
					);
				}
			}

			// Helper function to handle move errors
			function handleMoveError(error, moveContext) {
				console.error(chalk.red(`Error: ${error.message}`));

				// Enhanced error handling with structured error objects
				if (error.code === 'CROSS_TAG_DEPENDENCY_CONFLICTS') {
					// Use structured error data
					const conflicts = error.data.conflicts || [];
					const taskIds = error.data.taskIds || [];
					displayCrossTagDependencyError(
						conflicts,
						moveContext.sourceTag,
						moveContext.toTag,
						taskIds.join(', ')
					);
				} else if (error.code === 'CANNOT_MOVE_SUBTASK') {
					// Use structured error data
					const taskId =
						error.data.taskId || moveContext.sourceId?.split(',')[0];
					displaySubtaskMoveError(
						taskId,
						moveContext.sourceTag,
						moveContext.toTag
					);
				} else if (
					error.code === 'SOURCE_TARGET_TAGS_SAME' ||
					error.code === 'SAME_SOURCE_TARGET_TAG'
				) {
					displayInvalidTagCombinationError(
						moveContext.sourceTag,
						moveContext.toTag,
						'Source and target tags are identical'
					);
				} else {
					// General error - show dependency validation hints
					displayDependencyValidationHints('after-error');
				}

				process.exit(1);
			}

			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const sourceId = options.from;
			const destinationId = options.to;
			const fromTag = options.fromTag;
			const toTag = options.toTag;

			const tag = taskMaster.getCurrentTag();

			// Get the source tag - fallback to current tag if not provided
			const sourceTag = fromTag || taskMaster.getCurrentTag();

			// Check if this is a cross-tag move (different tags)
			const isCrossTagMove = sourceTag && toTag && sourceTag !== toTag;

			// Initialize move context with all relevant data
			const moveContext = {
				sourceId,
				destinationId,
				sourceTag,
				toTag,
				tag,
				taskMaster
			};

			try {
				if (isCrossTagMove) {
					// Cross-tag move logic
					await handleCrossTagMove(moveContext, options);
				} else {
					// Within-tag move logic
					await handleWithinTagMove(moveContext);
				}
			} catch (error) {
				const errMsg = String(error && (error.message || error));
				if (errMsg.includes('already exists in target tag')) {
					console.error(chalk.red(`Error: ${errMsg}`));
					console.log(
						'\n' +
							chalk.yellow.bold('Conflict: ID already exists in target tag') +
							'\n' +
							chalk.white(
								'  • Choose a different target tag without conflicting IDs'
							) +
							'\n' +
							chalk.white(
								'  • Move a different set of IDs (avoid existing ones)'
							) +
							'\n' +
							chalk.white(
								'  • If needed, move within-tag to a new ID first, then cross-tag move'
							)
					);
					process.exit(1);
				}
				handleMoveError(error, moveContext);
			}
		});

	// Add/remove profile rules command
	programInstance
		.command('rules [action] [profiles...]')
		.description(
			`Add or remove rules for one or more profiles. Valid actions: ${Object.values(RULES_ACTIONS).join(', ')} (e.g., task-master rules ${RULES_ACTIONS.ADD} windsurf roo)`
		)
		.option(
			'-f, --force',
			'Skip confirmation prompt when removing rules (dangerous)'
		)
		.option(
			`--${RULES_SETUP_ACTION}`,
			'Run interactive setup to select rule profiles to add'
		)
		.option(
			'-m, --mode <mode>',
			'Operating mode for filtering rules/commands (solo or team). Auto-detected from config if not specified.'
		)
		.option(
			'-y, --yes',
			'Non-interactive mode: auto-detect IDEs and install rules without prompting'
		)
		.addHelpText(
			'after',
			`
		Examples:
		$ task-master rules ${RULES_ACTIONS.ADD}                       # Interactive setup with auto-detected IDEs pre-selected
		$ task-master rules ${RULES_ACTIONS.ADD} -y                    # Auto-detect and install without prompting
		$ task-master rules ${RULES_ACTIONS.ADD} windsurf roo          # Add specific profiles
		$ task-master rules ${RULES_ACTIONS.ADD} cursor --mode=team    # Add Cursor rules for team mode only
		$ task-master rules ${RULES_ACTIONS.REMOVE} windsurf          # Remove Windsurf rule set`
		)
		.action(async (action, profiles, options) => {
			const taskMaster = initTaskMaster({});
			const projectRoot = taskMaster.getProjectRoot();
			if (!projectRoot) {
				console.error(chalk.red('Error: Could not find project root.'));
				process.exit(1);
			}

			/**
			 * 'task-master rules --setup' action:
			 *
			 * Launches an interactive prompt to select which rule profiles to add to the current project.
			 * This does NOT perform project initialization or ask about shell aliases—only rules selection.
			 *
			 * Example usage:
			 *   $ task-master rules --setup
			 *
			 * Useful for adding rules after project creation.
			 *
			 * The list of profiles is always up-to-date with the available profiles.
			 */
			if (options[RULES_SETUP_ACTION]) {
				// Run interactive rules setup ONLY (no project init)
				const selectedRuleProfiles =
					await runInteractiveProfilesSetup(projectRoot);

				if (!selectedRuleProfiles || selectedRuleProfiles.length === 0) {
					console.log(chalk.yellow('No profiles selected. Exiting.'));
					return;
				}

				console.log(
					chalk.blue(
						`Installing ${selectedRuleProfiles.length} selected profile(s)...`
					)
				);

				await processRuleProfiles(
					selectedRuleProfiles,
					projectRoot,
					options.mode
				);

				console.log(
					chalk.green(
						`\nCompleted installation of all ${selectedRuleProfiles.length} profile(s).`
					)
				);
				return;
			}

			// Validate action for non-setup mode
			if (!action || !isValidRulesAction(action)) {
				console.error(
					chalk.red(
						`Error: Invalid or missing action '${action || 'none'}'. Valid actions are: ${Object.values(RULES_ACTIONS).join(', ')}`
					)
				);
				console.error(
					chalk.yellow(
						`For interactive setup, use: task-master rules --${RULES_SETUP_ACTION}`
					)
				);
				process.exit(1);
			}

			/**
			 * 'task-master rules add' (no profiles):
			 *
			 * - Without -y: Opens interactive setup with auto-detected IDEs pre-selected
			 * - With -y: Non-interactive mode, installs rules for all detected IDEs
			 *
			 * Example usage:
			 *   $ task-master rules add       # Interactive setup with pre-selection
			 *   $ task-master rules add -y    # Auto-detect and install without prompting
			 */
			if (
				action === RULES_ACTIONS.ADD &&
				(!profiles || profiles.length === 0)
			) {
				let selectedRuleProfiles;

				if (options.yes) {
					// Non-interactive mode: auto-detect and install
					console.log(chalk.blue('\n🔍 Auto-detecting installed IDEs...\n'));

					const detected = detectInstalledIDEs({ projectRoot });

					if (detected.length === 0) {
						console.log(
							chalk.yellow(
								'No IDE markers detected in this project.\n' +
									chalk.gray(
										'Searched for: .cursor, .claude, .windsurf, .roo, .vscode, etc.\n'
									)
							)
						);
						console.log(
							chalk.cyan(
								'To manually select profiles, run without -y flag:\n' +
									'  task-master rules add\n\n' +
									'Or specify profiles directly:\n' +
									'  task-master rules add cursor windsurf\n'
							)
						);
						return;
					}

					// Show what was detected
					console.log(chalk.green('✓ Detected the following IDEs:\n'));
					for (const ide of detected) {
						console.log(
							`  • ${ide.displayName} ${chalk.gray(`(${ide.markerPath})`)}`
						);
					}
					console.log('');

					selectedRuleProfiles = detected.map((d) => d.profileName);
				} else {
					// Interactive mode: open setup with pre-selection
					selectedRuleProfiles = await runInteractiveProfilesSetup(projectRoot);
				}

				if (!selectedRuleProfiles || selectedRuleProfiles.length === 0) {
					console.log(chalk.yellow('No profiles selected. Exiting.'));
					return;
				}

				console.log(
					chalk.blue(
						`Installing ${selectedRuleProfiles.length} selected profile(s)...`
					)
				);

				const addResults = await processRuleProfiles(
					selectedRuleProfiles,
					projectRoot,
					options.mode
				);

				// Final summary
				const { allSuccessfulProfiles, totalSuccess, totalFailed } =
					categorizeProfileResults(addResults);
				console.log(
					chalk.green(
						`\n✓ Successfully installed ${allSuccessfulProfiles.length} profile(s)`
					)
				);
				if (totalSuccess > 0) {
					console.log(
						chalk.gray(
							`  ${totalSuccess} files processed, ${totalFailed} failed`
						)
					);
				}
				return;
			}

			if (!profiles || profiles.length === 0) {
				console.error(
					'Please specify at least one rule profile (e.g., windsurf, roo).'
				);
				process.exit(1);
			}

			// Support both space- and comma-separated profile lists
			const expandedProfiles = profiles
				.flatMap((b) => b.split(',').map((s) => s.trim()))
				.filter(Boolean);

			if (action === RULES_ACTIONS.REMOVE) {
				let confirmed = true;
				if (!options.force) {
					// Check if this removal would leave no profiles remaining
					if (wouldRemovalLeaveNoProfiles(projectRoot, expandedProfiles)) {
						const installedProfiles = getInstalledProfiles(projectRoot);
						confirmed = await confirmRemoveAllRemainingProfiles(
							expandedProfiles,
							installedProfiles
						);
					} else {
						confirmed = await confirmProfilesRemove(expandedProfiles);
					}
				}
				if (!confirmed) {
					console.log(chalk.yellow('Aborted: No rules were removed.'));
					return;
				}
			}

			const removalResults = [];
			const addResults = [];

			for (const profile of expandedProfiles) {
				if (!isValidProfile(profile)) {
					console.warn(
						`Rule profile for "${profile}" not found. Valid profiles: ${RULE_PROFILES.join(', ')}. Skipping.`
					);
					continue;
				}
				const profileConfig = getRulesProfile(profile);

				if (action === RULES_ACTIONS.ADD) {
					console.log(chalk.blue(`Adding rules for profile: ${profile}...`));
					const mode = await getOperatingMode(options.mode);
					const addResult = convertAllRulesToProfileRules(
						projectRoot,
						profileConfig,
						{ mode }
					);
					console.log(
						chalk.blue(`Completed adding rules for profile: ${profile}`)
					);

					// Store result with profile name for summary
					addResults.push({
						profileName: profile,
						success: addResult.success,
						failed: addResult.failed
					});

					console.log(chalk.green(generateProfileSummary(profile, addResult)));
				} else if (action === RULES_ACTIONS.REMOVE) {
					console.log(chalk.blue(`Removing rules for profile: ${profile}...`));
					const result = removeProfileRules(projectRoot, profileConfig);
					removalResults.push(result);
					console.log(
						chalk.green(generateProfileRemovalSummary(profile, result))
					);
				} else {
					console.error(
						`Unknown action. Use "${RULES_ACTIONS.ADD}" or "${RULES_ACTIONS.REMOVE}".`
					);
					process.exit(1);
				}
			}

			// Print summary for additions
			if (action === RULES_ACTIONS.ADD && addResults.length > 0) {
				const { allSuccessfulProfiles, totalSuccess, totalFailed } =
					categorizeProfileResults(addResults);

				if (allSuccessfulProfiles.length > 0) {
					console.log(
						chalk.green(
							`\nSuccessfully processed profiles: ${allSuccessfulProfiles.join(', ')}`
						)
					);

					// Create a descriptive summary
					if (totalSuccess > 0) {
						console.log(
							chalk.green(
								`Total: ${totalSuccess} files processed, ${totalFailed} failed.`
							)
						);
					} else {
						console.log(
							chalk.green(
								`Total: ${allSuccessfulProfiles.length} profile(s) set up successfully.`
							)
						);
					}
				}
			}

			// Print summary for removals
			if (action === RULES_ACTIONS.REMOVE && removalResults.length > 0) {
				const {
					successfulRemovals,
					skippedRemovals,
					failedRemovals,
					removalsWithNotices
				} = categorizeRemovalResults(removalResults);

				if (successfulRemovals.length > 0) {
					console.log(
						chalk.green(
							`\nSuccessfully removed profiles for: ${successfulRemovals.join(', ')}`
						)
					);
				}
				if (skippedRemovals.length > 0) {
					console.log(
						chalk.yellow(
							`Skipped (default or protected): ${skippedRemovals.join(', ')}`
						)
					);
				}
				if (failedRemovals.length > 0) {
					console.log(chalk.red('\nErrors occurred:'));
					failedRemovals.forEach((r) => {
						console.log(chalk.red(`  ${r.profileName}: ${r.error}`));
					});
				}
				// Display notices about preserved files/configurations
				if (removalsWithNotices.length > 0) {
					console.log(chalk.cyan('\nNotices:'));
					removalsWithNotices.forEach((r) => {
						console.log(chalk.cyan(`  ${r.profileName}: ${r.notice}`));
					});
				}

				// Overall summary
				const totalProcessed = removalResults.length;
				const totalSuccessful = successfulRemovals.length;
				const totalSkipped = skippedRemovals.length;
				const totalFailed = failedRemovals.length;

				console.log(
					chalk.blue(
						`\nTotal: ${totalProcessed} profile(s) processed - ${totalSuccessful} removed, ${totalSkipped} skipped, ${totalFailed} failed.`
					)
				);
			}
		});

	programInstance
		.command('migrate')
		.description(
			'Migrate existing project to use the new .taskmaster directory structure'
		)
		.option(
			'-f, --force',
			'Force migration even if .taskmaster directory already exists'
		)
		.option(
			'--backup',
			'Create backup of old files before migration (default: false)',
			false
		)
		.option(
			'--cleanup',
			'Remove old files after successful migration (default: true)',
			true
		)
		.option('-y, --yes', 'Skip confirmation prompts')
		.option(
			'--dry-run',
			'Show what would be migrated without actually moving files'
		)
		.action(async (options) => {
			try {
				await migrateProject(options);
			} catch (error) {
				console.error(chalk.red('Error during migration:'), error.message);
				process.exit(1);
			}
		});

	// sync-readme command
	programInstance
		.command('sync-readme')
		.description('Sync the current task list to README.md in the project root')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('--with-subtasks', 'Include subtasks in the README output')
		.option(
			'-s, --status <status>',
			'Show only tasks matching this status (e.g., pending, done)'
		)
		.option('-t, --tag <tag>', 'Tag to use for the task list (default: master)')
		.action(async (options) => {
			// Initialize TaskMaster
			const taskMaster = initTaskMaster({
				tasksPath: options.file || true,
				tag: options.tag
			});

			const withSubtasks = options.withSubtasks || false;
			const status = options.status || null;

			const tag = taskMaster.getCurrentTag();

			console.log(
				chalk.blue(
					`📝 Syncing tasks to README.md${withSubtasks ? ' (with subtasks)' : ''}${status ? ` (status: ${status})` : ''}...`
				)
			);

			const success = await syncTasksToReadme(taskMaster.getProjectRoot(), {
				withSubtasks,
				status,
				tasksPath: taskMaster.getTasksPath(),
				tag
			});

			if (!success) {
				console.error(chalk.red('❌ Failed to sync tasks to README.md'));
				process.exit(1);
			}
		});

	// ===== TAG MANAGEMENT COMMANDS =====

	// add-tag command (DEPRECATED - use `tm tags add` instead)
	programInstance
		.command('add-tag')
		.description(
			'[DEPRECATED] Create a new tag context for organizing tasks (use "tm tags add" instead)'
		)
		.argument(
			'[tagName]',
			'Name of the new tag to create (optional when using --from-branch)'
		)
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option(
			'--copy-from-current',
			'Copy tasks from the current tag to the new tag'
		)
		.option(
			'--copy-from <tag>',
			'Copy tasks from the specified tag to the new tag'
		)
		.option(
			'--from-branch',
			'Create tag name from current git branch (ignores tagName argument)'
		)
		.option('-d, --description <text>', 'Optional description for the tag')
		.action(async (tagName, options) => {
			// Show deprecation warning
			console.warn(
				chalk.yellow(
					'⚠ Warning: "tm add-tag" is deprecated. Use "tm tags add" instead.'
				)
			);
			console.log(
				chalk.gray('  This command will be removed in a future version.\n')
			);

			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true
				});
				const tasksPath = taskMaster.getTasksPath();

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					console.log(
						chalk.yellow(
							'Hint: Run task-master init or task-master parse-prd to create tasks.json first'
						)
					);
					process.exit(1);
				}

				// Validate that either tagName is provided or --from-branch is used
				if (!tagName && !options.fromBranch) {
					console.error(
						chalk.red(
							'Error: Either tagName argument or --from-branch option is required.'
						)
					);
					console.log(chalk.yellow('Usage examples:'));
					console.log(chalk.cyan('  task-master add-tag my-tag'));
					console.log(chalk.cyan('  task-master add-tag --from-branch'));
					process.exit(1);
				}

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					commandName: 'add-tag',
					outputType: 'cli'
				};

				// Handle --from-branch option
				if (options.fromBranch) {
					const { createTagFromBranch } = await import(
						'./task-manager/tag-management.js'
					);
					const gitUtils = await import('./utils/git-utils.js');

					// Check if we're in a git repository
					if (!(await gitUtils.isGitRepository(context.projectRoot))) {
						console.error(
							chalk.red(
								'Error: Not in a git repository. Cannot use --from-branch option.'
							)
						);
						process.exit(1);
					}

					// Get current git branch
					const currentBranch = await gitUtils.getCurrentBranch(
						context.projectRoot
					);
					if (!currentBranch) {
						console.error(
							chalk.red('Error: Could not determine current git branch.')
						);
						process.exit(1);
					}

					// Create tag from branch
					const branchOptions = {
						copyFromCurrent: options.copyFromCurrent || false,
						copyFromTag: options.copyFrom,
						description:
							options.description ||
							`Tag created from git branch "${currentBranch}"`
					};

					await createTagFromBranch(
						taskMaster.getTasksPath(),
						currentBranch,
						branchOptions,
						context,
						'text'
					);
				} else {
					// Regular tag creation
					const createOptions = {
						copyFromCurrent: options.copyFromCurrent || false,
						copyFromTag: options.copyFrom,
						description: options.description
					};

					await createTag(
						taskMaster.getTasksPath(),
						tagName,
						createOptions,
						context,
						'text'
					);
				}

				// Handle auto-switch if requested
				if (options.autoSwitch) {
					const { useTag } = await import('./task-manager/tag-management.js');
					const finalTagName = options.fromBranch
						? (await import('./utils/git-utils.js')).sanitizeBranchNameForTag(
								await (await import('./utils/git-utils.js')).getCurrentBranch(
									projectRoot
								)
							)
						: tagName;
					await useTag(
						taskMaster.getTasksPath(),
						finalTagName,
						{},
						context,
						'text'
					);
				}
			} catch (error) {
				console.error(chalk.red(`Error creating tag: ${error.message}`));
				showAddTagHelp();
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			showAddTagHelp();
			process.exit(1);
		});

	// delete-tag command (DEPRECATED - use `tm tags remove` instead)
	programInstance
		.command('delete-tag')
		.description(
			'[DEPRECATED] Delete an existing tag and all its tasks (use "tm tags remove" instead)'
		)
		.argument('<tagName>', 'Name of the tag to delete')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('-y, --yes', 'Skip confirmation prompts')
		.action(async (tagName, options) => {
			// Show deprecation warning
			console.warn(
				chalk.yellow(
					'⚠ Warning: "tm delete-tag" is deprecated. Use "tm tags remove" instead.'
				)
			);
			console.log(
				chalk.gray('  This command will be removed in a future version.\n')
			);

			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true
				});
				const tasksPath = taskMaster.getTasksPath();

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				const deleteOptions = {
					yes: options.yes || false
				};

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					commandName: 'delete-tag',
					outputType: 'cli'
				};

				await deleteTag(
					taskMaster.getTasksPath(),
					tagName,
					deleteOptions,
					context,
					'text'
				);
			} catch (error) {
				console.error(chalk.red(`Error deleting tag: ${error.message}`));
				showDeleteTagHelp();
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			showDeleteTagHelp();
			process.exit(1);
		});

	// tags command - REMOVED
	// This command has been replaced by the new CommandRegistry-based TagsCommand
	// in apps/cli/src/commands/tags.command.ts
	// The old implementation is no longer needed

	// use-tag command (DEPRECATED - use `tm tags use` instead)
	programInstance
		.command('use-tag')
		.description(
			'[DEPRECATED] Switch to a different tag context (use "tm tags use" instead)'
		)
		.argument('<tagName>', 'Name of the tag to switch to')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.action(async (tagName, options) => {
			// Show deprecation warning
			console.warn(
				chalk.yellow(
					'⚠ Warning: "tm use-tag" is deprecated. Use "tm tags use" instead.'
				)
			);
			console.log(
				chalk.gray('  This command will be removed in a future version.\n')
			);

			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true
				});
				const tasksPath = taskMaster.getTasksPath();

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					commandName: 'use-tag',
					outputType: 'cli'
				};

				await useTag(taskMaster.getTasksPath(), tagName, {}, context, 'text');
			} catch (error) {
				console.error(chalk.red(`Error switching tag: ${error.message}`));
				showUseTagHelp();
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			showUseTagHelp();
			process.exit(1);
		});

	// rename-tag command (DEPRECATED - use `tm tags rename` instead)
	programInstance
		.command('rename-tag')
		.description(
			'[DEPRECATED] Rename an existing tag (use "tm tags rename" instead)'
		)
		.argument('<oldName>', 'Current name of the tag')
		.argument('<newName>', 'New name for the tag')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.action(async (oldName, newName, options) => {
			// Show deprecation warning
			console.warn(
				chalk.yellow(
					'⚠ Warning: "tm rename-tag" is deprecated. Use "tm tags rename" instead.'
				)
			);
			console.log(
				chalk.gray('  This command will be removed in a future version.\n')
			);

			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true
				});
				const tasksPath = taskMaster.getTasksPath();

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					commandName: 'rename-tag',
					outputType: 'cli'
				};

				await renameTag(
					taskMaster.getTasksPath(),
					oldName,
					newName,
					{},
					context,
					'text'
				);
			} catch (error) {
				console.error(chalk.red(`Error renaming tag: ${error.message}`));
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			process.exit(1);
		});

	// copy-tag command (DEPRECATED - use `tm tags copy` instead)
	programInstance
		.command('copy-tag')
		.description(
			'[DEPRECATED] Copy an existing tag to create a new tag with the same tasks (use "tm tags copy" instead)'
		)
		.argument('<sourceName>', 'Name of the source tag to copy from')
		.argument('<targetName>', 'Name of the new tag to create')
		.option(
			'-f, --file <file>',
			'Path to the tasks file',
			TASKMASTER_TASKS_FILE
		)
		.option('-d, --description <text>', 'Optional description for the new tag')
		.action(async (sourceName, targetName, options) => {
			// Show deprecation warning
			console.warn(
				chalk.yellow(
					'⚠ Warning: "tm copy-tag" is deprecated. Use "tm tags copy" instead.'
				)
			);
			console.log(
				chalk.gray('  This command will be removed in a future version.\n')
			);

			try {
				// Initialize TaskMaster
				const taskMaster = initTaskMaster({
					tasksPath: options.file || true
				});
				const tasksPath = taskMaster.getTasksPath();

				// Validate tasks file exists
				if (!fs.existsSync(tasksPath)) {
					console.error(
						chalk.red(`Error: Tasks file not found at path: ${tasksPath}`)
					);
					process.exit(1);
				}

				const copyOptions = {
					description: options.description
				};

				const context = {
					projectRoot: taskMaster.getProjectRoot(),
					commandName: 'copy-tag',
					outputType: 'cli'
				};

				await copyTag(
					tasksPath,
					sourceName,
					targetName,
					copyOptions,
					context,
					'text'
				);
			} catch (error) {
				console.error(chalk.red(`Error copying tag: ${error.message}`));
				process.exit(1);
			}
		})
		.on('error', function (err) {
			console.error(chalk.red(`Error: ${err.message}`));
			process.exit(1);
		});

	// tui / repl command - launches the interactive TUI
	programInstance
		.command('tui')
		.alias('repl')
		.description('Launch the interactive TUI/REPL mode')
		.action(async () => {
			await launchREPL();
		});

	return programInstance;
}

/**
 * Launch the interactive TUI REPL
 */
async function launchREPL() {
	const React = await import('react');
	const tui = await loadTUI();

	if (!tui) {
		// Fallback to help if TUI not available
		console.log(
			chalk.yellow('TUI mode not available. Install @tm/tui to enable.')
		);
		console.log(chalk.dim('Showing help instead...\n'));
		if (isConnectedToHamster()) {
			displayHamsterHelp();
		} else {
			displayHelp();
		}
		return;
	}

	const { render, Shell } = tui;

	// Get current context
	let tag = 'master';
	let storageType = 'local';
	let brief = undefined;
	let authState = { isAuthenticated: false };
	let projectRoot = process.cwd();

	try {
		const taskMaster = initTaskMaster({});
		tag = taskMaster.getCurrentTag();
		projectRoot = taskMaster.getProjectRoot() || process.cwd();

		// Check if connected to Hamster
		const authManager = AuthManager.getInstance();
		const context = authManager.getContext();
		const storedContext = authManager.getStoredContext();

		// Build auth state from stored context
		if (storedContext && storedContext.email) {
			authState = {
				isAuthenticated: true,
				email: storedContext.email,
				userId: storedContext.userId
			};
		}

		if (context && context.briefId) {
			storageType = 'api';
			brief = {
				id: context.briefId,
				name: context.briefName || tag
			};
		}
	} catch (error) {
		// Use defaults
	}

	// Check if stdin supports raw mode (required for interactive TUI)
	const isInteractive =
		process.stdin.isTTY && typeof process.stdin.setRawMode === 'function';

	// Clear screen
	console.clear();

	// Shell props with interactive flag and auth state
	const shellProps = {
		showBanner: true,
		showSplash: isInteractive,
		initialTag: tag,
		storageType: storageType,
		brief: brief,
		authState: authState,
		isInteractive: isInteractive,
		projectRoot: projectRoot,
		onExit: () => {
			console.log(chalk.dim('\nGoodbye! 👋'));
			process.exit(0);
		}
	};

	const instance = render(React.createElement(Shell, shellProps));

	// In non-interactive mode, wait for render then exit
	if (!isInteractive) {
		setTimeout(() => {
			instance.unmount();
			console.log(
				chalk.dim('\n💡 Run in an interactive terminal for full REPL mode.')
			);
			process.exit(0);
		}, 200);
	}
}

/**
 * Setup the CLI application
 * @returns {Object} Configured Commander program
 */
function setupCLI() {
	// Create a new program instance
	const programInstance = new Command()
		.name('task-master')
		.description('AI-driven development task management')
		.version(process.env.TM_PUBLIC_VERSION || 'unknown')
		.helpOption('-h, --help', 'Display help')
		.addHelpCommand(false); // Disable default help command

	// Only override help for the main program, not for individual commands
	const originalHelpInformation =
		programInstance.helpInformation.bind(programInstance);
	programInstance.helpInformation = function () {
		// If this is being called for a subcommand, use the default Commander.js help
		if (this.parent && this.parent !== programInstance) {
			return originalHelpInformation();
		}
		// If this is the main program help, use our custom display
		// Check if connected to Hamster and show appropriate help
		if (isConnectedToHamster()) {
			displayHamsterHelp();
		} else {
			displayHelp();
		}
		return '';
	};

	// Register commands
	registerCommands(programInstance);

	return programInstance;
}

/**
 * Parse arguments and run the CLI
 * @param {Array} argv - Command-line arguments
 */
async function runCLI(argv = process.argv) {
	try {
		// If no arguments provided, launch the TUI REPL (which has its own banner)
		if (argv.length <= 2) {
			await launchREPL();
			return;
		}

		// Display banner if not in a pipe (except for init/start/repl commands which have their own)
		const isInitCommand = argv.includes('init');
		const isREPLCommand = argv.includes('tui') || argv.includes('repl');
		if (process.stdout.isTTY && !isInitCommand && !isREPLCommand) {
			displayBanner();
		}

		// Check for updates BEFORE executing the command (skip entirely in test/CI mode)
		const skipAutoUpdate =
			process.env.TASKMASTER_SKIP_AUTO_UPDATE === '1' ||
			process.env.CI ||
			process.env.NODE_ENV === 'test';

		const currentVersion = getTaskMasterVersion();
		const updateInfo = skipAutoUpdate
			? { currentVersion, latestVersion: currentVersion, needsUpdate: false }
			: await checkForUpdate(currentVersion);

		if (updateInfo.needsUpdate) {
			// Display the upgrade notification first
			displayUpgradeNotification(
				updateInfo.currentVersion,
				updateInfo.latestVersion,
				updateInfo.highlights
			);

			// Automatically perform the update
			const updateSuccess = await performAutoUpdate(updateInfo.latestVersion);
			if (updateSuccess) {
				// Restart with the new version - this will execute the user's command
				restartWithNewVersion(argv);
				return; // Never reached, but for clarity
			}
			// If update fails, continue with current version
		}

		// Setup and parse
		// NOTE: getConfig() might be called during setupCLI->registerCommands if commands need config
		// This means the ConfigurationError might be thrown here if configuration file is missing.
		const programInstance = setupCLI();
		await programInstance.parseAsync(argv);

		// Check if migration has occurred and show FYI notice once
		try {
			// Use initTaskMaster with no required fields - will only fail if no project root
			const taskMaster = initTaskMaster({});

			const tasksPath = taskMaster.getTasksPath();
			const statePath = taskMaster.getStatePath();

			if (tasksPath && fs.existsSync(tasksPath)) {
				// Read raw file to check if it has master key (bypassing tag resolution)
				const rawData = fs.readFileSync(tasksPath, 'utf8');
				const parsedData = JSON.parse(rawData);

				if (parsedData && parsedData.master) {
					// Migration has occurred, check if we've shown the notice
					let stateData = { migrationNoticeShown: false };
					if (statePath && fs.existsSync(statePath)) {
						// Read state.json directly without tag resolution since it's not a tagged file
						const rawStateData = fs.readFileSync(statePath, 'utf8');
						stateData = JSON.parse(rawStateData) || stateData;
					}

					if (!stateData.migrationNoticeShown) {
						displayTaggedTasksFYI({ _migrationHappened: true });

						// Mark as shown
						stateData.migrationNoticeShown = true;
						// Write state.json directly without tag resolution since it's not a tagged file
						if (statePath) {
							fs.writeFileSync(statePath, JSON.stringify(stateData, null, 2));
						}
					}
				}
			}
		} catch (error) {
			// Silently ignore errors checking for migration notice
		}
	} catch (error) {
		// ** Specific catch block for missing configuration file **
		if (error instanceof ConfigurationError) {
			console.error(
				boxen(
					chalk.red.bold('Configuration Update Required!') +
						'\n\n' +
						chalk.white('Taskmaster now uses a ') +
						chalk.yellow.bold('configuration file') +
						chalk.white(
							' in your project for AI model choices and settings.\n\n' +
								'This file appears to be '
						) +
						chalk.red.bold('missing') +
						chalk.white('. No worries though.\n\n') +
						chalk.cyan.bold('To create this file, run the interactive setup:') +
						'\n' +
						chalk.green('   task-master models --setup') +
						'\n\n' +
						chalk.white.bold('Key Points:') +
						'\n' +
						chalk.white('*   ') +
						chalk.yellow.bold('Configuration file') +
						chalk.white(
							': Stores your AI model settings (do not manually edit)\n'
						) +
						chalk.white('*   ') +
						chalk.yellow.bold('.env & .mcp.json') +
						chalk.white(': Still used ') +
						chalk.red.bold('only') +
						chalk.white(' for your AI provider API keys.\n\n') +
						chalk.cyan(
							'`task-master models` to check your config & available models\n'
						) +
						chalk.cyan(
							'`task-master models --setup` to adjust the AI models used by Taskmaster'
						),
					{
						padding: 1,
						margin: { top: 1 },
						borderColor: 'red',
						borderStyle: 'round'
					}
				)
			);
		} else {
			// Generic error handling for other errors
			displayError(error);
		}

		process.exit(1);
	}
}

/**
 * Resolve the final complexity-report path.
 * Rules:
 *  1. If caller passes --output, always respect it.
 *  2. If no explicit output AND tag === 'master' → default report file
 *  3. If no explicit output AND tag !== 'master' → append _<tag>.json
 *
 * @param {string|undefined} outputOpt  --output value from CLI (may be undefined)
 * @param {string} targetTag            resolved tag (defaults to 'master')
 * @param {string} projectRoot          absolute project root
 * @returns {string} absolute path for the report
 */
export function resolveComplexityReportPath({
	projectRoot,
	tag = 'master',
	output // may be undefined
}) {
	// 1. user knows best
	if (output) {
		return path.isAbsolute(output) ? output : path.join(projectRoot, output);
	}

	// 2. default naming
	const base = path.join(projectRoot, COMPLEXITY_REPORT_FILE);
	return tag !== 'master' ? base.replace('.json', `_${tag}.json`) : base;
}

export { registerCommands, setupCLI, runCLI, launchREPL };


--- scripts/modules/config-manager.js ---
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import {
	ALL_PROVIDERS,
	AuthManager,
	CUSTOM_PROVIDERS,
	CUSTOM_PROVIDERS_ARRAY,
	VALIDATED_PROVIDERS
} from '@tm/core';
import chalk from 'chalk';
import { z } from 'zod';
import { AI_COMMAND_NAMES } from '../../src/constants/commands.js';
import {
	LEGACY_CONFIG_FILE,
	TASKMASTER_DIR
} from '../../src/constants/paths.js';
import { findConfigPath } from '../../src/utils/path-utils.js';
import MODEL_MAP from './supported-models.json' with { type: 'json' };
import { findProjectRoot, isEmpty, log, resolveEnvVariable } from './utils.js';

// Calculate __dirname in ESM
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Default configuration values (used if config file is missing or incomplete)
const DEFAULTS = {
	models: {
		main: {
			provider: 'anthropic',
			modelId: 'claude-sonnet-4-20250514',
			maxTokens: 64000,
			temperature: 0.2
		},
		research: {
			provider: 'perplexity',
			modelId: 'sonar',
			maxTokens: 8700,
			temperature: 0.1
		},
		fallback: {
			// No default fallback provider/model initially
			provider: 'anthropic',
			modelId: 'claude-3-7-sonnet-20250219',
			maxTokens: 120000, // Default parameters if fallback IS configured
			temperature: 0.2
		}
	},
	global: {
		logLevel: 'info',
		debug: false,
		defaultNumTasks: 10,
		defaultSubtasks: 5,
		defaultPriority: 'medium',
		projectName: 'Task Master',
		ollamaBaseURL: 'http://localhost:11434/api',
		bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
		responseLanguage: 'English',
		enableCodebaseAnalysis: true,
		enableProxy: false,
		anonymousTelemetry: true // Allow users to opt out of Sentry telemetry for local storage
	},
	claudeCode: {},
	codexCli: {},
	grokCli: {
		timeout: 120000,
		workingDirectory: null,
		defaultModel: 'grok-4-latest'
	}
};

// --- Internal Config Loading ---
let loadedConfig = null;
let loadedConfigRoot = null; // Track which root loaded the config

/**
 * Suppress config file warnings (useful during API mode detection)
 * Uses global object so it can be shared across modules without circular deps
 * @param {boolean} suppress - Whether to suppress warnings
 */
export function setSuppressConfigWarnings(suppress) {
	global._tmSuppressConfigWarnings = suppress;
}

/**
 * Check if config warnings are currently suppressed
 * @returns {boolean}
 */
export function isConfigWarningSuppressed() {
	return global._tmSuppressConfigWarnings === true;
}

// Custom Error for configuration issues
class ConfigurationError extends Error {
	constructor(message) {
		super(message);
		this.name = 'ConfigurationError';
	}
}

function _loadAndValidateConfig(explicitRoot = null, options = {}) {
	const defaults = DEFAULTS; // Use the defined defaults
	let rootToUse = explicitRoot;
	const { storageType } = options;
	let configSource = explicitRoot
		? `explicit root (${explicitRoot})`
		: 'defaults (no root provided yet)';

	// ---> If no explicit root, TRY to find it <---
	if (!rootToUse) {
		rootToUse = findProjectRoot();
		if (rootToUse) {
			configSource = `found root (${rootToUse})`;
		} else {
			// No root found, use current working directory as fallback
			// This prevents infinite loops during initialization
			rootToUse = process.cwd();
			configSource = `current directory (${rootToUse}) - no project markers found`;
		}
	}
	// ---> End find project root logic <---

	// --- Find configuration file ---
	let configPath = null;
	let config = { ...defaults }; // Start with a deep copy of defaults
	let configExists = false;

	// During initialization (no project markers), skip config file search entirely
	const hasProjectMarkers =
		fs.existsSync(path.join(rootToUse, TASKMASTER_DIR)) ||
		fs.existsSync(path.join(rootToUse, LEGACY_CONFIG_FILE));

	if (hasProjectMarkers) {
		// Only try to find config if we have project markers
		// This prevents the repeated warnings during init
		configPath = findConfigPath(null, { projectRoot: rootToUse, storageType });
	}

	if (configPath) {
		configExists = true;
		const isLegacy = configPath.endsWith(LEGACY_CONFIG_FILE);

		try {
			const rawData = fs.readFileSync(configPath, 'utf-8');
			const parsedConfig = JSON.parse(rawData);

			// Deep merge parsed config onto defaults
			config = {
				models: {
					main: { ...defaults.models.main, ...parsedConfig?.models?.main },
					research: {
						...defaults.models.research,
						...parsedConfig?.models?.research
					},
					fallback:
						parsedConfig?.models?.fallback?.provider &&
						parsedConfig?.models?.fallback?.modelId
							? { ...defaults.models.fallback, ...parsedConfig.models.fallback }
							: { ...defaults.models.fallback }
				},
				global: { ...defaults.global, ...parsedConfig?.global },
				claudeCode: { ...defaults.claudeCode, ...parsedConfig?.claudeCode },
				codexCli: { ...defaults.codexCli, ...parsedConfig?.codexCli },
				grokCli: { ...defaults.grokCli, ...parsedConfig?.grokCli }
			};
			configSource = `file (${configPath})`; // Update source info

			// Issue deprecation warning if using legacy config file
			if (isLegacy) {
				console.warn(
					chalk.yellow(
						`⚠️  DEPRECATION WARNING: Found configuration in legacy location '${configPath}'. Please migrate to .taskmaster/config.json. Run 'task-master migrate' to automatically migrate your project.`
					)
				);
			}

			// --- Validation (Warn if file content is invalid) ---
			// Use log.warn for consistency
			if (!validateProvider(config.models.main.provider)) {
				console.warn(
					chalk.yellow(
						`Warning: Invalid main provider "${config.models.main.provider}" in ${configPath}. Falling back to default.`
					)
				);
				config.models.main = { ...defaults.models.main };
			}
			if (!validateProvider(config.models.research.provider)) {
				console.warn(
					chalk.yellow(
						`Warning: Invalid research provider "${config.models.research.provider}" in ${configPath}. Falling back to default.`
					)
				);
				config.models.research = { ...defaults.models.research };
			}
			if (
				config.models.fallback?.provider &&
				!validateProvider(config.models.fallback.provider)
			) {
				console.warn(
					chalk.yellow(
						`Warning: Invalid fallback provider "${config.models.fallback.provider}" in ${configPath}. Fallback model configuration will be ignored.`
					)
				);
				config.models.fallback.provider = undefined;
				config.models.fallback.modelId = undefined;
			}
			if (config.claudeCode && !isEmpty(config.claudeCode)) {
				config.claudeCode = validateClaudeCodeSettings(config.claudeCode);
			}
			if (config.codexCli && !isEmpty(config.codexCli)) {
				config.codexCli = validateCodexCliSettings(config.codexCli);
			}
		} catch (error) {
			// Use console.error for actual errors during parsing
			console.error(
				chalk.red(
					`Error reading or parsing ${configPath}: ${error.message}. Using default configuration.`
				)
			);
			config = { ...defaults }; // Reset to defaults on parse error
			configSource = `defaults (parse error at ${configPath})`;
		}
	} else {
		// Config file doesn't exist at the determined rootToUse.
		// Skip warnings if:
		// 1. Global suppress flag is set (during API mode detection)
		// 2. storageType is explicitly 'api' (remote storage mode - no local config expected)
		const shouldWarn = !isConfigWarningSuppressed() && storageType !== 'api';

		if (shouldWarn) {
			if (explicitRoot) {
				// Warn about explicit root not having config
				console.warn(
					chalk.yellow(
						`Warning: Configuration file not found at provided project root (${explicitRoot}). Using default configuration. Run 'task-master models --setup' to configure.`
					)
				);
			} else {
				// Don't warn about missing config during initialization
				// Only warn if this looks like an existing project (has .taskmaster dir or legacy config marker)
				const hasTaskmasterDir = fs.existsSync(
					path.join(rootToUse, TASKMASTER_DIR)
				);
				const hasLegacyMarker = fs.existsSync(
					path.join(rootToUse, LEGACY_CONFIG_FILE)
				);

				if (hasTaskmasterDir || hasLegacyMarker) {
					console.warn(
						chalk.yellow(
							`Warning: Configuration file not found at derived root (${rootToUse}). Using defaults.`
						)
					);
				}
			}
		}
		// Keep config as defaults
		config = { ...defaults };
		configSource = `defaults (no config file found at ${rootToUse})`;
	}

	return config;
}

/**
 * Gets the current configuration, loading it if necessary.
 * Handles MCP initialization context gracefully.
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @param {boolean} forceReload - Force reloading the config file.
 * @param {object} options - Optional configuration options.
 * @param {'api'|'file'|'auto'} [options.storageType] - Storage type to suppress warnings for API mode.
 * @returns {object} The loaded configuration object.
 */
function getConfig(explicitRoot = null, forceReload = false, options = {}) {
	// Determine if a reload is necessary
	const needsLoad =
		!loadedConfig ||
		forceReload ||
		(explicitRoot && explicitRoot !== loadedConfigRoot);

	if (needsLoad) {
		const newConfig = _loadAndValidateConfig(explicitRoot, options); // _load handles null explicitRoot

		// Only update the global cache if loading was forced or if an explicit root
		// was provided (meaning we attempted to load a specific project's config).
		// We avoid caching the initial default load triggered without an explicitRoot.
		if (forceReload || explicitRoot) {
			loadedConfig = newConfig;
			loadedConfigRoot = explicitRoot; // Store the root used for this loaded config
		}
		return newConfig; // Return the newly loaded/default config
	}

	// If no load was needed, return the cached config
	return loadedConfig;
}

/**
 * Validates if a provider name is supported.
 * Custom providers (azure, vertex, bedrock, openrouter, ollama) are always allowed.
 * Validated providers must exist in the MODEL_MAP from supported-models.json.
 * @param {string} providerName The name of the provider.
 * @returns {boolean} True if the provider is valid, false otherwise.
 */
function validateProvider(providerName) {
	// Custom providers are always allowed
	if (CUSTOM_PROVIDERS_ARRAY.includes(providerName)) {
		return true;
	}

	// Validated providers must exist in MODEL_MAP
	if (VALIDATED_PROVIDERS.includes(providerName)) {
		return !!(MODEL_MAP && MODEL_MAP[providerName]);
	}

	// Unknown providers are not allowed
	return false;
}

/**
 * Optional: Validates if a modelId is known for a given provider based on MODEL_MAP.
 * This is a non-strict validation; an unknown model might still be valid.
 * @param {string} providerName The name of the provider.
 * @param {string} modelId The model ID.
 * @returns {boolean} True if the modelId is in the map for the provider, false otherwise.
 */
function validateProviderModelCombination(providerName, modelId) {
	// If provider isn't even in our map, we can't validate the model
	if (!MODEL_MAP[providerName]) {
		return true; // Allow unknown providers or those without specific model lists
	}
	// If the provider is known, check if the model is in its list OR if the list is empty (meaning accept any)
	return (
		MODEL_MAP[providerName].length === 0 ||
		// Use .some() to check the 'id' property of objects in the array
		MODEL_MAP[providerName].some((modelObj) => modelObj.id === modelId)
	);
}

/**
 * Gets the list of supported model IDs for a given provider from supported-models.json
 * @param {string} providerName - The name of the provider (e.g., 'claude-code', 'anthropic')
 * @returns {string[]} Array of supported model IDs, or empty array if provider not found
 */
export function getSupportedModelsForProvider(providerName) {
	if (!MODEL_MAP[providerName]) {
		return [];
	}
	return MODEL_MAP[providerName]
		.filter((model) => model.supported !== false)
		.map((model) => model.id);
}

/**
 * Validates Claude Code AI provider custom settings
 * @param {object} settings The settings to validate
 * @returns {object} The validated settings
 */
function validateClaudeCodeSettings(settings) {
	// Define the base settings schema without commandSpecific first
	const BaseSettingsSchema = z.object({
		pathToClaudeCodeExecutable: z.string().optional(),
		// Use number().int() for integer validation in Zod
		maxTurns: z.number().int().positive().optional(),
		customSystemPrompt: z.string().optional(),
		appendSystemPrompt: z.string().optional(),
		permissionMode: z
			.enum(['default', 'acceptEdits', 'plan', 'bypassPermissions'])
			.optional(),
		allowedTools: z.array(z.string()).optional(),
		disallowedTools: z.array(z.string()).optional(),
		mcpServers: z
			.record(
				z.string(),
				z.object({
					type: z.enum(['stdio', 'sse']).optional(),
					command: z.string(),
					args: z.array(z.string()).optional(),
					env: z.record(z.string(), z.string()).optional(),
					url: z.url().optional(),
					headers: z.record(z.string(), z.string()).optional()
				})
			)
			.optional()
	});

	// Define CommandSpecificSchema using flexible keys, but restrict to known commands
	const CommandSpecificSchema = z
		.record(z.string(), BaseSettingsSchema)
		.refine(
			(obj) =>
				Object.keys(obj || {}).every((k) => AI_COMMAND_NAMES.includes(k)),
			{ message: 'Invalid command name in commandSpecific' }
		);

	// Define the full settings schema with commandSpecific
	const SettingsSchema = BaseSettingsSchema.extend({
		commandSpecific: CommandSpecificSchema.optional()
	});

	let validatedSettings = {};

	try {
		validatedSettings = SettingsSchema.parse(settings);
	} catch (error) {
		console.warn(
			chalk.yellow(
				`Warning: Invalid Claude Code settings in config: ${error.message}. Falling back to default.`
			)
		);

		validatedSettings = {};
	}

	return validatedSettings;
}

/**
 * Validates Codex CLI provider custom settings
 * Mirrors the ai-sdk-provider-codex-cli options
 * @param {object} settings The settings to validate
 * @returns {object} The validated settings
 */
function validateCodexCliSettings(settings) {
	const BaseSettingsSchema = z.object({
		codexPath: z.string().optional(),
		cwd: z.string().optional(),
		approvalMode: z
			.enum(['untrusted', 'on-failure', 'on-request', 'never'])
			.optional(),
		sandboxMode: z
			.enum(['read-only', 'workspace-write', 'danger-full-access'])
			.optional(),
		fullAuto: z.boolean().optional(),
		dangerouslyBypassApprovalsAndSandbox: z.boolean().optional(),
		skipGitRepoCheck: z.boolean().optional(),
		color: z.enum(['always', 'never', 'auto']).optional(),
		allowNpx: z.boolean().optional(),
		outputLastMessageFile: z.string().optional(),
		env: z.record(z.string(), z.string()).optional(),
		verbose: z.boolean().optional(),
		logger: z.union([z.object({}).passthrough(), z.literal(false)]).optional(),
		reasoningEffort: z
			.enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh'])
			.optional()
	});

	const CommandSpecificSchema = z
		.record(z.string(), BaseSettingsSchema)
		.refine(
			(obj) =>
				Object.keys(obj || {}).every((k) => AI_COMMAND_NAMES.includes(k)),
			{ message: 'Invalid command name in commandSpecific' }
		);

	const SettingsSchema = BaseSettingsSchema.extend({
		commandSpecific: CommandSpecificSchema.optional()
	});

	try {
		return SettingsSchema.parse(settings);
	} catch (error) {
		console.warn(
			chalk.yellow(
				`Warning: Invalid Codex CLI settings in config: ${error.message}. Falling back to default.`
			)
		);
		return {};
	}
}

// --- Claude Code Settings Getters ---

function getClaudeCodeSettings(explicitRoot = null, forceReload = false) {
	const config = getConfig(explicitRoot, forceReload);
	// Ensure Claude Code defaults are applied if Claude Code section is missing
	return { ...DEFAULTS.claudeCode, ...(config?.claudeCode || {}) };
}

// --- Codex CLI Settings Getters ---

function getCodexCliSettings(explicitRoot = null, forceReload = false) {
	const config = getConfig(explicitRoot, forceReload);
	return { ...DEFAULTS.codexCli, ...(config?.codexCli || {}) };
}

function getCodexCliSettingsForCommand(
	commandName,
	explicitRoot = null,
	forceReload = false
) {
	const settings = getCodexCliSettings(explicitRoot, forceReload);
	const commandSpecific = settings?.commandSpecific || {};
	return { ...settings, ...commandSpecific[commandName] };
}

function getClaudeCodeSettingsForCommand(
	commandName,
	explicitRoot = null,
	forceReload = false
) {
	const settings = getClaudeCodeSettings(explicitRoot, forceReload);
	const commandSpecific = settings?.commandSpecific || {};
	return { ...settings, ...commandSpecific[commandName] };
}

function getGrokCliSettings(explicitRoot = null, forceReload = false) {
	const config = getConfig(explicitRoot, forceReload);
	// Ensure Grok CLI defaults are applied if Grok CLI section is missing
	return { ...DEFAULTS.grokCli, ...(config?.grokCli || {}) };
}

function getGrokCliSettingsForCommand(
	commandName,
	explicitRoot = null,
	forceReload = false
) {
	const settings = getGrokCliSettings(explicitRoot, forceReload);
	const commandSpecific = settings?.commandSpecific || {};
	return { ...settings, ...commandSpecific[commandName] };
}

// --- Role-Specific Getters ---

function getModelConfigForRole(role, explicitRoot = null) {
	const config = getConfig(explicitRoot);
	const roleConfig = config?.models?.[role];
	if (!roleConfig) {
		log(
			'warn',
			`No model configuration found for role: ${role}. Returning default.`
		);
		return DEFAULTS.models[role] || {};
	}
	return roleConfig;
}

function getMainProvider(explicitRoot = null) {
	return getModelConfigForRole('main', explicitRoot).provider;
}

function getMainModelId(explicitRoot = null) {
	return getModelConfigForRole('main', explicitRoot).modelId;
}

function getMainMaxTokens(explicitRoot = null) {
	// Directly return value from config (which includes defaults)
	return getModelConfigForRole('main', explicitRoot).maxTokens;
}

function getMainTemperature(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('main', explicitRoot).temperature;
}

function getResearchProvider(explicitRoot = null) {
	return getModelConfigForRole('research', explicitRoot).provider;
}

/**
 * Check if codebase analysis feature flag is enabled across all sources
 * Priority: .env > MCP env > config.json
 * @param {object|null} session - MCP session object (optional)
 * @param {string|null} projectRoot - Project root path (optional)
 * @returns {boolean} True if codebase analysis is enabled
 */
function isCodebaseAnalysisEnabled(session = null, projectRoot = null) {
	// Priority 1: Environment variable
	const envFlag = resolveEnvVariable(
		'TASKMASTER_ENABLE_CODEBASE_ANALYSIS',
		session,
		projectRoot
	);
	if (envFlag !== null && envFlag !== undefined && envFlag !== '') {
		return envFlag.toLowerCase() === 'true' || envFlag === '1';
	}

	// Priority 2: MCP session environment
	if (session?.env?.TASKMASTER_ENABLE_CODEBASE_ANALYSIS) {
		const mcpFlag = session.env.TASKMASTER_ENABLE_CODEBASE_ANALYSIS;
		return mcpFlag.toLowerCase() === 'true' || mcpFlag === '1';
	}

	// Priority 3: Configuration file
	const globalConfig = getGlobalConfig(projectRoot);
	return globalConfig.enableCodebaseAnalysis !== false; // Default to true
}

/**
 * Check if codebase analysis is available and enabled
 * @param {boolean} useResearch - Whether to check research provider or main provider
 * @param {string|null} projectRoot - Project root path (optional)
 * @param {object|null} session - MCP session object (optional)
 * @returns {boolean} True if codebase analysis is available and enabled
 */
function hasCodebaseAnalysis(
	useResearch = false,
	projectRoot = null,
	session = null
) {
	// First check if the feature is enabled
	if (!isCodebaseAnalysisEnabled(session, projectRoot)) {
		return false;
	}

	// Then check if a codebase analysis provider is configured
	const currentProvider = useResearch
		? getResearchProvider(projectRoot)
		: getMainProvider(projectRoot);

	return (
		currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE ||
		currentProvider === CUSTOM_PROVIDERS.GEMINI_CLI ||
		currentProvider === CUSTOM_PROVIDERS.GROK_CLI ||
		currentProvider === CUSTOM_PROVIDERS.CODEX_CLI
	);
}

function getResearchModelId(explicitRoot = null) {
	return getModelConfigForRole('research', explicitRoot).modelId;
}

function getResearchMaxTokens(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('research', explicitRoot).maxTokens;
}

function getResearchTemperature(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('research', explicitRoot).temperature;
}

function getFallbackProvider(explicitRoot = null) {
	// Directly return value from config (will be undefined if not set)
	return getModelConfigForRole('fallback', explicitRoot).provider;
}

function getFallbackModelId(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('fallback', explicitRoot).modelId;
}

function getFallbackMaxTokens(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('fallback', explicitRoot).maxTokens;
}

function getFallbackTemperature(explicitRoot = null) {
	// Directly return value from config
	return getModelConfigForRole('fallback', explicitRoot).temperature;
}

// --- Global Settings Getters ---

function getGlobalConfig(explicitRoot = null) {
	const config = getConfig(explicitRoot);
	// Ensure global defaults are applied if global section is missing
	return { ...DEFAULTS.global, ...(config?.global || {}) };
}

function getLogLevel(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).logLevel.toLowerCase();
}

function getDebugFlag(explicitRoot = null) {
	// Directly return value from config, ensure boolean
	return getGlobalConfig(explicitRoot).debug === true;
}

function getDefaultSubtasks(explicitRoot = null) {
	// Directly return value from config, ensure integer
	const val = getGlobalConfig(explicitRoot).defaultSubtasks;
	const parsedVal = parseInt(val, 10);
	return Number.isNaN(parsedVal) ? DEFAULTS.global.defaultSubtasks : parsedVal;
}

function getDefaultNumTasks(explicitRoot = null) {
	const val = getGlobalConfig(explicitRoot).defaultNumTasks;
	const parsedVal = parseInt(val, 10);
	return Number.isNaN(parsedVal) ? DEFAULTS.global.defaultNumTasks : parsedVal;
}

function getDefaultPriority(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).defaultPriority;
}

function getProjectName(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).projectName;
}

function getOllamaBaseURL(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).ollamaBaseURL;
}

function getAzureBaseURL(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).azureBaseURL;
}

function getBedrockBaseURL(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).bedrockBaseURL;
}

/**
 * Gets the Google Cloud project ID for Vertex AI from configuration
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @returns {string|null} The project ID or null if not configured
 */
function getVertexProjectId(explicitRoot = null) {
	// Return value from config
	return getGlobalConfig(explicitRoot).vertexProjectId;
}

/**
 * Gets the Google Cloud location for Vertex AI from configuration
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @returns {string} The location
 */
function getVertexLocation(explicitRoot = null) {
	// Return value from config or default
	return getGlobalConfig(explicitRoot).vertexLocation;
}

function getResponseLanguage(explicitRoot = null) {
	// Directly return value from config
	return getGlobalConfig(explicitRoot).responseLanguage;
}

function getCodebaseAnalysisEnabled(explicitRoot = null) {
	// Return boolean-safe value with default true
	return getGlobalConfig(explicitRoot).enableCodebaseAnalysis !== false;
}

function getProxyEnabled(explicitRoot = null) {
	// Return boolean-safe value with default false
	return getGlobalConfig(explicitRoot).enableProxy === true;
}

function getAnonymousTelemetryEnabled(explicitRoot = null) {
	// Return boolean-safe value with default true (opt-in by default)
	const config = getGlobalConfig(explicitRoot);
	return config.anonymousTelemetry !== false; // Default true if undefined
}

function isProxyEnabled(session = null, projectRoot = null) {
	// Priority 1: Environment variable
	const envFlag = resolveEnvVariable(
		'TASKMASTER_ENABLE_PROXY',
		session,
		projectRoot
	);
	if (envFlag !== null && envFlag !== undefined && envFlag !== '') {
		return envFlag.toLowerCase() === 'true' || envFlag === '1';
	}

	// Priority 2: MCP session environment (explicit check for parity with other flags)
	if (session?.env?.TASKMASTER_ENABLE_PROXY) {
		const mcpFlag = session.env.TASKMASTER_ENABLE_PROXY;
		return mcpFlag.toLowerCase() === 'true' || mcpFlag === '1';
	}

	// Priority 3: Configuration file
	return getProxyEnabled(projectRoot);
}

/**
 * Gets model parameters (maxTokens, temperature) for a specific role,
 * considering model-specific overrides from supported-models.json.
 * @param {string} role - The role ('main', 'research', 'fallback').
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @returns {{maxTokens: number, temperature: number}}
 */
function getParametersForRole(role, explicitRoot = null) {
	const roleConfig = getModelConfigForRole(role, explicitRoot);
	const roleMaxTokens = roleConfig.maxTokens;
	const roleTemperature = roleConfig.temperature;
	const modelId = roleConfig.modelId;
	const providerName = roleConfig.provider;

	let effectiveMaxTokens = roleMaxTokens; // Start with the role's default
	let effectiveTemperature = roleTemperature; // Start with the role's default

	try {
		// Find the model definition in MODEL_MAP
		const providerModels = MODEL_MAP[providerName];
		if (providerModels && Array.isArray(providerModels)) {
			const modelDefinition = providerModels.find((m) => m.id === modelId);

			// Check if a model-specific max_tokens is defined and valid
			if (
				modelDefinition &&
				typeof modelDefinition.max_tokens === 'number' &&
				modelDefinition.max_tokens > 0
			) {
				const modelSpecificMaxTokens = modelDefinition.max_tokens;
				// Use the minimum of the role default and the model specific limit
				effectiveMaxTokens = Math.min(roleMaxTokens, modelSpecificMaxTokens);
				log(
					'debug',
					`Applying model-specific max_tokens (${modelSpecificMaxTokens}) for ${modelId}. Effective limit: ${effectiveMaxTokens}`
				);
			} else {
				log(
					'debug',
					`No valid model-specific max_tokens override found for ${modelId}. Using role default: ${roleMaxTokens}`
				);
			}

			// Check if a model-specific temperature is defined
			if (
				modelDefinition &&
				typeof modelDefinition.temperature === 'number' &&
				modelDefinition.temperature >= 0 &&
				modelDefinition.temperature <= 1
			) {
				effectiveTemperature = modelDefinition.temperature;
				log(
					'debug',
					`Applying model-specific temperature (${modelDefinition.temperature}) for ${modelId}`
				);
			}
		} else {
			// Special handling for custom OpenRouter models
			if (providerName === CUSTOM_PROVIDERS.OPENROUTER) {
				// Use a conservative default for OpenRouter models not in our list
				const openrouterDefault = 32768;
				effectiveMaxTokens = Math.min(roleMaxTokens, openrouterDefault);
				log(
					'debug',
					`Custom OpenRouter model ${modelId} detected. Using conservative max_tokens: ${effectiveMaxTokens}`
				);
			} else {
				log(
					'debug',
					`No model definitions found for provider ${providerName} in MODEL_MAP. Using role default maxTokens: ${roleMaxTokens}`
				);
			}
		}
	} catch (lookupError) {
		log(
			'warn',
			`Error looking up model-specific parameters for ${modelId}: ${lookupError.message}. Using role defaults.`
		);
		// Fallback to role defaults on error
		effectiveMaxTokens = roleMaxTokens;
		effectiveTemperature = roleTemperature;
	}

	return {
		maxTokens: effectiveMaxTokens,
		temperature: effectiveTemperature
	};
}

/**
 * Checks if the API key for a given provider is set in the environment.
 * Checks process.env first, then session.env if session is provided, then .env file if projectRoot provided.
 * @param {string} providerName - The name of the provider (e.g., 'openai', 'anthropic').
 * @param {object|null} [session=null] - The MCP session object (optional).
 * @param {string|null} [projectRoot=null] - The project root directory (optional, for .env file check).
 * @returns {boolean} True if the API key is set, false otherwise.
 */
function isApiKeySet(providerName, session = null, projectRoot = null) {
	// Define the expected environment variable name for each provider

	// Providers that don't require API keys for authentication
	const providersWithoutApiKeys = [
		CUSTOM_PROVIDERS.OLLAMA,
		CUSTOM_PROVIDERS.BEDROCK,
		CUSTOM_PROVIDERS.GEMINI_CLI,
		CUSTOM_PROVIDERS.GROK_CLI,
		CUSTOM_PROVIDERS.MCP,
		CUSTOM_PROVIDERS.CODEX_CLI
	];

	if (providersWithoutApiKeys.includes(providerName?.toLowerCase())) {
		return true; // Indicate key status is effectively "OK"
	}

	// Claude Code doesn't require an API key
	if (providerName?.toLowerCase() === 'claude-code') {
		return true; // No API key needed
	}

	// Codex CLI supports OAuth via codex login; API key optional
	if (providerName?.toLowerCase() === 'codex-cli') {
		return true; // Treat as OK even without key
	}

	const keyMap = {
		openai: 'OPENAI_API_KEY',
		anthropic: 'ANTHROPIC_API_KEY',
		google: 'GOOGLE_API_KEY',
		perplexity: 'PERPLEXITY_API_KEY',
		mistral: 'MISTRAL_API_KEY',
		azure: 'AZURE_OPENAI_API_KEY',
		openrouter: 'OPENROUTER_API_KEY',
		xai: 'XAI_API_KEY',
		zai: 'ZAI_API_KEY',
		'zai-coding': 'ZAI_API_KEY',
		groq: 'GROQ_API_KEY',
		vertex: 'GOOGLE_API_KEY', // Vertex uses the same key as Google
		'claude-code': 'CLAUDE_CODE_API_KEY', // Not actually used, but included for consistency
		bedrock: 'AWS_ACCESS_KEY_ID' // Bedrock uses AWS credentials
		// Add other providers as needed
	};

	const providerKey = providerName?.toLowerCase();
	if (!providerKey || !keyMap[providerKey]) {
		log('warn', `Unknown provider name: ${providerName} in isApiKeySet check.`);
		return false;
	}

	const envVarName = keyMap[providerKey];
	const apiKeyValue = resolveEnvVariable(envVarName, session, projectRoot);

	// Check if the key exists, is not empty, and is not a placeholder
	return (
		apiKeyValue &&
		apiKeyValue.trim() !== '' &&
		!/YOUR_.*_API_KEY_HERE/.test(apiKeyValue) && // General placeholder check
		!apiKeyValue.includes('KEY_HERE')
	); // Another common placeholder pattern
}

/**
 * Checks the API key status within .cursor/mcp.json for a given provider.
 * Reads the mcp.json file, finds the taskmaster-ai server config, and checks the relevant env var.
 * @param {string} providerName The name of the provider.
 * @param {string|null} projectRoot - Optional explicit path to the project root.
 * @returns {boolean} True if the key exists and is not a placeholder, false otherwise.
 */
function getMcpApiKeyStatus(providerName, projectRoot = null) {
	const rootDir = projectRoot || findProjectRoot(); // Use existing root finding
	if (!rootDir) {
		console.warn(
			chalk.yellow('Warning: Could not find project root to check mcp.json.')
		);
		return false; // Cannot check without root
	}
	const mcpConfigPath = path.join(rootDir, '.cursor', 'mcp.json');

	if (!fs.existsSync(mcpConfigPath)) {
		// console.warn(chalk.yellow('Warning: .cursor/mcp.json not found.'));
		return false; // File doesn't exist
	}

	try {
		const mcpConfigRaw = fs.readFileSync(mcpConfigPath, 'utf-8');
		const mcpConfig = JSON.parse(mcpConfigRaw);

		const mcpEnv =
			mcpConfig?.mcpServers?.['task-master-ai']?.env ||
			mcpConfig?.mcpServers?.['taskmaster-ai']?.env;
		if (!mcpEnv) {
			return false;
		}

		let apiKeyToCheck = null;
		let placeholderValue = null;

		switch (providerName) {
			case 'anthropic':
				apiKeyToCheck = mcpEnv.ANTHROPIC_API_KEY;
				placeholderValue = 'YOUR_ANTHROPIC_API_KEY_HERE';
				break;
			case 'openai':
				apiKeyToCheck = mcpEnv.OPENAI_API_KEY;
				placeholderValue = 'YOUR_OPENAI_API_KEY_HERE'; // Assuming placeholder matches OPENAI
				break;
			case 'openrouter':
				apiKeyToCheck = mcpEnv.OPENROUTER_API_KEY;
				placeholderValue = 'YOUR_OPENROUTER_API_KEY_HERE';
				break;
			case 'google':
				apiKeyToCheck = mcpEnv.GOOGLE_API_KEY;
				placeholderValue = 'YOUR_GOOGLE_API_KEY_HERE';
				break;
			case 'perplexity':
				apiKeyToCheck = mcpEnv.PERPLEXITY_API_KEY;
				placeholderValue = 'YOUR_PERPLEXITY_API_KEY_HERE';
				break;
			case 'xai':
				apiKeyToCheck = mcpEnv.XAI_API_KEY;
				placeholderValue = 'YOUR_XAI_API_KEY_HERE';
				break;
			case 'zai':
			case 'zai-coding':
				apiKeyToCheck = mcpEnv.ZAI_API_KEY;
				placeholderValue = 'YOUR_ZAI_API_KEY_HERE';
				break;
			case 'groq':
				apiKeyToCheck = mcpEnv.GROQ_API_KEY;
				placeholderValue = 'YOUR_GROQ_API_KEY_HERE';
				break;
			case 'ollama':
				return true; // No key needed
			case 'claude-code':
				return true; // No key needed
			case 'codex-cli':
				return true; // OAuth/subscription via Codex CLI
			case 'mistral':
				apiKeyToCheck = mcpEnv.MISTRAL_API_KEY;
				placeholderValue = 'YOUR_MISTRAL_API_KEY_HERE';
				break;
			case 'azure':
				apiKeyToCheck = mcpEnv.AZURE_OPENAI_API_KEY;
				placeholderValue = 'YOUR_AZURE_OPENAI_API_KEY_HERE';
				break;
			case 'vertex':
				apiKeyToCheck = mcpEnv.GOOGLE_API_KEY; // Vertex uses Google API key
				placeholderValue = 'YOUR_GOOGLE_API_KEY_HERE';
				break;
			case 'bedrock':
				apiKeyToCheck = mcpEnv.AWS_ACCESS_KEY_ID; // Bedrock uses AWS credentials
				placeholderValue = 'YOUR_AWS_ACCESS_KEY_ID_HERE';
				break;
			default:
				return false; // Unknown provider
		}

		return !!apiKeyToCheck && !/KEY_HERE$/.test(apiKeyToCheck);
	} catch (error) {
		console.error(
			chalk.red(`Error reading or parsing .cursor/mcp.json: ${error.message}`)
		);
		return false;
	}
}

/**
 * Gets a list of available models based on the MODEL_MAP.
 * @returns {Array<{id: string, name: string, provider: string, swe_score: number|null, cost_per_1m_tokens: {input: number|null, output: number|null}|null, allowed_roles: string[]}>}
 */
function getAvailableModels() {
	const available = [];
	for (const [provider, models] of Object.entries(MODEL_MAP)) {
		if (models.length > 0) {
			models
				.filter((modelObj) => Boolean(modelObj.supported))
				.forEach((modelObj) => {
					const modelId = modelObj.id;
					const sweScore = modelObj.swe_score;
					const cost = modelObj.cost_per_1m_tokens;
					const allowedRoles = modelObj.allowed_roles || ['main', 'fallback'];

					// Use name from JSON if available, otherwise generate from ID
					let name = modelObj.name;
					if (!name) {
						const nameParts = modelId
							.split('-')
							.map((p) => p.charAt(0).toUpperCase() + p.slice(1));
						name = nameParts.join(' ');
						// Handle specific known names better if needed
						if (modelId === 'claude-3.5-sonnet-20240620')
							name = 'Claude 3.5 Sonnet';
						if (modelId === 'claude-3-7-sonnet-20250219')
							name = 'Claude 3.7 Sonnet';
						if (modelId === 'gpt-4o') name = 'GPT-4o';
						if (modelId === 'gpt-4-turbo') name = 'GPT-4 Turbo';
						if (modelId === 'sonar-pro') name = 'Perplexity Sonar Pro';
						if (modelId === 'sonar-mini') name = 'Perplexity Sonar Mini';
					}

					available.push({
						id: modelId,
						name: name,
						provider: provider,
						swe_score: sweScore,
						cost_per_1m_tokens: cost,
						allowed_roles: allowedRoles,
						max_tokens: modelObj.max_tokens
					});
				});
		} else {
			// For providers with empty lists (like ollama), maybe add a placeholder or skip
			available.push({
				id: `[${provider}-any]`,
				name: `Any (${provider})`,
				provider: provider
			});
		}
	}
	return available;
}

/**
 * Writes the configuration object to the file.
 * @param {Object} config The configuration object to write.
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @returns {boolean} True if successful, false otherwise.
 */
function writeConfig(config, explicitRoot = null) {
	// ---> Determine root path reliably <---
	let rootPath = explicitRoot;
	if (explicitRoot === null || explicitRoot === undefined) {
		// Logic matching _loadAndValidateConfig
		const foundRoot = findProjectRoot(); // *** Explicitly call findProjectRoot ***
		if (!foundRoot) {
			console.error(
				chalk.red(
					'Error: Could not determine project root. Configuration not saved.'
				)
			);
			return false;
		}
		rootPath = foundRoot;
	}
	// ---> End determine root path logic <---

	// Use new config location: .taskmaster/config.json
	const taskmasterDir = path.join(rootPath, '.taskmaster');
	const configPath = path.join(taskmasterDir, 'config.json');

	try {
		// Ensure .taskmaster directory exists
		if (!fs.existsSync(taskmasterDir)) {
			fs.mkdirSync(taskmasterDir, { recursive: true });
		}

		fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
		loadedConfig = config; // Update the cache after successful write
		return true;
	} catch (error) {
		console.error(
			chalk.red(
				`Error writing configuration to ${configPath}: ${error.message}`
			)
		);
		return false;
	}
}

/**
 * Checks if a configuration file exists at the project root (new or legacy location)
 * @param {string|null} explicitRoot - Optional explicit path to the project root
 * @returns {boolean} True if the file exists, false otherwise
 */
function isConfigFilePresent(explicitRoot = null) {
	return findConfigPath(null, { projectRoot: explicitRoot }) !== null;
}

/**
 * Gets the user ID from the configuration.
 * @param {string|null} explicitRoot - Optional explicit path to the project root.
 * @returns {string|null} The user ID or null if not found.
 */
function getUserId(explicitRoot = null) {
	const config = getConfig(explicitRoot);
	if (!config.global) {
		config.global = {}; // Ensure global object exists
	}
	if (!config.global.userId) {
		config.global.userId = '1234567890';
		// Attempt to write the updated config.
		// It's important that writeConfig correctly resolves the path
		// using explicitRoot, similar to how getConfig does.
		const success = writeConfig(config, explicitRoot);
		if (!success) {
			// Log an error or handle the failure to write,
			// though for now, we'll proceed with the in-memory default.
			log(
				'warning',
				'Failed to write updated configuration with new userId. Please let the developers know.'
			);
		}
	}
	return config.global.userId;
}

/**
 * Gets a list of all known provider names (both validated and custom).
 * @returns {string[]} An array of all provider names.
 */
function getAllProviders() {
	return ALL_PROVIDERS;
}

function getBaseUrlForRole(role, explicitRoot = null) {
	const roleConfig = getModelConfigForRole(role, explicitRoot);
	if (roleConfig && typeof roleConfig.baseURL === 'string') {
		return roleConfig.baseURL;
	}
	const provider = roleConfig?.provider;
	if (provider) {
		const envVarName = `${provider.toUpperCase()}_BASE_URL`;
		return resolveEnvVariable(envVarName, null, explicitRoot);
	}
	return undefined;
}

/**
 * Get the operating mode for rules/commands filtering.
 * Priority order:
 * 1. Explicit CLI flag (--mode=solo|team)
 * 2. Config file (storage.operatingMode)
 * 3. Auth status fallback (authenticated = team, else solo)
 *
 * @param {string|undefined} explicitMode - Mode passed via CLI flag
 * @returns {Promise<'solo'|'team'>} The operating mode
 */
async function getOperatingMode(explicitMode) {
	// 1. CLI flag takes precedence
	if (explicitMode === 'solo' || explicitMode === 'team') {
		return explicitMode;
	}

	// 2. Check config file for operatingMode
	try {
		setSuppressConfigWarnings(true);
		const config = getConfig(null, false, { storageType: 'api' });
		if (config?.storage?.operatingMode) {
			return config.storage.operatingMode;
		}
	} catch {
		// Config check failed, continue to fallback
	} finally {
		setSuppressConfigWarnings(false);
	}

	// 3. Fallback: Check auth status
	// If authenticated with Hamster, assume team mode
	try {
		const authManager = AuthManager.getInstance();
		const credentials = await authManager.getAuthCredentials();
		if (credentials) {
			return 'team';
		}
	} catch {
		// Auth check failed, default to solo
	}

	// Default to solo mode
	return 'solo';
}

// Export the providers without API keys array for use in other modules
export const providersWithoutApiKeys = [
	CUSTOM_PROVIDERS.OLLAMA,
	CUSTOM_PROVIDERS.BEDROCK,
	CUSTOM_PROVIDERS.GEMINI_CLI,
	CUSTOM_PROVIDERS.GROK_CLI,
	CUSTOM_PROVIDERS.MCP,
	CUSTOM_PROVIDERS.CODEX_CLI
];

export {
	// Core config access
	getConfig,
	writeConfig,
	ConfigurationError,
	isConfigFilePresent,
	// Claude Code settings
	getClaudeCodeSettings,
	getClaudeCodeSettingsForCommand,
	// Codex CLI settings
	getCodexCliSettings,
	getCodexCliSettingsForCommand,
	// Grok CLI settings
	getGrokCliSettings,
	getGrokCliSettingsForCommand,
	// Validation
	validateProvider,
	validateProviderModelCombination,
	validateClaudeCodeSettings,
	validateCodexCliSettings,
	VALIDATED_PROVIDERS,
	CUSTOM_PROVIDERS,
	ALL_PROVIDERS,
	MODEL_MAP,
	getAvailableModels,
	// Role-specific getters (No env var overrides)
	getMainProvider,
	getMainModelId,
	getMainMaxTokens,
	getMainTemperature,
	getResearchProvider,
	getResearchModelId,
	getResearchMaxTokens,
	getResearchTemperature,
	hasCodebaseAnalysis,
	getFallbackProvider,
	getFallbackModelId,
	getFallbackMaxTokens,
	getFallbackTemperature,
	getBaseUrlForRole,
	// Global setting getters (No env var overrides)
	getLogLevel,
	getDebugFlag,
	getDefaultNumTasks,
	getDefaultSubtasks,
	getDefaultPriority,
	getProjectName,
	getOllamaBaseURL,
	getAzureBaseURL,
	getBedrockBaseURL,
	getResponseLanguage,
	getCodebaseAnalysisEnabled,
	isCodebaseAnalysisEnabled,
	getProxyEnabled,
	isProxyEnabled,
	getAnonymousTelemetryEnabled,
	getParametersForRole,
	getUserId,
	// Operating mode
	getOperatingMode,
	// API Key Checkers (still relevant)
	isApiKeySet,
	getMcpApiKeyStatus,
	// ADD: Function to get all provider names
	getAllProviders,
	getVertexProjectId,
	getVertexLocation
};


--- scripts/modules/dependency-manager.js ---
/**
 * dependency-manager.js
 * Manages task dependencies and relationships
 */

import path from 'path';
import boxen from 'boxen';
import chalk from 'chalk';

import {
	findCycles,
	formatTaskId,
	isSilentMode,
	log,
	readJSON,
	taskExists,
	traverseDependencies,
	writeJSON
} from './utils.js';

import { displayBanner } from './ui.js';

/**
 * Structured error class for dependency operations
 */
class DependencyError extends Error {
	constructor(code, message, data = {}) {
		super(message);
		this.name = 'DependencyError';
		this.code = code;
		this.data = data;
	}
}

/**
 * Error codes for dependency operations
 */
const DEPENDENCY_ERROR_CODES = {
	CANNOT_MOVE_SUBTASK: 'CANNOT_MOVE_SUBTASK',
	INVALID_TASK_ID: 'INVALID_TASK_ID',
	INVALID_SOURCE_TAG: 'INVALID_SOURCE_TAG',
	INVALID_TARGET_TAG: 'INVALID_TARGET_TAG'
};

/**
 * Add a dependency to a task
 * @param {string} tasksPath - Path to the tasks.json file
 * @param {number|string} taskId - ID of the task to add dependency to
 * @param {number|string} dependencyId - ID of the task to add as dependency
 * @param {Object} context - Context object containing projectRoot and tag information
 * @param {string} [context.projectRoot] - Project root path
 * @param {string} [context.tag] - Tag for the task
 */
async function addDependency(tasksPath, taskId, dependencyId, context = {}) {
	log('info', `Adding dependency ${dependencyId} to task ${taskId}...`);

	const data = readJSON(tasksPath, context.projectRoot, context.tag);
	if (!data || !data.tasks) {
		log('error', 'No valid tasks found in tasks.json');
		process.exit(1);
	}

	// Format the task and dependency IDs correctly
	const formattedTaskId =
		typeof taskId === 'string' && taskId.includes('.')
			? taskId
			: parseInt(taskId, 10);

	const formattedDependencyId = formatTaskId(dependencyId);

	// Check if the dependency task or subtask actually exists
	if (!taskExists(data.tasks, formattedDependencyId)) {
		log(
			'error',
			`Dependency target ${formattedDependencyId} does not exist in tasks.json`
		);
		process.exit(1);
	}

	// Find the task to update
	let targetTask = null;
	let isSubtask = false;

	if (typeof formattedTaskId === 'string' && formattedTaskId.includes('.')) {
		// Handle dot notation for subtasks (e.g., "1.2")
		const [parentId, subtaskId] = formattedTaskId
			.split('.')
			.map((id) => parseInt(id, 10));
		const parentTask = data.tasks.find((t) => t.id === parentId);

		if (!parentTask) {
			log('error', `Parent task ${parentId} not found.`);
			process.exit(1);
		}

		if (!parentTask.subtasks) {
			log('error', `Parent task ${parentId} has no subtasks.`);
			process.exit(1);
		}

		targetTask = parentTask.subtasks.find((s) => s.id === subtaskId);
		isSubtask = true;

		if (!targetTask) {
			log('error', `Subtask ${formattedTaskId} not found.`);
			process.exit(1);
		}
	} else {
		// Regular task (not a subtask)
		targetTask = data.tasks.find((t) => t.id === formattedTaskId);

		if (!targetTask) {
			log('error', `Task ${formattedTaskId} not found.`);
			process.exit(1);
		}
	}

	// Initialize dependencies array if it doesn't exist
	if (!targetTask.dependencies) {
		targetTask.dependencies = [];
	}

	// Check if dependency already exists
	if (
		targetTask.dependencies.some((d) => {
			// Convert both to strings for comparison to handle both numeric and string IDs
			return String(d) === String(formattedDependencyId);
		})
	) {
		log(
			'warn',
			`Dependency ${formattedDependencyId} already exists in task ${formattedTaskId}.`
		);
		return;
	}

	// Check if the task is trying to depend on itself - compare full IDs (including subtask parts)
	if (String(formattedTaskId) === String(formattedDependencyId)) {
		log('error', `Task ${formattedTaskId} cannot depend on itself.`);
		process.exit(1);
	}

	// For subtasks of the same parent, we need to make sure we're not treating it as a self-dependency
	// Check if we're dealing with subtasks with the same parent task
	let isSelfDependency = false;

	if (
		typeof formattedTaskId === 'string' &&
		typeof formattedDependencyId === 'string' &&
		formattedTaskId.includes('.') &&
		formattedDependencyId.includes('.')
	) {
		const [taskParentId] = formattedTaskId.split('.');
		const [depParentId] = formattedDependencyId.split('.');

		// Only treat it as a self-dependency if both the parent ID and subtask ID are identical
		isSelfDependency = formattedTaskId === formattedDependencyId;

		// Log for debugging
		log(
			'debug',
			`Adding dependency between subtasks: ${formattedTaskId} depends on ${formattedDependencyId}`
		);
		log(
			'debug',
			`Parent IDs: ${taskParentId} and ${depParentId}, Self-dependency check: ${isSelfDependency}`
		);
	}

	if (isSelfDependency) {
		log('error', `Subtask ${formattedTaskId} cannot depend on itself.`);
		process.exit(1);
	}

	// Check for circular dependencies
	const dependencyChain = [formattedTaskId];
	if (
		!isCircularDependency(data.tasks, formattedDependencyId, dependencyChain)
	) {
		// Add the dependency
		targetTask.dependencies.push(formattedDependencyId);

		// Sort dependencies numerically or by parent task ID first, then subtask ID
		targetTask.dependencies.sort((a, b) => {
			if (typeof a === 'number' && typeof b === 'number') {
				return a - b;
			} else if (typeof a === 'string' && typeof b === 'string') {
				const [aParent, aChild] = a.split('.').map(Number);
				const [bParent, bChild] = b.split('.').map(Number);
				return aParent !== bParent ? aParent - bParent : aChild - bChild;
			} else if (typeof a === 'number') {
				return -1; // Numbers come before strings
			} else {
				return 1; // Strings come after numbers
			}
		});

		// Save changes
		writeJSON(tasksPath, data, context.projectRoot, context.tag);
		log(
			'success',
			`Added dependency ${formattedDependencyId} to task ${formattedTaskId}`
		);

		// Display a more visually appealing success message
		if (!isSilentMode()) {
			console.log(
				boxen(
					chalk.green(`Successfully added dependency:\n\n`) +
						`Task ${chalk.bold(formattedTaskId)} now depends on ${chalk.bold(formattedDependencyId)}`,
					{
						padding: 1,
						borderColor: 'green',
						borderStyle: 'round',
						margin: { top: 1 }
					}
				)
			);
		}

		// Generate updated task files
		// await generateTaskFiles(tasksPath, path.dirname(tasksPath));

		log('info', 'Task files regenerated with updated dependencies.');
	} else {
		log(
			'error',
			`Cannot add dependency ${formattedDependencyId} to task ${formattedTaskId} as it would create a circular dependency.`
		);
		process.exit(1);
	}
}

/**
 * Remove a dependency from a task
 * @param {string} tasksPath - Path to the tasks.json file
 * @param {number|string} taskId - ID of the task to remove dependency from
 * @param {number|string} dependencyId - ID of the task to remove as dependency
 * @param {Object} context - Context object containing projectRoot and tag information
 * @param {string} [context.projectRoot] - Project root path
 * @param {string} [context.tag] - Tag for the task
 */
async function removeDependency(tasksPath, taskId, dependencyId, context = {}) {
	log('info', `Removing dependency ${dependencyId} from task ${taskId}...`);

	// Read tasks file
	const data = readJSON(tasksPath, context.projectRoot, context.tag);
	if (!data || !data.tasks) {
		log('error', 'No valid tasks found.');
		process.exit(1);
	}

	// Format the task and dependency IDs correctly
	const formattedTaskId =
		typeof taskId === 'string' && taskId.includes('.')
			? taskId
			: parseInt(taskId, 10);

	const formattedDependencyId = formatTaskId(dependencyId);

	// Find the task to update
	let targetTask = null;
	let isSubtask = false;

	if (typeof formattedTaskId === 'string' && formattedTaskId.includes('.')) {
		// Handle dot notation for subtasks (e.g., "1.2")
		const [parentId, subtaskId] = formattedTaskId
			.split('.')
			.map((id) => parseInt(id, 10));
		const parentTask = data.tasks.find((t) => t.id === parentId);

		if (!parentTask) {
			log('error', `Parent task ${parentId} not found.`);
			process.exit(1);
		}

		if (!parentTask.subtasks) {
			log('error', `Parent task ${parentId} has no subtasks.`);
			process.exit(1);
		}

		targetTask = parentTask.subtasks.find((s) => s.id === subtaskId);
		isSubtask = true;

		if (!targetTask) {
			log('error', `Subtask ${formattedTaskId} not found.`);
			process.exit(1);
		}
	} else {
		// Regular task (not a subtask)
		targetTask = data.tasks.find((t) => t.id === formattedTaskId);

		if (!targetTask) {
			log('error', `Task ${formattedTaskId} not found.`);
			process.exit(1);
		}
	}

	// Check if the task has any dependencies
	if (!targetTask.dependencies || targetTask.dependencies.length === 0) {
		log(
			'info',
			`Task ${formattedTaskId} has no dependencies, nothing to remove.`
		);
		return;
	}

	// Normalize the dependency ID for comparison to handle different formats
	const normalizedDependencyId = String(formattedDependencyId);

	// Check if the dependency exists by comparing string representations
	const dependencyIndex = targetTask.dependencies.findIndex((dep) => {
		// Direct string comparison (handles both numeric IDs and dot notation)
		const depStr = String(dep);
		if (depStr === normalizedDependencyId) {
			return true;
		}

		// For subtasks: handle numeric dependencies that might be references to other subtasks
		// in the same parent (e.g., subtask 1.2 depending on subtask 1.1 stored as just "1")
		if (typeof dep === 'number' && dep < 100 && isSubtask) {
			const [parentId] = formattedTaskId.split('.');
			const fullSubtaskRef = `${parentId}.${dep}`;
			if (fullSubtaskRef === normalizedDependencyId) {
				return true;
			}
		}

		return false;
	});

	if (dependencyIndex === -1) {
		log(
			'info',
			`Task ${formattedTaskId} does not depend on ${formattedDependencyId}, no changes made.`
		);
		return;
	}

	// Remove the dependency
	targetTask.dependencies.splice(dependencyIndex, 1);

	// Save the updated tasks
	writeJSON(tasksPath, data, context.projectRoot, context.tag);

	// Success message
	log(
		'success',
		`Removed dependency: Task ${formattedTaskId} no longer depends on ${formattedDependencyId}`
	);

	if (!isSilentMode()) {
		// Display a more visually appealing success message
		console.log(
			boxen(
				chalk.green(`Successfully removed dependency:\n\n`) +
					`Task ${chalk.bold(formattedTaskId)} no longer depends on ${chalk.bold(formattedDependencyId)}`,
				{
					padding: 1,
					borderColor: 'green',
					borderStyle: 'round',
					margin: { top: 1 }
				}
			)
		);
	}

	// Regenerate task files
	// await generateTaskFiles(tasksPath, path.dirname(tasksPath));
}

/**
 * Check if adding a dependency would create a circular dependency
 * @param {Array} tasks - Array of all tasks
 * @param {number|string} taskId - ID of task to check
 * @param {Array} chain - Chain of dependencies to check
 * @returns {boolean} True if circular dependency would be created
 */
function isCircularDependency(tasks, taskId, chain = []) {
	// Convert taskId to string for comparison
	const taskIdStr = String(taskId);

	// If we've seen this task before in the chain, we have a circular dependency
	if (chain.some((id) => String(id) === taskIdStr)) {
		return true;
	}

	// Find the task or subtask
	let task = null;
	let parentIdForSubtask = null;

	// Check if this is a subtask reference (e.g., "1.2")
	if (taskIdStr.includes('.')) {
		const [parentId, subtaskId] = taskIdStr.split('.').map(Number);
		const parentTask = tasks.find((t) => t.id === parentId);
		parentIdForSubtask = parentId; // Store parent ID if it's a subtask

		if (parentTask && parentTask.subtasks) {
			task = parentTask.subtasks.find((st) => st.id === subtaskId);
		}
	} else {
		// Regular task - handle both string and numeric task IDs
		const taskIdNum = parseInt(taskIdStr, 10);
		task = tasks.find((t) => t.id === taskIdNum || String(t.id) === taskIdStr);
	}

	if (!task) {
		return false; // Task doesn't exist, can't create circular dependency
	}

	// No dependencies, can't create circular dependency
	if (!task.dependencies || task.dependencies.length === 0) {
		return false;
	}

	// Check each dependency recursively
	const newChain = [...chain, taskIdStr]; // Use taskIdStr for consistency
	return task.dependencies.some((depId) => {
		let normalizedDepId = String(depId);
		// Normalize relative subtask dependencies
		if (typeof depId === 'number' && parentIdForSubtask !== null) {
			// If the current task is a subtask AND the dependency is a number,
			// assume it refers to a sibling subtask.
			normalizedDepId = `${parentIdForSubtask}.${depId}`;
		}
		// Pass the normalized ID to the recursive call
		return isCircularDependency(tasks, normalizedDepId, newChain);
	});
}

/**
 * Validate task dependencies
 * @param {Array} tasks - Array of all tasks
 * @returns {Object} Validation result with valid flag and issues array
 */
function validateTaskDependencies(tasks) {
	const issues = [];

	// Check each task's dependencies
	tasks.forEach((task) => {
		if (!task.dependencies) {
			return; // No dependencies to validate
		}

		task.dependencies.forEach((depId) => {
			// Check for self-dependencies
			if (String(depId) === String(task.id)) {
				issues.push({
					type: 'self',
					taskId: task.id,
					message: `Task ${task.id} depends on itself`
				});
				return;
			}

			// Check if dependency exists
			if (!taskExists(tasks, depId)) {
				issues.push({
					type: 'missing',
					taskId: task.id,
					dependencyId: depId,
					message: `Task ${task.id} depends on non-existent task ${depId}`
				});
			}
		});

		// Check for circular dependencies
		if (isCircularDependency(tasks, task.id)) {
			issues.push({
				type: 'circular',
				taskId: task.id,
				message: `Task ${task.id} is part of a circular dependency chain`
			});
		}

		// Check subtask dependencies if they exist
		if (task.subtasks && task.subtasks.length > 0) {
			task.subtasks.forEach((subtask) => {
				if (!subtask.dependencies) {
					return; // No dependencies to validate
				}

				// Create a full subtask ID for reference
				const fullSubtaskId = `${task.id}.${subtask.id}`;

				subtask.dependencies.forEach((depId) => {
					// Check for self-dependencies in subtasks
					if (
						String(depId) === String(fullSubtaskId) ||
						(typeof depId === 'number' && depId === subtask.id)
					) {
						issues.push({
							type: 'self',
							taskId: fullSubtaskId,
							message: `Subtask ${fullSubtaskId} depends on itself`
						});
						return;
					}

					// Check if dependency exists
					if (!taskExists(tasks, depId)) {
						issues.push({
							type: 'missing',
							taskId: fullSubtaskId,
							dependencyId: depId,
							message: `Subtask ${fullSubtaskId} depends on non-existent task/subtask ${depId}`
						});
					}
				});

				// Check for circular dependencies in subtasks
				if (isCircularDependency(tasks, fullSubtaskId)) {
					issues.push({
						type: 'circular',
						taskId: fullSubtaskId,
						message: `Subtask ${fullSubtaskId} is part of a circular dependency chain`
					});
				}
			});
		}
	});

	return {
		valid: issues.length === 0,
		issues
	};
}

/**
 * Remove duplicate dependencies from tasks
 * @param {Object} tasksData - Tasks data object with tasks array
 * @returns {Object} Updated tasks data with duplicates removed
 */
function removeDuplicateDependencies(tasksData) {
	const tasks = tasksData.tasks.map((task) => {
		if (!task.dependencies) {
			return task;
		}

		// Convert to Set and back to array to remove duplicates
		const uniqueDeps = [...new Set(task.dependencies)];
		return {
			...task,
			dependencies: uniqueDeps
		};
	});

	return {
		...tasksData,
		tasks
	};
}

/**
 * Clean up invalid subtask dependencies
 * @param {Object} tasksData - Tasks data object with tasks array
 * @returns {Object} Updated tasks data with invalid subtask dependencies removed
 */
function cleanupSubtaskDependencies(tasksData) {
	const tasks = tasksData.tasks.map((task) => {
		// Handle task's own dependencies
		if (task.dependencies) {
			task.dependencies = task.dependencies.filter((depId) => {
				// Keep only dependencies that exist
				return taskExists(tasksData.tasks, depId);
			});
		}

		// Handle subtask dependencies
		if (task.subtasks) {
			task.subtasks = task.subtasks.map((subtask) => {
				if (!subtask.dependencies) {
					return subtask;
				}

				// Filter out dependencies to non-existent subtasks
				subtask.dependencies = subtask.dependencies.filter((depId) => {
					return taskExists(tasksData.tasks, depId);
				});

				return subtask;
			});
		}

		return task;
	});

	return {
		...tasksData,
		tasks
	};
}

/**
 * Validate dependencies in task files
 * @param {string} tasksPath - Path to tasks.json
 * @param {Object} options - Options object, including context
 */
async function validateDependenciesCommand(tasksPath, options = {}) {
	const { context = {} } = options;
	log('info', 'Checking for invalid dependencies in task files...');

	// Read tasks data
	const data = readJSON(tasksPath, context.projectRoot, context.tag);
	if (!data || !data.tasks) {
		log('error', 'No valid tasks found in tasks.json');
		process.exit(1);
	}

	// Count of tasks and subtasks for reporting
	const taskCount = data.tasks.length;
	let subtaskCount = 0;
	data.tasks.forEach((task) => {
		if (task.subtasks && Array.isArray(task.subtasks)) {
			subtaskCount += task.subtasks.length;
		}
	});

	log(
		'info',
		`Analyzing dependencies for ${taskCount} tasks and ${subtaskCount} subtasks...`
	);

	try {
		// Directly call the validation function
		const validationResult = validateTaskDependencies(data.tasks);

		if (!validationResult.valid) {
			log(
				'error',
				`Dependency validation failed. Found ${validationResult.issues.length} issue(s):`
			);
			validationResult.issues.forEach((issue) => {
				let errorMsg = `  [${issue.type.toUpperCase()}] Task ${issue.taskId}: ${issue.message}`;
				if (issue.dependencyId) {
					errorMsg += ` (Dependency: ${issue.dependencyId})`;
				}
				log('error', errorMsg); // Log each issue as an error
			});

			// Optionally exit if validation fails, depending on desired behavior
			// process.exit(1); // Uncomment if validation failure should stop the process

			// Display summary box even on failure, showing issues found
			if (!isSilentMode()) {
				console.log(
					boxen(
						chalk.red(`Dependency Validation FAILED\n\n`) +
							`${chalk.cyan('Tasks checked:')} ${taskCount}\n` +
							`${chalk.cyan('Subtasks checked:')} ${subtaskCount}\n` +
							`${chalk.red('Issues found:')} ${validationResult.issues.length}`, // Display count from result
						{
							padding: 1,
							borderColor: 'red',
							borderStyle: 'round',
							margin: { top: 1, bottom: 1 }
						}
					)
				);
			}
		} else {
			log(
				'success',
				'No invalid dependencies found - all dependencies are valid'
			);

			// Show validation summary - only if not in silent mode
			if (!isSilentMode()) {
				console.log(
					boxen(
						chalk.green(`All Dependencies Are Valid\n\n`) +
							`${chalk.cyan('Tasks checked:')} ${taskCount}\n` +
							`${chalk.cyan('Subtasks checked:')} ${subtaskCount}\n` +
							`${chalk.cyan('Total dependencies verified:')} ${countAllDependencies(data.tasks)}`,
						{
							padding: 1,
							borderColor: 'green',
							borderStyle: 'round',
							margin: { top: 1, bottom: 1 }
						}
					)
				);
			}
		}
	} catch (error) {
		log('error', 'Error validating dependencies:', error);
		process.exit(1);
	}
}

/**
 * Helper function to count all dependencies across tasks and subtasks
 * @param {Array} tasks - All tasks
 * @returns {number} - Total number of dependencies
 */
function countAllDependencies(tasks) {
	let count = 0;

	tasks.forEach((task) => {
		// Count main task dependencies
		if (task.dependencies && Array.isArray(task.dependencies)) {
			count += task.dependencies.length;
		}

		// Count subtask dependencies
		if (task.subtasks && Array.isArray(task.subtasks)) {
			task.subtasks.forEach((subtask) => {
				if (subtask.dependencies && Array.isArray(subtask.dependencies)) {
					count += subtask.dependencies.length;
				}
			});
		}
	});

	return count;
}

/**
 * Fixes invalid dependencies in tasks.json
 * @param {string} tasksPath - Path to tasks.json
 * @param {Object} options - Options object, including context
 */
async function fixDependenciesCommand(tasksPath, options = {}) {
	const { context = {} } = options;
	log('info', 'Checking for and fixing invalid dependencies in tasks.json...');

	try {
		// Read tasks data
		const data = readJSON(tasksPath, context.projectRoot, context.tag);
		if (!data || !data.tasks) {
			log('error', 'No valid tasks found in tasks.json');
			process.exit(1);
		}

		// Create a deep copy of the original data for comparison
		const originalData = JSON.parse(JSON.stringify(data));

		// Track fixes for reporting
		const stats = {
			nonExistentDependenciesRemoved: 0,
			selfDependenciesRemoved: 0,
			duplicateDependenciesRemoved: 0,
			circularDependenciesFixed: 0,
			tasksFixed: 0,
			subtasksFixed: 0
		};

		// First phase: Remove duplicate dependencies in tasks
		data.tasks.forEach((task) => {
			if (task.dependencies && Array.isArray(task.dependencies)) {
				const uniqueDeps = new Set();
				const originalLength = task.dependencies.length;
				task.dependencies = task.dependencies.filter((depId) => {
					const depIdStr = String(depId);
					if (uniqueDeps.has(depIdStr)) {
						log(
							'info',
							`Removing duplicate dependency from task ${task.id}: ${depId}`
						);
						stats.duplicateDependenciesRemoved++;
						return false;
					}
					uniqueDeps.add(depIdStr);
					return true;
				});
				if (task.dependencies.length < originalLength) {
					stats.tasksFixed++;
				}
			}

			// Check for duplicates in subtasks
			if (task.subtasks && Array.isArray(task.subtasks)) {
				task.subtasks.forEach((subtask) => {
					if (subtask.dependencies && Array.isArray(subtask.dependencies)) {
						const uniqueDeps = new Set();
						const originalLength = subtask.dependencies.length;
						subtask.dependencies = subtask.dependencies.filter((depId) => {
							let depIdStr = String(depId);
							if (typeof depId === 'number' && depId < 100) {
								depIdStr = `${task.id}.${depId}`;
							}
							if (uniqueDeps.has(depIdStr)) {
								log(
									'info',
									`Removing duplicate dependency from subtask ${task.id}.${subtask.id}: ${depId}`
								);
								stats.duplicateDependenciesRemoved++;
								return false;
							}
							uniqueDeps.add(depIdStr);
							return true;
						});
						if (subtask.dependencies.length < originalLength) {
							stats.subtasksFixed++;
						}
					}
				});
			}
		});

		// Create validity maps for tasks and subtasks
		const validTaskIds = new Set(data.tasks.map((t) => t.id));
		const validSubtaskIds = new Set();
		data.tasks.forEach((task) => {
			if (task.subtasks && Array.isArray(task.subtasks)) {
				task.subtasks.forEach((subtask) => {
					validSubtaskIds.add(`${task.id}.${subtask.id}`);
				});
			}
		});

		// Second phase: Remove invalid task dependencies (non-existent tasks)
		data.tasks.forEach((task) => {
			if (task.dependencies && Array.isArray(task.dependencies)) {
				const originalLength = task.dependencies.length;
				task.dependencies = task.dependencies.filter((depId) => {
					const isSubtask = typeof depId === 'string' && depId.includes('.');

					if (isSubtask) {
						// Check if the subtask exists
						if (!validSubtaskIds.has(depId)) {
							log(
								'info',
								`Removing invalid subtask dependency from task ${task.id}: ${depId} (subtask does not exist)`
							);
							stats.nonExistentDependenciesRemoved++;
							return false;
						}
						return true;
					} else {
						// Check if the task exists
						const numericId =
							typeof depId === 'string' ? parseInt(depId, 10) : depId;
						if (!validTaskIds.has(numericId)) {
							log(
								'info',
								`Removing invalid task dependency from task ${task.id}: ${depId} (task does not exist)`
							);
							stats.nonExistentDependenciesRemoved++;
							return false;
						}
						return true;
					}
				});

				if (task.dependencies.length < originalLength) {
					stats.tasksFixed++;
				}
			}

			// Check subtask dependencies for invalid references
			if (task.subtasks && Array.isArray(task.subtasks)) {
				task.subtasks.forEach((subtask) => {
					if (subtask.dependencies && Array.isArray(subtask.dependencies)) {
						const originalLength = subtask.dependencies.length;
						const subtaskId = `${task.id}.${subtask.id}`;

						// First check for self-dependencies
						const hasSelfDependency = subtask.dependencies.some((depId) => {
							if (typeof depId === 'string' && depId.includes('.')) {
								return depId === subtaskId;
							} else if (typeof depId === 'number' && depId < 100) {
								return depId === subtask.id;
							}
							return false;
						});

						if (hasSelfDependency) {
							subtask.dependencies = subtask.dependencies.filter((depId) => {
								const normalizedDepId =
									typeof depId === 'number' && depId < 100
										? `${task.id}.${depId}`
										: String(depId);

								if (normalizedDepId === subtaskId) {
									log(
										'info',
										`Removing self-dependency from subtask ${subtaskId}`
									);
									stats.selfDependenciesRemoved++;
									return false;
								}
								return true;
							});
						}

						// Then check for non-existent dependencies
						subtask.dependencies = subtask.dependencies.filter((depId) => {
							if (typeof depId === 'string' && depId.includes('.')) {
								if (!validSubtaskIds.has(depId)) {
									log(
										'info',
										`Removing invalid subtask dependency from subtask ${subtaskId}: ${depId} (subtask does not exist)`
									);
									stats.nonExistentDependenciesRemoved++;
									return false;
								}
								return true;
							}

							// Handle numeric dependencies
							const numericId =
								typeof depId === 'number' ? depId : parseInt(depId, 10);

							// Small numbers likely refer to subtasks in the same task
							if (numericId < 100) {
								const fullSubtaskId = `${task.id}.${numericId}`;

								if (!validSubtaskIds.has(fullSubtaskId)) {
									log(
										'info',
										`Removing invalid subtask dependency from subtask ${subtaskId}: ${numericId}`
									);
									stats.nonExistentDependenciesRemoved++;
									return false;
								}

								return true;
							}

							// Otherwise it's a task reference
							if (!validTaskIds.has(numericId)) {
								log(
									'info',
									`Removing invalid task dependency from subtask ${subtaskId}: ${numericId}`
								);
								stats.nonExistentDependenciesRemoved++;
								return false;
							}

							return true;
						});

						if (subtask.dependencies.length < originalLength) {
							stats.subtasksFixed++;
						}
					}
				});
			}
		});

		// Third phase: Check for circular dependencies
		log('info', 'Checking for circular dependencies...');

		// Build the dependency map for subtasks
		const subtaskDependencyMap = new Map();
		data.tasks.forEach((task) => {
			if (task.subtasks && Array.isArray(task.subtasks)) {
				task.subtasks.forEach((subtask) => {
					const subtaskId = `${task.id}.${subtask.id}`;

					if (subtask.dependencies && Array.isArray(subtask.dependencies)) {
						const normalizedDeps = subtask.dependencies.map((depId) => {
							if (typeof depId === 'string' && depId.includes('.')) {
								return depId;
							} else if (typeof depId === 'number' && depId < 100) {
								return `${task.id}.${depId}`;
							}
							return String(depId);
						});
						subtaskDependencyMap.set(subtaskId, normalizedDeps);
					} else {
						subtaskDependencyMap.set(subtaskId, []);
					}
				});
			}
		});

		// Check for and fix circular dependencies
		for (const [subtaskId, dependencies] of subtaskDependencyMap.entries()) {
			const visited = new Set();
			const recursionStack = new Set();

			// Detect cycles
			const cycleEdges = findCycles(
				subtaskId,
				subtaskDependencyMap,
				visited,
				recursionStack
			);

			if (cycleEdges.length > 0) {
				const [taskId, subtaskNum] = subtaskId
					.split('.')
					.map((part) => Number(part));
				const task = data.tasks.find((t) => t.id === taskId);

				if (task && task.subtasks) {
					const subtask = task.subtasks.find((st) => st.id === subtaskNum);

					if (subtask && subtask.dependencies) {
						const originalLength = subtask.dependencies.length;

						const edgesToRemove = cycleEdges.map((edge) => {
							if (edge.includes('.')) {
								const [depTaskId, depSubtaskId] = edge
									.split('.')
									.map((part) => Number(part));

								if (depTaskId === taskId) {
									return depSubtaskId;
								}

								return edge;
							}

							return Number(edge);
						});

						subtask.dependencies = subtask.dependencies.filter((depId) => {
							const normalizedDepId =
								typeof depId === 'number' && depId < 100
									? `${taskId}.${depId}`
									: String(depId);

							if (
								edgesToRemove.includes(depId) ||
								edgesToRemove.includes(normalizedDepId)
							) {
								log(
									'info',
									`Breaking circular dependency: Removing ${normalizedDepId} from subtask ${subtaskId}`
								);
								stats.circularDependenciesFixed++;
								return false;
							}
							return true;
						});

						if (subtask.dependencies.length < originalLength) {
							stats.subtasksFixed++;
						}
					}
				}
			}
		}

		// Check if any changes were made by comparing with original data
		const dataChanged = JSON.stringify(data) !== JSON.stringify(originalData);

		if (dataChanged) {
			// Save the changes
			writeJSON(tasksPath, data, context.projectRoot, context.tag);
			log('success', 'Fixed dependency issues in tasks.json');

			// Regenerate task files
			log('info', 'Regenerating task files to reflect dependency changes...');
			// await generateTaskFiles(tasksPath, path.dirname(tasksPath));
		} else {
			log('info', 'No changes needed to fix dependencies');
		}

		// Show detailed statistics report
		const totalFixedAll =
			stats.nonExistentDependenciesRemoved +
			stats.selfDependenciesRemoved +
			stats.duplicateDependenciesRemoved +
			stats.circularDependenciesFixed;

		if (!isSilentMode()) {
			if (totalFixedAll > 0) {
				log('success', `Fixed ${totalFixedAll} dependency issues in total!`);

				console.log(
					boxen(
						chalk.green(`Dependency Fixes Summary:\n\n`) +
							`${chalk.cyan('Invalid dependencies removed:')} ${stats.nonExistentDependenciesRemoved}\n` +
							`${chalk.cyan('Self-dependencies removed:')} ${stats.selfDependenciesRemoved}\n` +
							`${chalk.cyan('Duplicate dependencies removed:')} ${stats.duplicateDependenciesRemoved}\n` +
							`${chalk.cyan('Circular dependencies fixed:')} ${stats.circularDependenciesFixed}\n\n` +
							`${chalk.cyan('Tasks fixed:')} ${stats.tasksFixed}\n` +
							`${chalk.cyan('Subtasks fixed:')} ${stats.subtasksFixed}\n`,
						{
							padding: 1,
							borderColor: 'green',
							borderStyle: 'round',
							margin: { top: 1, bottom: 1 }
						}
					)
				);
			} else {
				log(
					'success',
					'No dependency issues found - all dependencies are valid'
				);

				console.log(
					boxen(
						chalk.green(`All Dependencies Are Valid\n\n`) +
							`${chalk.cyan('Tasks checked:')} ${data.tasks.length}\n` +
							`${chalk.cyan('Total dependencies verified:')} ${countAllDependencies(data.tasks)}`,
						{
							padding: 1,
							borderColor: 'green',
							borderStyle: 'round',
							margin: { top: 1, bottom: 1 }
						}
					)
				);
			}
		}
	} catch (error) {
		log('error', 'Error in fix-dependencies command:', error);
		process.exit(1);
	}
}

/**
 * Ensure at least one subtask in each task has no dependencies
 * @param {Object} tasksData - The tasks data object with tasks array
 * @returns {boolean} - True if any changes were made
 */
function ensureAtLeastOneIndependentSubtask(tasksData) {
	if (!tasksData || !tasksData.tasks || !Array.isArray(tasksData.tasks)) {
		return false;
	}

	let changesDetected = false;

	tasksData.tasks.forEach((task) => {
		if (
			!task.subtasks ||
			!Array.isArray(task.subtasks) ||
			task.subtasks.length === 0
		) {
			return;
		}

		// Check if any subtask has no dependencies
		const hasIndependentSubtask = task.subtasks.some(
			(st) =>
				!st.dependencies ||
				!Array.isArray(st.dependencies) ||
				st.dependencies.length === 0
		);

		if (!hasIndependentSubtask) {
			// Find the first subtask and clear its dependencies
			if (task.subtasks.length > 0) {
				const firstSubtask = task.subtasks[0];
				log(
					'debug',
					`Ensuring at least one independent subtask: Clearing dependencies for subtask ${task.id}.${firstSubtask.id}`
				);
				firstSubtask.dependencies = [];
				changesDetected = true;
			}
		}
	});

	return changesDetected;
}

/**
 * Validate and fix dependencies across all tasks and subtasks
 * This function is designed to be called after any task modification
 * @param {Object} tasksData - The tasks data object with tasks array
 * @param {string} tasksPath - Optional path to save the changes
 * @param {string} projectRoot - Optional project root for tag context
 * @param {string} tag - Optional tag for tag context
 * @returns {boolean} - True if any changes were made
 */
function validateAndFixDependencies(
	tasksData,
	tasksPath = null,
	projectRoot = null,
	tag = null
) {
	if (!tasksData || !tasksData.tasks || !Array.isArray(tasksData.tasks)) {
		log('error', 'Invalid tasks data');
		return false;
	}

	log('debug', 'Validating and fixing dependencies...');

	// Create a deep copy for comparison
	const originalData = JSON.parse(JSON.stringify(tasksData));

	// 1. Remove duplicate dependencies from tasks and subtasks
	tasksData.tasks = tasksData.tasks.map((task) => {
		// Handle task dependencies
		if (task.dependencies) {
			const uniqueDeps = [...new Set(task.dependencies)];
			task.dependencies = uniqueDeps;
		}

		// Handle subtask dependencies
		if (task.subtasks) {
			task.subtasks = task.subtasks.map((subtask) => {
				if (subtask.dependencies) {
					const uniqueDeps = [...new Set(subtask.dependencies)];
					subtask.dependencies = uniqueDeps;
				}
				return subtask;
			});
		}
		return task;
	});

	// 2. Remove invalid task dependencies (non-existent tasks)
	tasksData.tasks.forEach((task) => {
		// Clean up task dependencies
		if (task.dependencies) {
			task.dependencies = task.dependencies.filter((depId) => {
				// Remove self-dependencies
				if (String(depId) === String(task.id)) {
					return false;
				}
				// Remove non-existent dependencies
				return taskExists(tasksData.tasks, depId);
			});
		}

		// Clean up subtask dependencies
		if (task.subtasks) {
			task.subtasks.forEach((subtask) => {
				if (subtask.dependencies) {
					subtask.dependencies = subtask.dependencies.filter((depId) => {
						// Handle numeric subtask references
						if (typeof depId === 'number' && depId < 100) {
							const fullSubtaskId = `${task.id}.${depId}`;
							return taskExists(tasksData.tasks, fullSubtaskId);
						}
						// Handle full task/subtask references
						return taskExists(tasksData.tasks, depId);
					});
				}
			});
		}
	});

	// 3. Ensure at least one subtask has no dependencies in each task
	tasksData.tasks.forEach((task) => {
		if (task.subtasks && task.subtasks.length > 0) {
			const hasIndependentSubtask = task.subtasks.some(
				(st) =>
					!st.dependencies ||
					!Array.isArray(st.dependencies) ||
					st.dependencies.length === 0
			);

			if (!hasIndependentSubtask) {
				task.subtasks[0].dependencies = [];
			}
		}
	});

	// Check if any changes were made by comparing with original data
	const changesDetected =
		JSON.stringify(tasksData) !== JSON.stringify(originalData);

	// Save changes if needed
	if (tasksPath && changesDetected) {
		try {
			writeJSON(tasksPath, tasksData, projectRoot, tag);
			log('debug', 'Saved dependency fixes to tasks.json');
		} catch (error) {
			log('error', 'Failed to save dependency fixes to tasks.json', error);
		}
	}

	return changesDetected;
}

/**
 * Recursively find all dependencies for a set of tasks with depth limiting
 * Recursively find all dependencies for a set of tasks with depth limiting
 *
 * @note This function depends on the traverseDependencies utility from utils.js
 * for the actual dependency traversal logic.
 *
 * @param {Array} sourceTasks - Array of source tasks to find dependencies for
 * @param {Array} allTasks - Array of all available tasks
 * @param {Object} options - Options object
 * @param {number} options.maxDepth - Maximum recursion depth (default: 50)
 * @param {boolean} options.includeSelf - Whether to include self-references (default: false)
 * @returns {Array} Array of all dependency task IDs
 */
function findAllDependenciesRecursively(sourceTasks, allTasks, options = {}) {
	if (!Array.isArray(sourceTasks)) {
		throw new Error('Source tasks parameter must be an array');
	}
	if (!Array.isArray(allTasks)) {
		throw new Error('All tasks parameter must be an array');
	}
	return traverseDependencies(sourceTasks, allTasks, {
		...options,
		direction: 'forward',
		logger: { warn: log.warn || console.warn }
	});
}

/**
 * Find dependency task by ID, handling various ID formats
 * @param {string|number} depId - Dependency ID to find
 * @param {string} taskId - ID of the task that has this dependency
 * @param {Array} allTasks - Array of all tasks to search
 * @returns {Object|null} Found dependency task or null
 */
/**
 * Find a subtask within a parent task's subtasks array
 * @param {string} parentId - The parent task ID
 * @param {string|number} subtaskId - The subtask ID to find
 * @param {Array} allTasks - Array of all tasks to search in
 * @param {boolean} useStringComparison - Whether to use string comparison for subtaskId
 * @returns {Object|null} The found subtask with full ID or null if not found
 */
function findSubtaskInParent(
	parentId,
	subtaskId,
	allTasks,
	useStringComparison = false
) {
	// Convert parentId to numeric for proper comparison with top-level task IDs
	const numericParentId = parseInt(parentId, 10);
	const parentTask = allTasks.find((t) => t.id === numericParentId);

	if (parentTask && parentTask.subtasks && Array.isArray(parentTask.subtasks)) {
		const foundSubtask = parentTask.subtasks.find((subtask) =>
			useStringComparison
				? String(subtask.id) === String(subtaskId)
				: subtask.id === subtaskId
		);
		if (foundSubtask) {
			// Return a task-like object that represents the subtask with full ID
			return {
				...foundSubtask,
				id: `${parentId}.${foundSubtask.id}`
			};
		}
	}

	return null;
}

function findDependencyTask(depId, taskId, allTasks) {
	if (!depId) {
		return null;
	}

	// Convert depId to string for consistent comparison
	const depIdStr = String(depId);

	// Find the dependency task - handle both top-level and subtask IDs
	let depTask = null;

	// First try exact match (for top-level tasks)
	depTask = allTasks.find((t) => String(t.id) === depIdStr);

	// If not found and it's a subtask reference (contains dot), find the parent task first
	if (!depTask && depIdStr.includes('.')) {
		const [parentId, subtaskId] = depIdStr.split('.');
		depTask = findSubtaskInParent(parentId, subtaskId, allTasks, true);
	}

	// If still not found, try numeric comparison for relative subtask references
	if (!depTask && !isNaN(depId)) {
		const numericId = parseInt(depId, 10);
		// For subtasks, this might be a relative reference within the same parent
		if (taskId && typeof taskId === 'string' && taskId.includes('.')) {
			const [parentId] = taskId.split('.');
			depTask = findSubtaskInParent(parentId, numericId, allTasks, false);
		}
	}

	return depTask;
}

/**
 * Check if a task has cross-tag dependencies
 * @param {Object} task - Task to check
 * @param {string} targetTag - Target tag name
 * @param {Array} allTasks - Array of all tasks from all tags
 * @returns {Array} Array of cross-tag dependency conflicts
 */
function findTaskCrossTagConflicts(task, targetTag, allTasks) {
	const conflicts = [];

	// Validate task.dependencies is an array before processing
	if (!Array.isArray(task.dependencies) || task.dependencies.length === 0) {
		return conflicts;
	}

	// Filter out null/undefined dependencies and check each valid dependency
	const validDependencies = task.dependencies.filter((depId) => depId != null);

	validDependencies.forEach((depId) => {
		const depTask = findDependencyTask(depId, task.id, allTasks);

		if (depTask && depTask.tag !== targetTag) {
			conflicts.push({
				taskId: task.id,
				dependencyId: depId,
				dependencyTag: depTask.tag,
				message: `Task ${task.id} depends on ${depId} (in ${depTask.tag})`
			});
		}
	});

	return conflicts;
}

function validateCrossTagMove(task, sourceTag, targetTag, allTasks) {
	// Parameter validation
	if (!task || typeof task !== 'object') {
		throw new Error('Task parameter must be a valid object');
	}

	if (!sourceTag || typeof sourceTag !== 'string') {
		throw new Error('Source tag must be a valid string');
	}

	if (!targetTag || typeof targetTag !== 'string') {
		throw new Error('Target tag must be a valid string');
	}

	if (!Array.isArray(allTasks)) {
		throw new Error('All tasks parameter must be an array');
	}

	const conflicts = findTaskCrossTagConflicts(task, targetTag, allTasks);

	return {
		canMove: conflicts.length === 0,
		conflicts
	};
}

/**
 * Find all cross-tag dependencies for a set of tasks
 * @param {Array} sourceTasks - Array of tasks to check
 * @param {string} sourceTag - Source tag name
 * @param {string} targetTag - Target tag name
 * @param {Array} allTasks - Array of all tasks from all tags
 * @returns {Array} Array of cross-tag dependency conflicts
 */
function findCrossTagDependencies(sourceTasks, sourceTag, targetTag, allTasks) {
	// Parameter validation
	if (!Array.isArray(sourceTasks)) {
		throw new Error('Source tasks parameter must be an array');
	}

	if (!sourceTag || typeof sourceTag !== 'string') {
		throw new Error('Source tag must be a valid string');
	}

	if (!targetTag || typeof targetTag !== 'string') {
		throw new Error('Target tag must be a valid string');
	}

	if (!Array.isArray(allTasks)) {
		throw new Error('All tasks parameter must be an array');
	}

	const conflicts = [];

	sourceTasks.forEach((task) => {
		// Validate task object and dependencies array
		if (
			!task ||
			typeof task !== 'object' ||
			!Array.isArray(task.dependencies) ||
			task.dependencies.length === 0
		) {
			return;
		}

		// Use the shared helper function to find conflicts for this task
		const taskConflicts = findTaskCrossTagConflicts(task, targetTag, allTasks);
		conflicts.push(...taskConflicts);
	});

	return conflicts;
}

/**
 * Helper function to find all tasks that depend on a given task (reverse dependencies)
 * @param {string|number} taskId - The task ID to find dependencies for
 * @param {Array} allTasks - Array of all tasks to search
 * @param {Set} dependentTaskIds - Set to add found dependencies to
 */
function findTasksThatDependOn(taskId, allTasks, dependentTaskIds) {
	// Find the task object for the given ID
	const sourceTask = allTasks.find((t) => t.id === taskId);
	if (!sourceTask) {
		return;
	}

	// Use the shared utility for reverse dependency traversal
	const reverseDeps = traverseDependencies([sourceTask], allTasks, {
		direction: 'reverse',
		includeSelf: false,
		logger: { warn: log.warn || console.warn }
	});

	// Add all found reverse dependencies to the dependentTaskIds set
	reverseDeps.forEach((depId) => dependentTaskIds.add(depId));
}

/**
 * Helper function to check if a task depends on a source task
 * @param {Object} task - Task to check for dependencies
 * @param {Object} sourceTask - Source task to check dependency against
 * @returns {boolean} True if task depends on source task
 */
function taskDependsOnSource(task, sourceTask) {
	if (!task || !Array.isArray(task.dependencies)) {
		return false;
	}

	const sourceTaskIdStr = String(sourceTask.id);

	return task.dependencies.some((depId) => {
		if (!depId) return false;

		const depIdStr = String(depId);

		// Exact match
		if (depIdStr === sourceTaskIdStr) {
			return true;
		}

		// Handle subtask references
		if (
			sourceTaskIdStr &&
			typeof sourceTaskIdStr === 'string' &&
			sourceTaskIdStr.includes('.')
		) {
			// If source is a subtask, check if dependency references the parent
			const [parentId] = sourceTaskIdStr.split('.');
			if (depIdStr === parentId) {
				return true;
			}
		}

		// Handle relative subtask references
		if (
			depIdStr &&
			typeof depIdStr === 'string' &&
			depIdStr.includes('.') &&
			sourceTaskIdStr &&
			typeof sourceTaskIdStr === 'string' &&
			sourceTaskIdStr.includes('.')
		) {
			const [depParentId] = depIdStr.split('.');
			const [sourceParentId] = sourceTaskIdStr.split('.');
			if (depParentId === sourceParentId) {
				// Both are subtasks of the same parent, check if they reference each other
				const depSubtaskNum = parseInt(depIdStr.split('.')[1], 10);
				const sourceSubtaskNum = parseInt(sourceTaskIdStr.split('.')[1], 10);
				if (depSubtaskNum === sourceSubtaskNum) {
					return true;
				}
			}
		}

		return false;
	});
}

/**
 * Helper function to check if any subtasks of a task depend on source tasks
 * @param {Object} task - Task to check subtasks of
 * @param {Array} sourceTasks - Array of source tasks to check dependencies against
 * @returns {boolean} True if any subtasks depend on source tasks
 */
function subtasksDependOnSource(task, sourceTasks) {
	if (!task.subtasks || !Array.isArray(task.subtasks)) {
		return false;
	}

	return task.subtasks.some((subtask) => {
		// Check if this subtask depends on any source task
		const subtaskDependsOnSource = sourceTasks.some((sourceTask) =>
			taskDependsOnSource(subtask, sourceTask)
		);

		if (subtaskDependsOnSource) {
			return true;
		}

		// Recursively check if any nested subtasks depend on source tasks
		if (subtask.subtasks && Array.isArray(subtask.subtasks)) {
			return subtasksDependOnSource(subtask, sourceTasks);
		}

		return false;
	});
}

/**
 * Get all dependent task IDs for a set of cross-tag dependencies
 * @param {Array} sourceTasks - Array of source tasks
 * @param {Array} crossTagDependencies - Array of cross-tag dependency conflicts
 * @param {Array} allTasks - Array of all tasks from all tags
 * @returns {Array} Array of dependent task IDs to move
 */
function getDependentTaskIds(sourceTasks, crossTagDependencies, allTasks) {
	// Enhanced parameter validation
	if (!Array.isArray(sourceTasks)) {
		throw new Error('Source tasks parameter must be an array');
	}

	if (!Array.isArray(crossTagDependencies)) {
		throw new Error('Cross tag dependencies parameter must be an array');
	}

	if (!Array.isArray(allTasks)) {
		throw new Error('All tasks parameter must be an array');
	}

	// Use the shared recursive dependency finder
	const dependentTaskIds = new Set(
		findAllDependenciesRecursively(sourceTasks, allTasks, {
			includeSelf: false
		})
	);

	// Add immediate dependency IDs from conflicts and find their dependencies recursively
	const conflictTasksToProcess = [];
	crossTagDependencies.forEach((conflict) => {
		if (conflict && conflict.dependencyId) {
			const depId =
				typeof conflict.dependencyId === 'string'
					? parseInt(conflict.dependencyId, 10)
					: conflict.dependencyId;
			if (!isNaN(depId)) {
				dependentTaskIds.add(depId);
				// Find the task object for recursive dependency finding
				const depTask = allTasks.find((t) => t.id === depId);
				if (depTask) {
					conflictTasksToProcess.push(depTask);
				}
			}
		}
	});

	// Find dependencies of conflict tasks
	if (conflictTasksToProcess.length > 0) {
		const conflictDependencies = findAllDependenciesRecursively(
			conflictTasksToProcess,
			allTasks,
			{ includeSelf: false }
		);
		conflictDependencies.forEach((depId) => dependentTaskIds.add(depId));
	}

	// For --with-dependencies, we also need to find all dependencies of the source tasks
	sourceTasks.forEach((sourceTask) => {
		if (sourceTask && sourceTask.id) {
			// Find all tasks that this source task depends on (forward dependencies) - already handled above

			// Find all tasks that depend on this source task (reverse dependencies)
			findTasksThatDependOn(sourceTask.id, allTasks, dependentTaskIds);
		}
	});

	// Also include any tasks that depend on the source tasks
	sourceTasks.forEach((sourceTask) => {
		if (!sourceTask || typeof sourceTask !== 'object' || !sourceTask.id) {
			return; // Skip invalid source tasks
		}

		allTasks.forEach((task) => {
			// Validate task and dependencies array
			if (
				!task ||
				typeof task !== 'object' ||
				!Array.isArray(task.dependencies)
			) {
				return;
			}

			// Check if this task depends on the source task
			const hasDependency = taskDependsOnSource(task, sourceTask);

			// Check if any subtasks of this task depend on the source task
			const subtasksHaveDependency = subtasksDependOnSource(task, [sourceTask]);

			if (hasDependency || subtasksHaveDependency) {
				dependentTaskIds.add(task.id);
			}
		});
	});

	return Array.from(dependentTaskIds);
}

/**
 * Validate subtask movement - block direct cross-tag subtask moves
 * @param {string} taskId - Task ID to validate
 * @param {string} sourceTag - Source tag name
 * @param {string} targetTag - Target tag name
 * @throws {Error} If subtask movement is attempted
 */
function validateSubtaskMove(taskId, sourceTag, targetTag) {
	// Parameter validation
	if (!taskId || typeof taskId !== 'string') {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.INVALID_TASK_ID,
			'Task ID must be a valid string'
		);
	}

	if (!sourceTag || typeof sourceTag !== 'string') {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.INVALID_SOURCE_TAG,
			'Source tag must be a valid string'
		);
	}

	if (!targetTag || typeof targetTag !== 'string') {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.INVALID_TARGET_TAG,
			'Target tag must be a valid string'
		);
	}

	if (taskId.includes('.')) {
		throw new DependencyError(
			DEPENDENCY_ERROR_CODES.CANNOT_MOVE_SUBTASK,
			`Cannot move subtask ${taskId} directly between tags.

First promote it to a full task using:
  task-master remove-subtask --id=${taskId} --convert`,
			{
				taskId,
				sourceTag,
				targetTag
			}
		);
	}
}

/**
 * Check if a task can be moved with its dependencies
 * @param {string} taskId - Task ID to check
 * @param {string} sourceTag - Source tag name
 * @param {string} targetTag - Target tag name
 * @param {Array} allTasks - Array of all tasks from all tags
 * @returns {Object} Object with canMove boolean and dependentTaskIds array
 */
function canMoveWithDependencies(taskId, sourceTag, targetTag, allTasks) {
	// Parameter validation
	if (!taskId || typeof taskId !== 'string') {
		throw new Error('Task ID must be a valid string');
	}

	if (!sourceTag || typeof sourceTag !== 'string') {
		throw new Error('Source tag must be a valid string');
	}

	if (!targetTag || typeof targetTag !== 'string') {
		throw new Error('Target tag must be a valid string');
	}

	if (!Array.isArray(allTasks)) {
		throw new Error('All tasks parameter must be an array');
	}

	// Enhanced task lookup to handle subtasks properly
	let sourceTask = null;

	// Check if it's a subtask ID (e.g., "1.2")
	if (taskId.includes('.')) {
		const [parentId, subtaskId] = taskId
			.split('.')
			.map((id) => parseInt(id, 10));
		const parentTask = allTasks.find(
			(t) => t.id === parentId && t.tag === sourceTag
		);

		if (
			parentTask &&
			parentTask.subtasks &&
			Array.isArray(parentTask.subtasks)
		) {
			const subtask = parentTask.subtasks.find((st) => st.id === subtaskId);
			if (subtask) {
				// Create a copy of the subtask with parent context
				sourceTask = {
					...subtask,
					parentTask: {
						id: parentTask.id,
						title: parentTask.title,
						status: parentTask.status
					},
					isSubtask: true
				};
			}
		}
	} else {
		// Regular task lookup - handle both string and numeric IDs
		sourceTask = allTasks.find((t) => {
			const taskIdNum = parseInt(taskId, 10);
			return (t.id === taskIdNum || t.id === taskId) && t.tag === sourceTag;
		});
	}

	if (!sourceTask) {
		return {
			canMove: false,
			dependentTaskIds: [],
			conflicts: [],
			error: 'Task not found'
		};
	}

	const validation = validateCrossTagMove(
		sourceTask,
		sourceTag,
		targetTag,
		allTasks
	);

	// Fix contradictory logic: return canMove: false when conflicts exist
	if (validation.canMove) {
		return {
			canMove: true,
			dependentTaskIds: [],
			conflicts: []
		};
	}

	// When conflicts exist, return canMove: false with conflicts and dependent task IDs
	const dependentTaskIds = getDependentTaskIds(
		[sourceTask],
		validation.conflicts,
		allTasks
	);

	return {
		canMove: false,
		dependentTaskIds,
		conflicts: validation.conflicts
	};
}

export {
	addDependency,
	removeDependency,
	isCircularDependency,
	validateTaskDependencies,
	validateDependenciesCommand,
	fixDependenciesCommand,
	removeDuplicateDependencies,
	cleanupSubtaskDependencies,
	ensureAtLeastOneIndependentSubtask,
	validateAndFixDependencies,
	findDependencyTask,
	findTaskCrossTagConflicts,
	validateCrossTagMove,
	findCrossTagDependencies,
	getDependentTaskIds,
	validateSubtaskMove,
	canMoveWithDependencies,
	findAllDependenciesRecursively,
	DependencyError,
	DEPENDENCY_ERROR_CODES
};


--- scripts/modules/error-formatter.js ---
/**
 * error-formatter.js
 * Professional error message formatting with context-specific hints and sanitization
 */

import boxen from 'boxen';
import chalk from 'chalk';

/**
 * Error type categories for context-specific handling
 */
export const ERROR_TYPES = {
	AUTHENTICATION: 'authentication',
	VALIDATION: 'validation',
	NETWORK: 'network',
	API: 'api',
	FILE_SYSTEM: 'file_system',
	TASK: 'task',
	PERMISSION: 'permission',
	TIMEOUT: 'timeout',
	GENERIC: 'generic'
};

/**
 * Sensitive data patterns to sanitize from error messages
 */
const SENSITIVE_PATTERNS = [
	// API Keys and tokens
	/\b[A-Za-z0-9_-]{20,}\b/g, // Generic token pattern
	/sk-[A-Za-z0-9]{32,}/g, // OpenAI-style keys
	/api[_-]?key[:\s=]+[^\s]+/gi,
	/bearer\s+[^\s]+/gi,
	/token[:\s=]+[^\s]+/gi,

	// File paths that might contain user info
	/\/Users\/[^/]+/g,
	/C:\\Users\\[^\\]+/g,
	/\/home\/[^/]+/g,

	// Email addresses
	/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,

	// URLs with auth
	/https?:\/\/[^:]+:[^@]+@/g
];

/**
 * Sanitize sensitive information from error messages
 * @param {string} message - The message to sanitize
 * @returns {string} Sanitized message
 */
function sanitizeMessage(message) {
	if (!message || typeof message !== 'string') return message;

	let sanitized = message;

	// Replace sensitive patterns
	for (const pattern of SENSITIVE_PATTERNS) {
		sanitized = sanitized.replace(pattern, '***REDACTED***');
	}

	return sanitized;
}

/**
 * Determine error type from error object
 * @param {Error|Object} error - Error object
 * @returns {string} Error type from ERROR_TYPES
 */
function categorizeError(error) {
	if (!error) return ERROR_TYPES.GENERIC;

	const message = (error.message || '').toLowerCase();
	const code = (error.code || '').toLowerCase();

	// Authentication errors
	if (
		message.includes('auth') ||
		message.includes('unauthorized') ||
		message.includes('forbidden') ||
		message.includes('api key') ||
		message.includes('token') ||
		code.includes('auth')
	) {
		return ERROR_TYPES.AUTHENTICATION;
	}

	// Validation errors
	if (
		message.includes('invalid') ||
		message.includes('validation') ||
		message.includes('required') ||
		message.includes('must be') ||
		code.includes('validation')
	) {
		return ERROR_TYPES.VALIDATION;
	}

	// Network errors
	if (
		message.includes('network') ||
		message.includes('connection') ||
		message.includes('econnrefused') ||
		message.includes('enotfound') ||
		code.includes('network') ||
		code.includes('econnrefused') ||
		code.includes('enotfound')
	) {
		return ERROR_TYPES.NETWORK;
	}

	// Timeout errors
	if (
		message.includes('timeout') ||
		message.includes('timed out') ||
		code.includes('timeout')
	) {
		return ERROR_TYPES.TIMEOUT;
	}

	// API errors
	if (
		message.includes('api') ||
		message.includes('rate limit') ||
		message.includes('quota') ||
		code.includes('api')
	) {
		return ERROR_TYPES.API;
	}

	// File system errors
	if (
		message.includes('enoent') ||
		message.includes('eacces') ||
		message.includes('file') ||
		message.includes('directory') ||
		code.includes('enoent') ||
		code.includes('eacces')
	) {
		return ERROR_TYPES.FILE_SYSTEM;
	}

	// Permission errors
	if (
		message.includes('permission') ||
		message.includes('access denied') ||
		code.includes('eperm')
	) {
		return ERROR_TYPES.PERMISSION;
	}

	// Task-specific errors
	if (message.includes('task') || message.includes('subtask')) {
		return ERROR_TYPES.TASK;
	}

	return ERROR_TYPES.GENERIC;
}

/**
 * Generate context-specific hints for an error
 * @param {string} errorType - Error type from ERROR_TYPES
 * @param {Error|Object} error - Original error object
 * @param {string} context - Additional context about what was being attempted
 * @returns {string[]} Array of hint strings
 */
function generateHints(errorType, error, context) {
	const hints = [];
	const message = (error.message || '').toLowerCase();

	switch (errorType) {
		case ERROR_TYPES.AUTHENTICATION:
			if (message.includes('api key')) {
				hints.push('Check that your API key is correctly set in the .env file');
				hints.push('Verify the API key has not expired or been revoked');
			} else if (message.includes('token')) {
				hints.push('Your authentication token may have expired');
				hints.push('Try running: tm auth refresh');
			} else {
				hints.push('Verify your credentials are correctly configured');
				hints.push('Check the authentication status with: tm auth status');
			}
			break;

		case ERROR_TYPES.VALIDATION:
			if (message.includes('brief id')) {
				hints.push('Brief IDs are case-insensitive (e.g., "ham32" = "HAM-32")');
				hints.push('Check the brief ID format: usually LETTERS-NUMBERS');
			} else if (
				message.includes('task id') ||
				message.includes('invalid id')
			) {
				hints.push('Task IDs should be numbers (e.g., 1, 2, 3)');
				hints.push('Subtask IDs use dot notation (e.g., 1.1, 2.3)');
			} else {
				hints.push('Check that all required parameters are provided');
				hints.push('Verify parameter values match expected formats');
			}
			break;

		case ERROR_TYPES.NETWORK:
			if (message.includes('econnrefused')) {
				hints.push('Could not connect to the server');
				hints.push('Check your internet connection');
				hints.push('Verify the API endpoint URL is correct');
			} else if (message.includes('enotfound')) {
				hints.push('Could not resolve the server hostname');
				hints.push('Check your internet connection');
			} else {
				hints.push('Check your network connection');
				hints.push('Verify firewall settings are not blocking the request');
			}
			break;

		case ERROR_TYPES.TIMEOUT:
			hints.push('The operation took too long to complete');
			hints.push('Try again with a simpler request');
			hints.push('Check your network speed and stability');
			break;

		case ERROR_TYPES.API:
			if (message.includes('rate limit')) {
				hints.push('You have exceeded the API rate limit');
				hints.push('Wait a few minutes before trying again');
			} else if (message.includes('quota')) {
				hints.push('You have reached your API quota');
				hints.push('Check your account usage and limits');
			} else {
				hints.push('The API returned an error');
				hints.push('Try again in a few moments');
			}
			break;

		case ERROR_TYPES.FILE_SYSTEM:
			if (message.includes('enoent')) {
				hints.push('The specified file or directory does not exist');
				hints.push('Check the file path and ensure it is correct');
				if (context.includes('tasks.json')) {
					hints.push('Initialize the project with: tm init');
				}
			} else if (message.includes('eacces')) {
				hints.push('Permission denied to access the file');
				hints.push('Check file permissions or run with appropriate privileges');
			} else {
				hints.push('Check that the file or directory exists and is accessible');
			}
			break;

		case ERROR_TYPES.PERMISSION:
			hints.push('You do not have permission to perform this operation');
			hints.push('Check file/directory permissions');
			hints.push('You may need elevated privileges (sudo)');
			break;

		case ERROR_TYPES.TASK:
			if (message.includes('not found')) {
				hints.push('The specified task does not exist');
				hints.push('Use: tm list to see all available tasks');
			} else if (
				message.includes('dependency') ||
				message.includes('circular')
			) {
				hints.push('Task dependencies form a circular reference');
				hints.push('Use: tm validate-dependencies to identify issues');
			} else {
				hints.push('Check that the task ID is correct');
				hints.push('Use: tm show <id> to view task details');
			}
			break;

		default:
			hints.push('Check the error message for specific details');
			if (context) {
				hints.push(`Operation failed while: ${context}`);
			}
	}

	// Limit to 2 hints max
	return hints.slice(0, 2);
}

/**
 * Format an error with context-specific hints and professional styling
 * @param {Error|Object|string} error - The error to format
 * @param {Object} options - Formatting options
 * @param {string} [options.context] - Context about what was being attempted
 * @param {boolean} [options.debug] - Include stack trace
 * @param {string} [options.command] - Command that was being executed
 * @returns {Object} Formatted error object
 */
export function formatError(error, options = {}) {
	const { context = '', debug = false, command = '' } = options;

	// Handle string errors
	if (typeof error === 'string') {
		error = new Error(error);
	}

	// Ensure error object
	if (!error || typeof error !== 'object') {
		error = new Error('An unknown error occurred');
	}

	// Sanitize the error message
	const sanitizedMessage = sanitizeMessage(error.message || 'Unknown error');

	// Categorize the error
	const errorType = categorizeError(error);

	// Generate context-specific hints
	const hints = generateHints(errorType, error, context);

	// Build formatted error object
	const formattedError = {
		type: errorType,
		message: sanitizedMessage,
		context: context || 'Unknown operation',
		hints,
		command: command || null,
		code: error.code || null,
		stack: debug ? sanitizeMessage(error.stack) : null
	};

	return formattedError;
}

/**
 * Display a formatted error message in the terminal
 * @param {Error|Object|string} error - The error to display
 * @param {Object} options - Display options
 * @param {string} [options.context] - Context about what was being attempted
 * @param {boolean} [options.debug] - Include stack trace
 * @param {string} [options.command] - Command that was being executed
 */
export function displayFormattedError(error, options = {}) {
	const formattedError = formatError(error, options);

	// Build error message content
	let content = chalk.red.bold('✗ Error\n\n');

	// Add error message
	content += chalk.white(formattedError.message) + '\n\n';

	// Add context if available
	if (
		formattedError.context &&
		formattedError.context !== 'Unknown operation'
	) {
		content +=
			chalk.gray('Context: ') + chalk.white(formattedError.context) + '\n\n';
	}

	// Add command if available
	if (formattedError.command) {
		content +=
			chalk.gray('Command: ') + chalk.cyan(formattedError.command) + '\n\n';
	}

	// Add hints
	if (formattedError.hints && formattedError.hints.length > 0) {
		content += chalk.yellow.bold('Suggestions:\n');
		formattedError.hints.forEach((hint, index) => {
			content += chalk.yellow(`  ${index + 1}. ${hint}\n`);
		});
	}

	// Add error code if available
	if (formattedError.code) {
		content += '\n' + chalk.gray(`Error Code: ${formattedError.code}`);
	}

	// Display in a box
	console.log(
		'\n' +
			boxen(content.trim(), {
				padding: { top: 1, bottom: 1, left: 2, right: 2 },
				borderStyle: 'round',
				borderColor: 'red'
			}) +
			'\n'
	);

	// Display stack trace in debug mode
	if (options.debug && formattedError.stack) {
		console.log(chalk.gray('Stack Trace:'));
		console.log(chalk.dim(formattedError.stack));
		console.log();
	}
}

/**
 * Display a warning message
 * @param {string} message - Warning message
 * @param {string[]} [hints] - Optional hints
 */
export function displayWarning(message, hints = []) {
	let content = chalk.yellow.bold('⚠ Warning\n\n');
	content += chalk.white(message);

	if (hints && hints.length > 0) {
		content += '\n\n' + chalk.yellow.bold('Suggestions:\n');
		hints.forEach((hint, index) => {
			content += chalk.yellow(`  ${index + 1}. ${hint}\n`);
		});
	}

	console.log(
		'\n' +
			boxen(content.trim(), {
				padding: { top: 1, bottom: 1, left: 2, right: 2 },
				borderStyle: 'round',
				borderColor: 'yellow'
			}) +
			'\n'
	);
}

/**
 * Display an informational message
 * @param {string} message - Info message
 * @param {string} [title] - Optional title
 */
export function displayInfo(message, title = 'Info') {
	let content = chalk.blue.bold(`ℹ ${title}\n\n`);
	content += chalk.white(message);

	console.log(
		'\n' +
			boxen(content.trim(), {
				padding: { top: 1, bottom: 1, left: 2, right: 2 },
				borderStyle: 'round',
				borderColor: 'blue'
			}) +
			'\n'
	);
}

/**
 * Display a success message
 * @param {string} message - Success message
 * @param {string[]} [nextSteps] - Optional next steps
 */
export function displaySuccess(message, nextSteps = []) {
	let content = chalk.green.bold('✓ Success\n\n');
	content += chalk.white(message);

	if (nextSteps && nextSteps.length > 0) {
		content += '\n\n' + chalk.cyan.bold('Next Steps:\n');
		nextSteps.forEach((step, index) => {
			content += chalk.cyan(`  ${index + 1}. ${step}\n`);
		});
	}

	console.log(
		'\n' +
			boxen(content.trim(), {
				padding: { top: 1, bottom: 1, left: 2, right: 2 },
				borderStyle: 'round',
				borderColor: 'green'
			}) +
			'\n'
	);
}


--- scripts/modules/index.js ---
/**
 * index.js
 * Main export point for all Task Master CLI modules
 */

// Export all modules
export * from './ui.js';
export * from './utils.js';
export * from './commands.js';
export * from './task-manager.js';
export * from './prompt-manager.js';


--- CHANGELOG.md ---
# task-master-ai

## 0.40.1

### Patch Changes

- [#1523](https://github.com/eyaltoledano/claude-task-master/pull/1523) [`fc1a79f`](https://github.com/eyaltoledano/claude-task-master/commit/fc1a79f2565b0d8c24f009aec2c473a335262ae2) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Codex cli Validate reasoning effort against model capabilities
  - Add provider-level reasoning effort validation for OpenAI models
  - Automatically cap unsupported effort levels (e.g., 'xhigh' on gpt-5.1 and gpt-5 becomes 'high')

- [#1549](https://github.com/eyaltoledano/claude-task-master/pull/1549) [`98087ac`](https://github.com/eyaltoledano/claude-task-master/commit/98087acae91fad7345bdb4c253d4dfd0d584f81e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve CLI startup speed by 2x

- [#1545](https://github.com/eyaltoledano/claude-task-master/pull/1545) [`a0007a3`](https://github.com/eyaltoledano/claude-task-master/commit/a0007a3575305c367c8561584aa0dbd181f5e1cc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Smarter project root detection with boundary markers
  - Prevents Task Master from incorrectly detecting `.taskmaster` folders in your home directory when working inside a different project
  - Now stops at project boundaries (`.git`, `package.json`, lock files) instead of searching all the way up to the filesystem root
  - Adds support for monorepo markers (`lerna.json`, `nx.json`, `turbo.json`) and additional lock files (`bun.lockb`, `deno.lock`)

- [#1523](https://github.com/eyaltoledano/claude-task-master/pull/1523) [`fc1a79f`](https://github.com/eyaltoledano/claude-task-master/commit/fc1a79f2565b0d8c24f009aec2c473a335262ae2) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve json schemas for ai-related commands making it more compatible with openai models
  - Fixes #1541 #1542

- [#1542](https://github.com/eyaltoledano/claude-task-master/pull/1542) [`b817d6f`](https://github.com/eyaltoledano/claude-task-master/commit/b817d6f9f278c84785ec468f9b305e70c47266f6) Thanks [@mdimitrovg](https://github.com/mdimitrovg)! - Fixed vertex-ai authentication when using service account and vertex location env variable.

## 0.40.0

### Minor Changes

- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added Gemini 3 Flash Preview model support for Google and Gemini CLI providers

- [#1535](https://github.com/eyaltoledano/claude-task-master/pull/1535) [`4d1ed20`](https://github.com/eyaltoledano/claude-task-master/commit/4d1ed20345083ab2ec1c7fc268c69379281a68ea) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add auto-detection for IDE profiles in rules command
  - `tm rules add` now opens interactive setup with detected IDEs pre-selected
  - `tm rules add -y` auto-detects and installs rules without prompting
  - Detects 13 IDEs: Cursor, Claude Code, Windsurf, VS Code, Roo, Cline, Kiro, Zed, Kilo, Trae, Gemini, OpenCode, Codex

- [#1526](https://github.com/eyaltoledano/claude-task-master/pull/1526) [`38c2c08`](https://github.com/eyaltoledano/claude-task-master/commit/38c2c08af1f8de729d5d2dab586ec4622445f2db) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add watch mode and compact output to list command
  - Add `-w/--watch` flag to continuously monitor task changes with real-time updates
  - Add `-c/--compact` flag for minimal task output format
  - Add `--no-header` flag to hide the command header
  - Support file-based watching via fs.watch for local tasks.json
  - Support API-based watching via Supabase Realtime for authenticated users
  - Display last sync timestamp and source in watch mode

### Patch Changes

- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improved model search in `task-master models --setup` to match both display names and model IDs

## 0.40.0-rc.0

### Minor Changes

- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added Gemini 3 Flash Preview model support for Google and Gemini CLI providers

- [#1535](https://github.com/eyaltoledano/claude-task-master/pull/1535) [`4d1ed20`](https://github.com/eyaltoledano/claude-task-master/commit/4d1ed20345083ab2ec1c7fc268c69379281a68ea) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add auto-detection for IDE profiles in rules command
  - `tm rules add` now opens interactive setup with detected IDEs pre-selected
  - `tm rules add -y` auto-detects and installs rules without prompting
  - Detects 13 IDEs: Cursor, Claude Code, Windsurf, VS Code, Roo, Cline, Kiro, Zed, Kilo, Trae, Gemini, OpenCode, Codex

- [#1526](https://github.com/eyaltoledano/claude-task-master/pull/1526) [`38c2c08`](https://github.com/eyaltoledano/claude-task-master/commit/38c2c08af1f8de729d5d2dab586ec4622445f2db) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add watch mode and compact output to list command
  - Add `-w/--watch` flag to continuously monitor task changes with real-time updates
  - Add `-c/--compact` flag for minimal task output format
  - Add `--no-header` flag to hide the command header
  - Support file-based watching via fs.watch for local tasks.json
  - Support API-based watching via Supabase Realtime for authenticated users
  - Display last sync timestamp and source in watch mode

### Patch Changes

- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improved model search in `task-master models --setup` to match both display names and model IDs

## 0.39.0

### Minor Changes

- [#1521](https://github.com/eyaltoledano/claude-task-master/pull/1521) [`353e3bf`](https://github.com/eyaltoledano/claude-task-master/commit/353e3bffd6df528dc19f7c5790564d0dead14c6d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced task metadata display for remote/team mode tasks
  - Tasks now display rich implementation guidance in team mode including:
    - **Relevant Files**: Files to create, modify, or reference with descriptions
    - **Codebase Patterns**: Coding patterns and conventions to follow
    - **Existing Infrastructure**: Code and utilities to leverage
    - **Scope Boundaries**: What's in and out of scope for the task
    - **Implementation Approach**: Step-by-step guidance
    - **Technical Constraints**: Requirements and limitations
    - **Acceptance Criteria**: Definition of done checklist
    - **Skills & Category**: Task classification and required expertise
  - How to see the new task details:
    1. Create a brief on tryhamster.com
    2. Generate the plan of the brief
    3. View subtasks

- [#1525](https://github.com/eyaltoledano/claude-task-master/pull/1525) [`1c2228d`](https://github.com/eyaltoledano/claude-task-master/commit/1c2228dbb618e522798c4484b74c1508f13d61d6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add tool search tool for Claude Code MCP server and enable deferred MCP loading
  - Added new tool search tool capabilities for the Taskmaster MCP in Claude Code
  - Running `task-master rules add claude` now automatically configures your shell (`~/.zshrc`, `~/.bashrc`, or PowerShell profile) with `ENABLE_EXPERIMENTAL_MCP_CLI=true` to enable deferred MCP loading
  - **Context savings**: Deferred loading saves ~16% of Claude Code's 200k context window (~33k tokens for Task Master alone). Savings apply to all MCP servers, so total savings may be higher depending on your setup.

### Patch Changes

- [#1310](https://github.com/eyaltoledano/claude-task-master/pull/1310) [`4b6570e`](https://github.com/eyaltoledano/claude-task-master/commit/4b6570e300eedb265af215c0ca6baeb772d42e4a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix Azure OpenAI provider to use correct deployment-based URL format
  - Add Azure OpenAI documentation page <https://docs.task-master.dev/providers/azure>

## 0.39.0-rc.0

### Minor Changes

- [#1521](https://github.com/eyaltoledano/claude-task-master/pull/1521) [`353e3bf`](https://github.com/eyaltoledano/claude-task-master/commit/353e3bffd6df528dc19f7c5790564d0dead14c6d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced task metadata display for remote/team mode tasks
  - Tasks now display rich implementation guidance in team mode including:
    - **Relevant Files**: Files to create, modify, or reference with descriptions
    - **Codebase Patterns**: Coding patterns and conventions to follow
    - **Existing Infrastructure**: Code and utilities to leverage
    - **Scope Boundaries**: What's in and out of scope for the task
    - **Implementation Approach**: Step-by-step guidance
    - **Technical Constraints**: Requirements and limitations
    - **Acceptance Criteria**: Definition of done checklist
    - **Skills & Category**: Task classification and required expertise
  - How to see the new task details:
    1. Create a brief on tryhamster.com
    2. Generate the plan of the brief
    3. View subtasks

- [#1525](https://github.com/eyaltoledano/claude-task-master/pull/1525) [`1c2228d`](https://github.com/eyaltoledano/claude-task-master/commit/1c2228dbb618e522798c4484b74c1508f13d61d6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add tool search tool for Claude Code MCP server and enable deferred MCP loading
  - Added new tool search tool capabilities for the Taskmaster MCP in Claude Code
  - Running `task-master rules add claude` now automatically configures your shell (`~/.zshrc`, `~/.bashrc`, or PowerShell profile) with `ENABLE_EXPERIMENTAL_MCP_CLI=true` to enable deferred MCP loading
  - **Context savings**: Deferred loading saves ~16% of Claude Code's 200k context window (~33k tokens for Task Master alone). Savings apply to all MCP servers, so total savings may be higher depending on your setup.

### Patch Changes

- [#1310](https://github.com/eyaltoledano/claude-task-master/pull/1310) [`4b6570e`](https://github.com/eyaltoledano/claude-task-master/commit/4b6570e300eedb265af215c0ca6baeb772d42e4a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix Azure OpenAI provider to use correct deployment-based URL format
  - Add Azure OpenAI documentation page <https://docs.task-master.dev/providers/azure>

## 0.38.0

### Minor Changes

- [#1461](https://github.com/eyaltoledano/claude-task-master/pull/1461) [`9ee63e0`](https://github.com/eyaltoledano/claude-task-master/commit/9ee63e01db4308cf248be3855949c7cd86272b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add operating mode filtering for slash commands and rules

  Solo mode and team mode now have distinct sets of commands and rules:
  - **Solo mode**: Local file-based storage commands (parse-prd, add-task, expand, etc.) plus common commands
  - **Team mode**: Team-specific commands (goham) plus common commands (show-task, list-tasks, help, etc.)

  Both modes share common commands for viewing and navigating tasks. The difference is:
  - Solo users get commands for local file management (PRD parsing, task expansion, dependencies)
  - Team users get Hamster cloud integration commands instead

  When switching modes (e.g., from solo to team), all existing TaskMaster commands and rules are automatically cleaned up before adding the new mode's files. This prevents orphaned commands/rules from previous modes.

  The operating mode is auto-detected from config or auth status, and can be overridden with `--mode=solo|team` flag on the `rules` command.

- [#1461](https://github.com/eyaltoledano/claude-task-master/pull/1461) [`9ee63e0`](https://github.com/eyaltoledano/claude-task-master/commit/9ee63e01db4308cf248be3855949c7cd86272b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Taskmaster slash commands for:
  - Roo
  - Cursor
  - Codex
  - Gemini
  - Opencode

  Add them with `task-master rules add <provider>`

- [#1508](https://github.com/eyaltoledano/claude-task-master/pull/1508) [`69ac463`](https://github.com/eyaltoledano/claude-task-master/commit/69ac46351eac8e1c3f58b203b2a618bf6114c000) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Added support for new OpenAI models with reasoning effort configuration:
  - `gpt-5.1` (codex-cli & openai): supports none, low, medium, high reasoning
  - `gpt-5.1-codex-max` (codex-cli & openai): supports none, low, medium, high, xhigh reasoning
  - `gpt-5.2` (codex-cli & openai): supports none, low, medium, high, xhigh reasoning
  - `gpt-5.2-pro` (openai only): supports medium, high, xhigh reasoning

  Updated ai-sdk-provider-codex-cli dependency to ^0.7.0.

## 0.38.0-rc.1

### Minor Changes

- [#1461](https://github.com/eyaltoledano/claude-task-master/pull/1461) [`9ee63e0`](https://github.com/eyaltoledano/claude-task-master/commit/9ee63e01db4308cf248be3855949c7cd86272b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add operating mode filtering for slash commands and rules

  Solo mode and team mode now have distinct sets of commands and rules:
  - **Solo mode**: Local file-based storage commands (parse-prd, add-task, expand, etc.) plus common commands
  - **Team mode**: Team-specific commands (goham) plus common commands (show-task, list-tasks, help, etc.)

  Both modes share common commands for viewing and navigating tasks. The difference is:
  - Solo users get commands for local file management (PRD parsing, task expansion, dependencies)
  - Team users get Hamster cloud integration commands instead

  When switching modes (e.g., from solo to team), all existing TaskMaster commands and rules are automatically cleaned up before adding the new mode's files. This prevents orphaned commands/rules from previous modes.

  The operating mode is auto-detected from config or auth status, and can be overridden with `--mode=solo|team` flag on the `rules` command.

- [#1461](https://github.com/eyaltoledano/claude-task-master/pull/1461) [`9ee63e0`](https://github.com/eyaltoledano/claude-task-master/commit/9ee63e01db4308cf248be3855949c7cd86272b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Taskmaster slash commands for:
  - Roo
  - Cursor
  - Codex
  - Gemini
  - Opencode

  Add them with `task-master rules add <provider>`

## 0.38.0-rc.0

### Minor Changes

- [#1508](https://github.com/eyaltoledano/claude-task-master/pull/1508) [`69ac463`](https://github.com/eyaltoledano/claude-task-master/commit/69ac46351eac8e1c3f58b203b2a618bf6114c000) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Added support for new OpenAI models with reasoning effort configuration:
  - `gpt-5.1` (codex-cli & openai): supports none, low, medium, high reasoning
  - `gpt-5.1-codex-max` (codex-cli & openai): supports none, low, medium, high, xhigh reasoning
  - `gpt-5.2` (codex-cli & openai): supports none, low, medium, high, xhigh reasoning
  - `gpt-5.2-pro` (openai only): supports medium, high, xhigh reasoning

  Updated ai-sdk-provider-codex-cli dependency to ^0.7.0.

## 0.37.2

### Patch Changes

- [#1492](https://github.com/eyaltoledano/claude-task-master/pull/1492) [`071dfc6`](https://github.com/eyaltoledano/claude-task-master/commit/071dfc6be9abe30909157ea72e026036721cea1d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix login issues for users whose browsers or firewalls were blocking CLI authentication

- [#1491](https://github.com/eyaltoledano/claude-task-master/pull/1491) [`0e908be`](https://github.com/eyaltoledano/claude-task-master/commit/0e908be43af1075bae1fd7f6b7a6fad8a131dd56) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add `tm/` prefix to autopilot branch names
  - Team mode branches now follow the `tm/<org-slug>/task-<id>` naming convention for better organization.
  - Solves issue some users were having regarding not being able to start workflow on master Taskmaster tag

## 0.37.2

### Patch Changes

- [#1492](https://github.com/eyaltoledano/claude-task-master/pull/1492) [`071dfc6`](https://github.com/eyaltoledano/claude-task-master/commit/071dfc6be9abe30909157ea72e026036721cea1d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix login issues for users whose browsers or firewalls were blocking CLI authentication

- [#1491](https://github.com/eyaltoledano/claude-task-master/pull/1491) [`0e908be`](https://github.com/eyaltoledano/claude-task-master/commit/0e908be43af1075bae1fd7f6b7a6fad8a131dd56) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add `tm/` prefix to autopilot branch names
  - Team mode branches now follow the `tm/<org-slug>/task-<id>` naming convention for better organization.
  - Solves issue some users were having regarding not being able to start workflow on master Taskmaster tag

## 0.37.2-rc.0

### Patch Changes

- [#1492](https://github.com/eyaltoledano/claude-task-master/pull/1492) [`071dfc6`](https://github.com/eyaltoledano/claude-task-master/commit/071dfc6be9abe30909157ea72e026036721cea1d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix login issues for users whose browsers or firewalls were blocking CLI authentication

- [#1491](https://github.com/eyaltoledano/claude-task-master/pull/1491) [`0e908be`](https://github.com/eyaltoledano/claude-task-master/commit/0e908be43af1075bae1fd7f6b7a6fad8a131dd56) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add `tm/` prefix to autopilot branch names
  - Team mode branches now follow the `tm/<org-slug>/task-<id>` naming convention for better organization.
  - Solves issue some users were having regarding not being able to start workflow on master Taskmaster tag

## 0.37.1

### Patch Changes

- [#1477](https://github.com/eyaltoledano/claude-task-master/pull/1477) [`b0199f1`](https://github.com/eyaltoledano/claude-task-master/commit/b0199f1cfa643051f90406d69e90ea916d434e6a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve auth-related error handling

- [#1478](https://github.com/eyaltoledano/claude-task-master/pull/1478) [`6ff330f`](https://github.com/eyaltoledano/claude-task-master/commit/6ff330f8c2bc6e534e0a883c770e8394d7ad5fa8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Increase page size of brief selection (interactive cli setup)

## 0.37.1-rc.0

### Patch Changes

- [#1478](https://github.com/eyaltoledano/claude-task-master/pull/1478) [`6ff330f`](https://github.com/eyaltoledano/claude-task-master/commit/6ff330f8c2bc6e534e0a883c770e8394d7ad5fa8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Increase page size of brief selection (interactive cli setup)

## 0.37.0

### Minor Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Hamster integration for `parse-prd` command

  Your tasks are only as good as the context behind them. Now when you run `parse-prd`, you can choose to bring your PRD to Hamster instead of parsing locally.

  **New Workflow Choice**
  - **Parse locally**: PRD becomes a task list in a local JSON file - great for quick prototyping and vibing solo
  - **Bring it to Hamster**: PRD becomes a living brief connected to your team, codebase, and agents

  **Why Hamster?**
  - Tasks live in a central place with real-time sync across your team
  - Collaborate on your PRD/brief together, generate tasks on Hamster, bring them into Taskmaster
  - No API keys needed - Hamster handles all AI inference, just need a Hamster account

  **Hamster Integration**
  - OAuth login flow when choosing Hamster (same as export command)
  - Create brief directly from PRD content with auto-generated title/description
  - Progress bar showing task generation phases (analyzing → generating → processing)
  - Invite teammates during brief creation
  - Auto-set context to new brief when complete

  **Quality of Life**
  - Clickable brief URL and team invite URL in terminal
  - Shows task count as they're generated
  - Graceful fallback if generation takes longer than expected

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Redesign `tm init` with clearer workflow selection and reduced noise

  Choose how you want to plan: Solo with Taskmaster or Together with Hamster. The new init flow guides you through setup with context-appropriate options and cleaner output.

  **New Workflow Selection**
  - Clear framing: "You need a plan before you execute. How do you want to build it?"
  - **Solo (Taskmaster)**: Parse PRD → structured tasks → AI agent executes with control
  - **Together (Hamster)**: Team writes brief → Hamster refines → aligned execution with Taskmaster

  **Cleaner Experience**
  - Optional AI IDE rules setup (Y/n prompt instead of always showing)
  - 15+ log messages moved to debug level - much less noise
  - Skip Git prompts when using Hamster (not needed for cloud storage)
  - Skip AI model configuration for Hamster (uses Hamster's AI)

  **Hamster Integration**
  - OAuth login flow when choosing Hamster workflow
  - Context-aware guidance based on your workflow choice

  **Quality of Life**
  - Run `tm rules --setup` anytime if you declined during init
  - Use `--yes` flag for fully non-interactive setup
  - Use `--rules cursor,windsurf` to specify rules upfront

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Introduce `tm export` command - bring Task Master to your team

  Share your task plans with teammates by exporting local tasks to collaborative briefs on Hamster. Select which tags to export, invite team members, and start collaborating instantly.

  **New `tm export` Command**
  - Export your local tasks to shareable team briefs
  - Hamster will reverse engineer your PRD based on your tasks (reverse parse prd!)
  - Select multiple tags to export in one go, import all tasks across tags to Hamster
  - Hamster will generate brief titles and descriptions from your task content
  - Automatically sets your CLI context to the new brief
  - All AI calls handled by Hamster, zero API keys needed - just a Hamster account!

  **Team Collaboration**
  - Invite teammates during export with `-I, --invite` flag
  - Add up to 10 team members by email
  - See invitation status: sent, already a member, or error

  **Quality of Life Improvements**
  - New `tm login` / `tm logout` shortcuts
  - Display ID shortcuts: `tm show ham31` now works (normalizes to HAM-31)
  - Better task rendering with proper HTML/Markdown support

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add simpler positional syntax and Hamster-aware UI improvements
  - **Simpler command syntax**: Use positional arguments without flags
    - `tm update-task 1 Added implementation` (no quotes needed for multi-word prompts)
    - `tm status 1 done` (new alias for set-status) or `tm set-status 1,1.1,2 in-progress`
    - `tm list done` or `tm list in-progress` or `tm list all` (shortcut for --with-subtasks)
  - **Hamster-aware help**: Context-specific command list when connected to Hamster
    - Shows only relevant commands for Hamster workflow
    - Beautiful boxed section headers with improved spacing
    - Clear usage examples with new positional syntax
    - Better visual alignment and cleaner formatting
  - **Progress indicators**: Added loading spinner to `update-task` when connected to Hamster
    - Shows "Updating task X on Hamster..." during AI processing
    - Cleaner, more responsive UX for long-running operations
  - **Improved context display**: Show 'Brief: [name]' instead of 'tag: [name]' when connected to Hamster
  - **Cleaner Hamster updates**: Simplified update display (removed redundant Mode/Prompt info)
  - **Smart messaging**: "NO TASKS AVAILABLE" warning only shows when literally no tasks exist
    - Removed misleading messages when tasks are just completed/in-progress/blocked
    - Better UX for filtered task lists
  - **Updated help everywhere**: Regular help menu now shows new positional argument syntax
    - All suggested actions updated across commands
    - Consistent syntax in all UI components
  - **Auto-detection**: Automatically detects Hamster connection for better UX
  - **Backward compatible**: All old flag syntax still works (`--id`, `--status`, etc.)

### Patch Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Sentry integration for error tracking and AI telemetry monitoring
  - **Sentry Integration**: Added comprehensive error tracking and AI operation monitoring using Sentry with Vercel AI SDK integration
  - **AI Telemetry**: All AI operations (generateText, streamText, generateObject, streamObject) now automatically track spans, token usage, prompts, and responses
  - **MCP Server Instrumentation**: Wrapped FastMCP server with `Sentry.wrapMcpServerWithSentry()` to automatically capture spans for all MCP tool interactions
  - **Privacy Controls**: Added `anonymousTelemetry` config option (default: true) allowing local storage users to opt out of telemetry
  - **Complete Coverage**: Telemetry enabled for all AI commands including parse-prd, expand, update-task, analyze-complexity, and research
  - **Internal Telemetry**: Sentry DSN is hardcoded internally for Task Master's telemetry (not user-configurable)
  - **Dual Initialization**: Automatic Sentry initialization in both CLI (scripts/dev.js) and MCP Server (mcp-server/src/index.js) with full MCP instrumentation

- [#1463](https://github.com/eyaltoledano/claude-task-master/pull/1463) [`55595f6`](https://github.com/eyaltoledano/claude-task-master/commit/55595f680c8b52b5421d3e0c7640bf2050efe44f) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix package issue in earlier rc

## 0.36.0-rc.3

### Minor Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Hamster integration for `parse-prd` command

  Your tasks are only as good as the context behind them. Now when you run `parse-prd`, you can choose to bring your PRD to Hamster instead of parsing locally.

  **New Workflow Choice**
  - **Parse locally**: PRD becomes a task list in a local JSON file - great for quick prototyping and vibing solo
  - **Bring it to Hamster**: PRD becomes a living brief connected to your team, codebase, and agents

  **Why Hamster?**
  - Tasks live in a central place with real-time sync across your team
  - Collaborate on your PRD/brief together, generate tasks on Hamster, bring them into Taskmaster
  - No API keys needed - Hamster handles all AI inference, just need a Hamster account

  **Hamster Integration**
  - OAuth login flow when choosing Hamster (same as export command)
  - Create brief directly from PRD content with auto-generated title/description
  - Progress bar showing task generation phases (analyzing → generating → processing)
  - Invite teammates during brief creation
  - Auto-set context to new brief when complete

  **Quality of Life**
  - Clickable brief URL and team invite URL in terminal
  - Shows task count as they're generated
  - Graceful fallback if generation takes longer than expected

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Redesign `tm init` with clearer workflow selection and reduced noise

  Choose how you want to plan: Solo with Taskmaster or Together with Hamster. The new init flow guides you through setup with context-appropriate options and cleaner output.

  **New Workflow Selection**
  - Clear framing: "You need a plan before you execute. How do you want to build it?"
  - **Solo (Taskmaster)**: Parse PRD → structured tasks → AI agent executes with control
  - **Together (Hamster)**: Team writes brief → Hamster refines → aligned execution with Taskmaster

  **Cleaner Experience**
  - Optional AI IDE rules setup (Y/n prompt instead of always showing)
  - 15+ log messages moved to debug level - much less noise
  - Skip Git prompts when using Hamster (not needed for cloud storage)
  - Skip AI model configuration for Hamster (uses Hamster's AI)

  **Hamster Integration**
  - OAuth login flow when choosing Hamster workflow
  - Context-aware guidance based on your workflow choice

  **Quality of Life**
  - Run `tm rules --setup` anytime if you declined during init
  - Use `--yes` flag for fully non-interactive setup
  - Use `--rules cursor,windsurf` to specify rules upfront

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Introduce `tm export` command - bring Task Master to your team

  Share your task plans with teammates by exporting local tasks to collaborative briefs on Hamster. Select which tags to export, invite team members, and start collaborating instantly.

  **New `tm export` Command**
  - Export your local tasks to shareable team briefs
  - Hamster will reverse engineer your PRD based on your tasks (reverse parse prd!)
  - Select multiple tags to export in one go, import all tasks across tags to Hamster
  - Hamster will generate brief titles and descriptions from your task content
  - Automatically sets your CLI context to the new brief
  - All AI calls handled by Hamster, zero API keys needed - just a Hamster account!

  **Team Collaboration**
  - Invite teammates during export with `-I, --invite` flag
  - Add up to 10 team members by email
  - See invitation status: sent, already a member, or error

  **Quality of Life Improvements**
  - New `tm login` / `tm logout` shortcuts
  - Display ID shortcuts: `tm show ham31` now works (normalizes to HAM-31)
  - Better task rendering with proper HTML/Markdown support

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add simpler positional syntax and Hamster-aware UI improvements
  - **Simpler command syntax**: Use positional arguments without flags
    - `tm update-task 1 Added implementation` (no quotes needed for multi-word prompts)
    - `tm status 1 done` (new alias for set-status) or `tm set-status 1,1.1,2 in-progress`
    - `tm list done` or `tm list in-progress` or `tm list all` (shortcut for --with-subtasks)
  - **Hamster-aware help**: Context-specific command list when connected to Hamster
    - Shows only relevant commands for Hamster workflow
    - Beautiful boxed section headers with improved spacing
    - Clear usage examples with new positional syntax
    - Better visual alignment and cleaner formatting
  - **Progress indicators**: Added loading spinner to `update-task` when connected to Hamster
    - Shows "Updating task X on Hamster..." during AI processing
    - Cleaner, more responsive UX for long-running operations
  - **Improved context display**: Show 'Brief: [name]' instead of 'tag: [name]' when connected to Hamster
  - **Cleaner Hamster updates**: Simplified update display (removed redundant Mode/Prompt info)
  - **Smart messaging**: "NO TASKS AVAILABLE" warning only shows when literally no tasks exist
    - Removed misleading messages when tasks are just completed/in-progress/blocked
    - Better UX for filtered task lists
  - **Updated help everywhere**: Regular help menu now shows new positional argument syntax
    - All suggested actions updated across commands
    - Consistent syntax in all UI components
  - **Auto-detection**: Automatically detects Hamster connection for better UX
  - **Backward compatible**: All old flag syntax still works (`--id`, `--status`, etc.)

### Patch Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Sentry integration for error tracking and AI telemetry monitoring
  - **Sentry Integration**: Added comprehensive error tracking and AI operation monitoring using Sentry with Vercel AI SDK integration
  - **AI Telemetry**: All AI operations (generateText, streamText, generateObject, streamObject) now automatically track spans, token usage, prompts, and responses
  - **MCP Server Instrumentation**: Wrapped FastMCP server with `Sentry.wrapMcpServerWithSentry()` to automatically capture spans for all MCP tool interactions
  - **Privacy Controls**: Added `anonymousTelemetry` config option (default: true) allowing local storage users to opt out of telemetry
  - **Complete Coverage**: Telemetry enabled for all AI commands including parse-prd, expand, update-task, analyze-complexity, and research
  - **Internal Telemetry**: Sentry DSN is hardcoded internally for Task Master's telemetry (not user-configurable)
  - **Dual Initialization**: Automatic Sentry initialization in both CLI (scripts/dev.js) and MCP Server (mcp-server/src/index.js) with full MCP instrumentation

- [#1463](https://github.com/eyaltoledano/claude-task-master/pull/1463) [`55595f6`](https://github.com/eyaltoledano/claude-task-master/commit/55595f680c8b52b5421d3e0c7640bf2050efe44f) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix package issue in earlier rc

## 0.36.0

### Minor Changes

- [#1446](https://github.com/eyaltoledano/claude-task-master/pull/1446) [`2316e94`](https://github.com/eyaltoledano/claude-task-master/commit/2316e94b288915bb906e1a61a87f59e291594fef) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Bring back `task-master generate` as a command and mcp tool (after popular demand)
  - Generated files are now `.md` instead of `.txt`
    - They also follow the markdownlint format making them look like more standard md files
  - added parameters to generate allowing you to generate with the `--tag` flag
    - If I am on an active tag and want to generate files from another tag, I can with the tag parameter
  - See `task-master generate --help` for more information.

- [#1454](https://github.com/eyaltoledano/claude-task-master/pull/1454) [`38ff7eb`](https://github.com/eyaltoledano/claude-task-master/commit/38ff7ebbc029919ea4cd5257573efbf1ea2f0eeb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Hamster rules to task-master rules

## 0.36.0

### Minor Changes

- [#1446](https://github.com/eyaltoledano/claude-task-master/pull/1446) [`2316e94`](https://github.com/eyaltoledano/claude-task-master/commit/2316e94b288915bb906e1a61a87f59e291594fef) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Bring back `task-master generate` as a command and mcp tool (after popular demand)
  - Generated files are now `.md` instead of `.txt`
    - They also follow the markdownlint format making them look like more standard md files
  - added parameters to generate allowing you to generate with the `--tag` flag
    - If I am on an active tag and want to generate files from another tag, I can with the tag parameter
  - See `task-master generate --help` for more information.

- [#1454](https://github.com/eyaltoledano/claude-task-master/pull/1454) [`38ff7eb`](https://github.com/eyaltoledano/claude-task-master/commit/38ff7ebbc029919ea4cd5257573efbf1ea2f0eeb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Hamster rules to task-master rules

## 0.36.0-rc.2

### Patch Changes

- [#1463](https://github.com/eyaltoledano/claude-task-master/pull/1463) [`55595f6`](https://github.com/eyaltoledano/claude-task-master/commit/55595f680c8b52b5421d3e0c7640bf2050efe44f) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix package issue in earlier rc

## 0.36.0-rc.1

### Minor Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Hamster integration for `parse-prd` command

  Your tasks are only as good as the context behind them. Now when you run `parse-prd`, you can choose to bring your PRD to Hamster instead of parsing locally.

  **New Workflow Choice**
  - **Parse locally**: PRD becomes a task list in a local JSON file - great for quick prototyping and vibing solo
  - **Bring it to Hamster**: PRD becomes a living brief connected to your team, codebase, and agents

  **Why Hamster?**
  - Tasks live in a central place with real-time sync across your team
  - Collaborate on your PRD/brief together, generate tasks on Hamster, bring them into Taskmaster
  - No API keys needed - Hamster handles all AI inference, just need a Hamster account

  **Hamster Integration**
  - OAuth login flow when choosing Hamster (same as export command)
  - Create brief directly from PRD content with auto-generated title/description
  - Progress bar showing task generation phases (analyzing → generating → processing)
  - Invite teammates during brief creation
  - Auto-set context to new brief when complete

  **Quality of Life**
  - Clickable brief URL and team invite URL in terminal
  - Shows task count as they're generated
  - Graceful fallback if generation takes longer than expected

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Redesign `tm init` with clearer workflow selection and reduced noise

  Choose how you want to plan: Solo with Taskmaster or Together with Hamster. The new init flow guides you through setup with context-appropriate options and cleaner output.

  **New Workflow Selection**
  - Clear framing: "You need a plan before you execute. How do you want to build it?"
  - **Solo (Taskmaster)**: Parse PRD → structured tasks → AI agent executes with control
  - **Together (Hamster)**: Team writes brief → Hamster refines → aligned execution with Taskmaster

  **Cleaner Experience**
  - Optional AI IDE rules setup (Y/n prompt instead of always showing)
  - 15+ log messages moved to debug level - much less noise
  - Skip Git prompts when using Hamster (not needed for cloud storage)
  - Skip AI model configuration for Hamster (uses Hamster's AI)

  **Hamster Integration**
  - OAuth login flow when choosing Hamster workflow
  - Context-aware guidance based on your workflow choice

  **Quality of Life**
  - Run `tm rules --setup` anytime if you declined during init
  - Use `--yes` flag for fully non-interactive setup
  - Use `--rules cursor,windsurf` to specify rules upfront

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Introduce `tm export` command - bring Task Master to your team

  Share your task plans with teammates by exporting local tasks to collaborative briefs on Hamster. Select which tags to export, invite team members, and start collaborating instantly.

  **New `tm export` Command**
  - Export your local tasks to shareable team briefs
  - Hamster will reverse engineer your PRD based on your tasks (reverse parse prd!)
  - Select multiple tags to export in one go, import all tasks across tags to Hamster
  - Hamster will generate brief titles and descriptions from your task content
  - Automatically sets your CLI context to the new brief
  - All AI calls handled by Hamster, zero API keys needed - just a Hamster account!

  **Team Collaboration**
  - Invite teammates during export with `-I, --invite` flag
  - Add up to 10 team members by email
  - See invitation status: sent, already a member, or error

  **Quality of Life Improvements**
  - New `tm login` / `tm logout` shortcuts
  - Display ID shortcuts: `tm show ham31` now works (normalizes to HAM-31)
  - Better task rendering with proper HTML/Markdown support

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add simpler positional syntax and Hamster-aware UI improvements
  - **Simpler command syntax**: Use positional arguments without flags
    - `tm update-task 1 Added implementation` (no quotes needed for multi-word prompts)
    - `tm status 1 done` (new alias for set-status) or `tm set-status 1,1.1,2 in-progress`
    - `tm list done` or `tm list in-progress` or `tm list all` (shortcut for --with-subtasks)
  - **Hamster-aware help**: Context-specific command list when connected to Hamster
    - Shows only relevant commands for Hamster workflow
    - Beautiful boxed section headers with improved spacing
    - Clear usage examples with new positional syntax
    - Better visual alignment and cleaner formatting
  - **Progress indicators**: Added loading spinner to `update-task` when connected to Hamster
    - Shows "Updating task X on Hamster..." during AI processing
    - Cleaner, more responsive UX for long-running operations
  - **Improved context display**: Show 'Brief: [name]' instead of 'tag: [name]' when connected to Hamster
  - **Cleaner Hamster updates**: Simplified update display (removed redundant Mode/Prompt info)
  - **Smart messaging**: "NO TASKS AVAILABLE" warning only shows when literally no tasks exist
    - Removed misleading messages when tasks are just completed/in-progress/blocked
    - Better UX for filtered task lists
  - **Updated help everywhere**: Regular help menu now shows new positional argument syntax
    - All suggested actions updated across commands
    - Consistent syntax in all UI components
  - **Auto-detection**: Automatically detects Hamster connection for better UX
  - **Backward compatible**: All old flag syntax still works (`--id`, `--status`, etc.)

### Patch Changes

- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452) [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add Sentry integration for error tracking and AI telemetry monitoring
  - **Sentry Integration**: Added comprehensive error tracking and AI operation monitoring using Sentry with Vercel AI SDK integration
  - **AI Telemetry**: All AI operations (generateText, streamText, generateObject, streamObject) now automatically track spans, token usage, prompts, and responses
  - **MCP Server Instrumentation**: Wrapped FastMCP server with `Sentry.wrapMcpServerWithSentry()` to automatically capture spans for all MCP tool interactions
  - **Privacy Controls**: Added `anonymousTelemetry` config option (default: true) allowing local storage users to opt out of telemetry
  - **Complete Coverage**: Telemetry enabled for all AI commands including parse-prd, expand, update-task, analyze-complexity, and research
  - **Internal Telemetry**: Sentry DSN is hardcoded internally for Task Master's telemetry (not user-configurable)
  - **Dual Initialization**: Automatic Sentry initialization in both CLI (scripts/dev.js) and MCP Server (mcp-server/src/index.js) with full MCP instrumentation

## 0.36.0-rc.0

### Minor Changes

- [#1446](https://github.com/eyaltoledano/claude-task-master/pull/1446) [`2316e94`](https://github.com/eyaltoledano/claude-task-master/commit/2316e94b288915bb906e1a61a87f59e291594fef) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Bring back `task-master generate` as a command and mcp tool (after popular demand)
  - Generated files are now `.md` instead of `.txt`
    - They also follow the markdownlint format making them look like more standard md files
  - added parameters to generate allowing you to generate with the `--tag` flag
    - If I am on an active tag and want to generate files from another tag, I can with the tag parameter
  - See `task-master generate --help` for more information.

- [#1454](https://github.com/eyaltoledano/claude-task-master/pull/1454) [`38ff7eb`](https://github.com/eyaltoledano/claude-task-master/commit/38ff7ebbc029919ea4cd5257573efbf1ea2f0eeb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Hamster rules to task-master rules

## 0.35.0

### Minor Changes

- [#1437](https://github.com/eyaltoledano/claude-task-master/pull/1437) [`783398e`](https://github.com/eyaltoledano/claude-task-master/commit/783398ecdf71432bd2b97f400756acbcfd60fbef) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Upgrade gemini-cli provider to native structured output support
  - Upgrade `ai-sdk-provider-gemini-cli` from v1.1.1 to v1.4.0 with native `responseJsonSchema` support
  - Simplify provider implementation by removing JSON extraction workarounds (652 lines → 95 lines)
  - Enable native structured output via Gemini API's schema enforcement

- [#1440](https://github.com/eyaltoledano/claude-task-master/pull/1440) [`9f6f3af`](https://github.com/eyaltoledano/claude-task-master/commit/9f6f3affe322512a8708624850c144b4b890e782) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for opus 4.1 and opus 4.5 anthropic models

### Patch Changes

- [#1440](https://github.com/eyaltoledano/claude-task-master/pull/1440) [`9f6f3af`](https://github.com/eyaltoledano/claude-task-master/commit/9f6f3affe322512a8708624850c144b4b890e782) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Correct swe scores of haiku 4.5 and sonnet 4.5

- [#1436](https://github.com/eyaltoledano/claude-task-master/pull/1436) [`c1df63d`](https://github.com/eyaltoledano/claude-task-master/commit/c1df63d7229f05b57abba4af11e74a8d2bc6dcd9) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Upgrade ai-sdk-provider-claude-code to v2.2.0 for native structured outputs support.

## 0.34.0

### Minor Changes

- [#1425](https://github.com/eyaltoledano/claude-task-master/pull/1425) [`99d9179`](https://github.com/eyaltoledano/claude-task-master/commit/99d9179522dc66797ec7e3f428d72b46a9557f09) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Deprecated generate command

## 0.33.0

### Minor Changes

- [#1427](https://github.com/eyaltoledano/claude-task-master/pull/1427) [`122c23a`](https://github.com/eyaltoledano/claude-task-master/commit/122c23abb36634c1e68c476d681f41b4b4991671) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added Gemini 3 pro preview to supported Taskmaster AI providers
  - Added to Google providers
  - Added to Gemini CLI providers
    - Attention: Gemini 3 Pro is available for:
      - Google AI Ultra Subscribers
      - Users who have access via a paid Gemini API key
        - If you want to use the gemini api key, make sure you have this defined in your .env or mcp.json env variables: `GEMINI_API_KEY=xxxx`

## 0.32.2

### Patch Changes

- [#1421](https://github.com/eyaltoledano/claude-task-master/pull/1421) [`e75946b`](https://github.com/eyaltoledano/claude-task-master/commit/e75946b1a998269e6a751d2b5baf5c3b7e9b9f46) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Upgrade fastmcp dependency to solve `Server does not support completions (required for completion/complete)`
  - This resolves errors where MCP clients (like Cursor) failed to connect to the Task Master MCP server:
    - [#1413](https://github.com/eyaltoledano/claude-task-master/issues/1413)
    - [#1411](https://github.com/eyaltoledano/claude-task-master/issues/1411)

## 0.32.1

### Patch Changes

- [#1396](https://github.com/eyaltoledano/claude-task-master/pull/1396) [`9883e83`](https://github.com/eyaltoledano/claude-task-master/commit/9883e83b78306e55003e960ea072a11048d89ec9) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix box title alignment by adding emoji variant selector to warning sign

## 0.32.0

### Minor Changes

- [#1382](https://github.com/eyaltoledano/claude-task-master/pull/1382) [`ac4328a`](https://github.com/eyaltoledano/claude-task-master/commit/ac4328ae86380c50bb84fff0e98e2370f4ea666f) Thanks [@JJVvV](https://github.com/JJVvV)! - Added opt-in proxy support for all AI providers - respects http_proxy/https_proxy environment variables when enabled.

  When using Task Master in corporate or restricted network environments that require HTTP/HTTPS proxies, API calls to AI providers (OpenAI, Anthropic, Google, AWS Bedrock, etc.) would previously fail with ECONNRESET errors. This update adds seamless proxy support that can be enabled via environment variable or configuration file.

  **How to enable:**

  Proxy support is opt-in. Enable it using either method:

  **Method 1: Environment Variable**

  ```bash
  export TASKMASTER_ENABLE_PROXY=true
  export http_proxy=http://your-proxy:port
  export https_proxy=http://your-proxy:port
  export no_proxy=localhost,127.0.0.1  # Optional: bypass proxy for specific hosts

  # Then use Task Master normally
  task-master add-task "Create a new feature"
  ```

  **Method 2: Configuration File**

  Add to `.taskmaster/config.json`:

  ```json
  {
    "global": {
      "enableProxy": true
    }
  }
  ```

  Then set your proxy environment variables:

  ```bash
  export http_proxy=http://your-proxy:port
  export https_proxy=http://your-proxy:port
  ```

  **Technical details:**
  - Uses undici's `EnvHttpProxyAgent` for automatic proxy detection
  - Centralized implementation in `BaseAIProvider` for consistency across all providers
  - Supports all AI providers: OpenAI, Anthropic, Perplexity, Azure OpenAI, Google AI, Google Vertex AI, AWS Bedrock, and OpenAI-compatible providers
  - Opt-in design ensures users without proxy requirements are not affected
  - Priority: `TASKMASTER_ENABLE_PROXY` environment variable > `config.json` setting

- [#1408](https://github.com/eyaltoledano/claude-task-master/pull/1408) [`10ec025`](https://github.com/eyaltoledano/claude-task-master/commit/10ec0255812dad00aaa72f1b31f41ca978e4451c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add --json back to `task-master list` and `task-master show` for when using the commands with ai agents (less context)

- [#1398](https://github.com/eyaltoledano/claude-task-master/pull/1398) [`e59c16c`](https://github.com/eyaltoledano/claude-task-master/commit/e59c16c707d3ade479a422d8c617004eac1a857f) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Claude Code provider now respects your global, project, and local Claude Code configuration files.

  When using the Claude Code AI provider, Task Master now automatically loads your Claude Code settings from:
  - **Global config** (`~/.claude/` directory) - Your personal preferences across all projects
  - **Project config** (`.claude/` directory) - Project-specific settings like CLAUDE.md instructions
  - **Local config** - Workspace-specific overrides

  This means your CLAUDE.md files, custom instructions, and Claude Code settings will now be properly applied when Task Master uses Claude Code as an AI provider. Previously, these settings were being ignored.

  **What's improved:**
  - ✅ CLAUDE.md files are now automatically loaded and applied (global and local)
  - ✅ Your custom Claude Code settings are respected
  - ✅ Project-specific instructions work as expected
  - ✅ No manual configuration needed - works out of the box

  **Issues:**
  - Resolves #1391
  - Resolves #1315

### Patch Changes

- [#1400](https://github.com/eyaltoledano/claude-task-master/pull/1400) [`c62cf84`](https://github.com/eyaltoledano/claude-task-master/commit/c62cf845dad1960ec183df217293d4edbeea71b9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtasks not showing parent task when displaying in cli (eg. tm show 10)

- [#1393](https://github.com/eyaltoledano/claude-task-master/pull/1393) [`da8ed6a`](https://github.com/eyaltoledano/claude-task-master/commit/da8ed6aa116b9ade3ef4502dd8b8c44727057b5f) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix completion percentage and dependency resolution to treat cancelled tasks as complete. Cancelled tasks now correctly count toward project completion (e.g., 14 done + 1 cancelled = 100%, not 93%) and satisfy dependencies for dependent tasks, preventing permanent blocks.

- [#1407](https://github.com/eyaltoledano/claude-task-master/pull/1407) [`0003b6f`](https://github.com/eyaltoledano/claude-task-master/commit/0003b6fca6b8c9320ee959fb0081eed4ba086b98) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix complexity analysis prompt to ensure consistent JSON output format

- [#1351](https://github.com/eyaltoledano/claude-task-master/pull/1351) [`37aee78`](https://github.com/eyaltoledano/claude-task-master/commit/37aee7809ce753104692b2024eb8b2bb0d376c14) Thanks [@bjcoombs](https://github.com/bjcoombs)! - fix: prioritize .taskmaster in parent directories over other project markers

  When running task-master commands from subdirectories containing other project markers (like .git, go.mod, package.json), findProjectRoot() now correctly finds and uses .taskmaster directories in parent folders instead of stopping at the first generic project marker found.

  This enables multi-repo monorepo setups where a single .taskmaster at the root tracks work across multiple sub-repositories.

- [#1406](https://github.com/eyaltoledano/claude-task-master/pull/1406) [`9079d04`](https://github.com/eyaltoledano/claude-task-master/commit/9079d0417907f468360e8db8dd461abb619609e7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server compatibility with Cursor IDE's latest update by upgrading to fastmcp v3.20.1 with Zod v4 support
  - This resolves connection failures where the MCP server was unable to establish proper capability negotiation.
  - Issue typically included wording like: `Server does not support completions`

## 0.32.0-rc.0

### Minor Changes

- [#1398](https://github.com/eyaltoledano/claude-task-master/pull/1398) [`e59c16c`](https://github.com/eyaltoledano/claude-task-master/commit/e59c16c707d3ade479a422d8c617004eac1a857f) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Claude Code provider now respects your global, project, and local Claude Code configuration files.

  When using the Claude Code AI provider, Task Master now automatically loads your Claude Code settings from:
  - **Global config** (`~/.claude/` directory) - Your personal preferences across all projects
  - **Project config** (`.claude/` directory) - Project-specific settings like CLAUDE.md instructions
  - **Local config** - Workspace-specific overrides

  This means your CLAUDE.md files, custom instructions, and Claude Code settings will now be properly applied when Task Master uses Claude Code as an AI provider. Previously, these settings were being ignored.

  **What's improved:**
  - ✅ CLAUDE.md files are now automatically loaded and applied (global and local)
  - ✅ Your custom Claude Code settings are respected
  - ✅ Project-specific instructions work as expected
  - ✅ No manual configuration needed - works out of the box

  **Issues:**
  - Resolves #1391
  - Resolves #1315

### Patch Changes

- [#1400](https://github.com/eyaltoledano/claude-task-master/pull/1400) [`c62cf84`](https://github.com/eyaltoledano/claude-task-master/commit/c62cf845dad1960ec183df217293d4edbeea71b9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtasks not showing parent task when displaying in cli (eg. tm show 10)

- [#1393](https://github.com/eyaltoledano/claude-task-master/pull/1393) [`da8ed6a`](https://github.com/eyaltoledano/claude-task-master/commit/da8ed6aa116b9ade3ef4502dd8b8c44727057b5f) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix completion percentage and dependency resolution to treat cancelled tasks as complete. Cancelled tasks now correctly count toward project completion (e.g., 14 done + 1 cancelled = 100%, not 93%) and satisfy dependencies for dependent tasks, preventing permanent blocks.

- [#1407](https://github.com/eyaltoledano/claude-task-master/pull/1407) [`0003b6f`](https://github.com/eyaltoledano/claude-task-master/commit/0003b6fca6b8c9320ee959fb0081eed4ba086b98) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix complexity analysis prompt to ensure consistent JSON output format

- [#1351](https://github.com/eyaltoledano/claude-task-master/pull/1351) [`37aee78`](https://github.com/eyaltoledano/claude-task-master/commit/37aee7809ce753104692b2024eb8b2bb0d376c14) Thanks [@bjcoombs](https://github.com/bjcoombs)! - fix: prioritize .taskmaster in parent directories over other project markers

  When running task-master commands from subdirectories containing other project markers (like .git, go.mod, package.json), findProjectRoot() now correctly finds and uses .taskmaster directories in parent folders instead of stopping at the first generic project marker found.

  This enables multi-repo monorepo setups where a single .taskmaster at the root tracks work across multiple sub-repositories.

- [#1406](https://github.com/eyaltoledano/claude-task-master/pull/1406) [`9079d04`](https://github.com/eyaltoledano/claude-task-master/commit/9079d0417907f468360e8db8dd461abb619609e7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server compatibility with Cursor IDE's latest update by upgrading to fastmcp v3.20.1 with Zod v4 support
  - This resolves connection failures where the MCP server was unable to establish proper capability negotiation.
  - Issue typically included wording like: `Server does not support completions`

- [#1382](https://github.com/eyaltoledano/claude-task-master/pull/1382) [`ac4328a`](https://github.com/eyaltoledano/claude-task-master/commit/ac4328ae86380c50bb84fff0e98e2370f4ea666f) Thanks [@JJVvV](https://github.com/JJVvV)! - Added opt-in proxy support for all AI providers - respects http_proxy/https_proxy environment variables when enabled.

  When using Task Master in corporate or restricted network environments that require HTTP/HTTPS proxies, API calls to AI providers (OpenAI, Anthropic, Google, AWS Bedrock, etc.) would previously fail with ECONNRESET errors. This update adds seamless proxy support that can be enabled via environment variable or configuration file.

  **How to enable:**

  Proxy support is opt-in. Enable it using either method:

  **Method 1: Environment Variable**

  ```bash
  export TASKMASTER_ENABLE_PROXY=true
  export http_proxy=http://your-proxy:port
  export https_proxy=http://your-proxy:port
  export no_proxy=localhost,127.0.0.1  # Optional: bypass proxy for specific hosts

  # Then use Task Master normally
  task-master add-task "Create a new feature"
  ```

  **Method 2: Configuration File**

  Add to `.taskmaster/config.json`:

  ```json
  {
    "global": {
      "enableProxy": true
    }
  }
  ```

  Then set your proxy environment variables:

  ```bash
  export http_proxy=http://your-proxy:port
  export https_proxy=http://your-proxy:port
  ```

  **Technical details:**
  - Uses undici's `EnvHttpProxyAgent` for automatic proxy detection
  - Centralized implementation in `BaseAIProvider` for consistency across all providers
  - Supports all AI providers: OpenAI, Anthropic, Perplexity, Azure OpenAI, Google AI, Google Vertex AI, AWS Bedrock, and OpenAI-compatible providers
  - Opt-in design ensures users without proxy requirements are not affected
  - Priority: `TASKMASTER_ENABLE_PROXY` environment variable > `config.json` setting

- [#1408](https://github.com/eyaltoledano/claude-task-master/pull/1408) [`10ec025`](https://github.com/eyaltoledano/claude-task-master/commit/10ec0255812dad00aaa72f1b31f41ca978e4451c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add --json back to `task-master list` and `task-master show` for when using the commands with ai agents (less context)

## 0.31.2

### Patch Changes

- [#1377](https://github.com/eyaltoledano/claude-task-master/pull/1377) [`3c22875`](https://github.com/eyaltoledano/claude-task-master/commit/3c22875efeb5d21754d447a9559817bc5327a234) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix parse-prd schema to accept responses from models that omit optional fields (like Z.ai/GLM). Changed `metadata` field to use union pattern with `.default(null)` for better structured outputs compatibility.

- [#1377](https://github.com/eyaltoledano/claude-task-master/pull/1377) [`3c22875`](https://github.com/eyaltoledano/claude-task-master/commit/3c22875efeb5d21754d447a9559817bc5327a234) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix ai response not showing price after its json was repaired

- [#1377](https://github.com/eyaltoledano/claude-task-master/pull/1377) [`3c22875`](https://github.com/eyaltoledano/claude-task-master/commit/3c22875efeb5d21754d447a9559817bc5327a234) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enable structured outputs for Z.ai providers. Added `supportsStructuredOutputs: true` to use `json_schema` mode for more reliable JSON generation in operations like parse-prd.

## 0.31.1

### Patch Changes

- [#1370](https://github.com/eyaltoledano/claude-task-master/pull/1370) [`9c3b273`](https://github.com/eyaltoledano/claude-task-master/commit/9c3b2737dd224e788b197f41df644ea0a6f4cfe2) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for ZAI (GLM) Coding Plan subscription endpoint as a separate provider. Users can now select between two ZAI providers:
  - **zai**: Standard ZAI endpoint (`https://api.z.ai/api/paas/v4/`)
  - **zai-coding**: Coding Plan endpoint (`https://api.z.ai/api/coding/paas/v4/`)

  Both providers use the same model IDs (glm-4.6, glm-4.5) but route to different API endpoints based on your subscription. When running `tm models --setup`, you'll see both providers listed separately:
  - `zai / glm-4.6` - Standard endpoint
  - `zai-coding / glm-4.6` - Coding Plan endpoint

- [#1371](https://github.com/eyaltoledano/claude-task-master/pull/1371) [`abf46b8`](https://github.com/eyaltoledano/claude-task-master/commit/abf46b8087c2f32466a71d057415bab315e35567) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improved auto-update experience:
  - updates now happen before your CLI command runs and automatically restart to execute your command with the new version.
  - No more manual restarts needed!

## 0.31.0

### Minor Changes

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for custom OpenAI-compatible providers, allowing you to connect Task Master to any service that implements the OpenAI API specification

  **How to use:**

  Configure your custom provider with the `models` command:

  ```bash
  task-master models --set-main <your-model-id> --openai-compatible --baseURL <your-api-endpoint>
  ```

  Example:

  ```bash
  task-master models --set-main llama-3-70b --openai-compatible --baseURL http://localhost:8000/v1
  # Or for an interactive view
  task-master models --setup
  ```

  Set your API key (if required by your provider) in mcp.json, your .env file or in your env exports:

  ```bash
  OPENAI_COMPATIBLE_API_KEY="your-key-here"
  ```

  This gives you the flexibility to use virtually any LLM service with Task Master, whether it's self-hosted, a specialized provider, or a custom inference server.

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add native support for Z.ai (GLM models), giving you access to high-performance Chinese models including glm-4.6 with massive 200K+ token context windows at competitive pricing

  **How to use:**
  1. Get your Z.ai API key from <https://z.ai/manage-apikey/apikey-list>
  2. Set your API key in .env, mcp.json or in env exports:

     ```bash
     ZAI_API_KEY="your-key-here"
     ```

  3. Configure Task Master to use GLM models:

     ```bash
     task-master models --set-main glm-4.6
     # Or for an interactive view
     task-master models --setup
     ```

  **Available models:**
  - `glm-4.6` - Latest model with 200K+ context, excellent for complex projects
  - `glm-4.5` - Previous generation, still highly capable
  - Additional GLM variants for different use cases: `glm-4.5-air`, `glm-4.5v`

  GLM models offer strong performance on software engineering tasks, with particularly good results on code generation and technical reasoning. The large context window makes them ideal for analyzing entire codebases or working with extensive documentation.

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add LM Studio integration, enabling you to run Task Master completely offline with local models at zero API cost.

  **How to use:**
  1. Download and install [LM Studio](https://lmstudio.ai/)
  2. Launch LM Studio and download a model (e.g., Llama 3.2, Mistral, Qwen)
  3. Optional: Add api key to mcp.json or .env (LMSTUDIO_API_KEY)
  4. Go to the "Local Server" tab and click "Start Server"
  5. Configure Task Master:

     ```bash
     task-master models --set-main <model-name> --lmstudio
     ```

     Example:

     ```bash
     task-master models --set-main llama-3.2-3b --lmstudio
     ```

### Patch Changes

- [#1362](https://github.com/eyaltoledano/claude-task-master/pull/1362) [`3e70edf`](https://github.com/eyaltoledano/claude-task-master/commit/3e70edfa3a1f47bd8a6d2d2a30c20c72f5758b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve parse PRD schema for better llm model compatiblity
  - Fixes #1353

- [#1358](https://github.com/eyaltoledano/claude-task-master/pull/1358) [`0c639bd`](https://github.com/eyaltoledano/claude-task-master/commit/0c639bd1db9d2d9b4c2c22ac60b0d875ba75f80e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask ID display to show full compound notation

  When displaying a subtask via `tm show 104.1`, the header and properties table showed only the subtask's local ID (e.g., "1") instead of the full compound ID (e.g., "104.1"). The CLI now preserves and displays the original requested task ID throughout the display chain, ensuring subtasks are clearly identified with their parent context. Also improved TypeScript typing by using discriminated unions for Task/Subtask returns from `tasks.get()`, eliminating unsafe type coercions.

- [#1339](https://github.com/eyaltoledano/claude-task-master/pull/1339) [`3b09b5d`](https://github.com/eyaltoledano/claude-task-master/commit/3b09b5da2a929f260d275f056d35bb6ded54ca6d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed MCP server sometimes crashing when getting into the commit step of autopilot
  - autopilot now persists state consistently through the whole flow

- [#1326](https://github.com/eyaltoledano/claude-task-master/pull/1326) [`9d5812b`](https://github.com/eyaltoledano/claude-task-master/commit/9d5812ba6725cfadebb8db8f4aa732cf3cdb3a36) Thanks [@SharifMrCreed](https://github.com/SharifMrCreed)! - Improve gemini cli integration

  When initializing Task Master with the `gemini` profile, you now get properly configured context files tailored specifically for Gemini CLI, including MCP configuration and Gemini-specific features like file references, session management, and headless mode.

## 0.31.0-rc.0

### Minor Changes

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for custom OpenAI-compatible providers, allowing you to connect Task Master to any service that implements the OpenAI API specification

  **How to use:**

  Configure your custom provider with the `models` command:

  ```bash
  task-master models --set-main <your-model-id> --openai-compatible --baseURL <your-api-endpoint>
  ```

  Example:

  ```bash
  task-master models --set-main llama-3-70b --openai-compatible --baseURL http://localhost:8000/v1
  # Or for an interactive view
  task-master models --setup
  ```

  Set your API key (if required by your provider) in mcp.json, your .env file or in your env exports:

  ```bash
  OPENAI_COMPATIBLE_API_KEY="your-key-here"
  ```

  This gives you the flexibility to use virtually any LLM service with Task Master, whether it's self-hosted, a specialized provider, or a custom inference server.

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add native support for Z.ai (GLM models), giving you access to high-performance Chinese models including glm-4.6 with massive 200K+ token context windows at competitive pricing

  **How to use:**
  1. Get your Z.ai API key from <https://z.ai/manage-apikey/apikey-list>
  2. Set your API key in .env, mcp.json or in env exports:

     ```bash
     ZAI_API_KEY="your-key-here"
     ```

  3. Configure Task Master to use GLM models:

     ```bash
     task-master models --set-main glm-4.6
     # Or for an interactive view
     task-master models --setup
     ```

  **Available models:**
  - `glm-4.6` - Latest model with 200K+ context, excellent for complex projects
  - `glm-4.5` - Previous generation, still highly capable
  - Additional GLM variants for different use cases: `glm-4.5-air`, `glm-4.5v`

  GLM models offer strong performance on software engineering tasks, with particularly good results on code generation and technical reasoning. The large context window makes them ideal for analyzing entire codebases or working with extensive documentation.

- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360) [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add LM Studio integration, enabling you to run Task Master completely offline with local models at zero API cost.

  **How to use:**
  1. Download and install [LM Studio](https://lmstudio.ai/)
  2. Launch LM Studio and download a model (e.g., Llama 3.2, Mistral, Qwen)
  3. Optional: Add api key to mcp.json or .env (LMSTUDIO_API_KEY)
  4. Go to the "Local Server" tab and click "Start Server"
  5. Configure Task Master:

     ```bash
     task-master models --set-main <model-name> --lmstudio
     ```

     Example:

     ```bash
     task-master models --set-main llama-3.2-3b --lmstudio
     ```

### Patch Changes

- [#1362](https://github.com/eyaltoledano/claude-task-master/pull/1362) [`3e70edf`](https://github.com/eyaltoledano/claude-task-master/commit/3e70edfa3a1f47bd8a6d2d2a30c20c72f5758b9b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve parse PRD schema for better llm model compatiblity
  - Fixes #1353

- [#1358](https://github.com/eyaltoledano/claude-task-master/pull/1358) [`0c639bd`](https://github.com/eyaltoledano/claude-task-master/commit/0c639bd1db9d2d9b4c2c22ac60b0d875ba75f80e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask ID display to show full compound notation

  When displaying a subtask via `tm show 104.1`, the header and properties table showed only the subtask's local ID (e.g., "1") instead of the full compound ID (e.g., "104.1"). The CLI now preserves and displays the original requested task ID throughout the display chain, ensuring subtasks are clearly identified with their parent context. Also improved TypeScript typing by using discriminated unions for Task/Subtask returns from `tasks.get()`, eliminating unsafe type coercions.

- [#1339](https://github.com/eyaltoledano/claude-task-master/pull/1339) [`3b09b5d`](https://github.com/eyaltoledano/claude-task-master/commit/3b09b5da2a929f260d275f056d35bb6ded54ca6d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed MCP server sometimes crashing when getting into the commit step of autopilot
  - autopilot now persists state consistently through the whole flow

- [#1326](https://github.com/eyaltoledano/claude-task-master/pull/1326) [`9d5812b`](https://github.com/eyaltoledano/claude-task-master/commit/9d5812ba6725cfadebb8db8f4aa732cf3cdb3a36) Thanks [@SharifMrCreed](https://github.com/SharifMrCreed)! - Improve gemini cli integration

  When initializing Task Master with the `gemini` profile, you now get properly configured context files tailored specifically for Gemini CLI, including MCP configuration and Gemini-specific features like file references, session management, and headless mode.

## 0.30.2

### Patch Changes

- [#1340](https://github.com/eyaltoledano/claude-task-master/pull/1340) [`d63a40c`](https://github.com/eyaltoledano/claude-task-master/commit/d63a40c6ddc1ed2fe418206a19acd3e9dc27fd99) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve session persistence reliability

## 0.30.1

### Patch Changes

- [#1305](https://github.com/eyaltoledano/claude-task-master/pull/1305) [`a98d96e`](https://github.com/eyaltoledano/claude-task-master/commit/a98d96ef0414833b948672f86da4acc11f700ebb) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix warning message box width to match dashboard box width for consistent UI alignment

- [#1346](https://github.com/eyaltoledano/claude-task-master/pull/1346) [`25addf9`](https://github.com/eyaltoledano/claude-task-master/commit/25addf919f58b439dbc2f6ccf5be822b48280fa3) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - remove file and complexity report parameter from get-tasks and get-task mcp tool
  - In an effort to reduce complexity and context bloat for ai coding agents, we simplified the parameters of these tools

## 0.30.1-rc.0

### Patch Changes

- [#1305](https://github.com/eyaltoledano/claude-task-master/pull/1305) [`a98d96e`](https://github.com/eyaltoledano/claude-task-master/commit/a98d96ef0414833b948672f86da4acc11f700ebb) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix warning message box width to match dashboard box width for consistent UI alignment

## 0.30.0

### Minor Changes

- [#1181](https://github.com/eyaltoledano/claude-task-master/pull/1181) [`a69d8c9`](https://github.com/eyaltoledano/claude-task-master/commit/a69d8c91dc9205a3fdaf9d32276144fa3bcad55d) Thanks [@karol-f](https://github.com/karol-f)! - Add configurable MCP tool loading to optimize LLM context usage

  You can now control which Task Master MCP tools are loaded by setting the `TASK_MASTER_TOOLS` environment variable in your MCP configuration. This helps reduce context usage for LLMs by only loading the tools you need.

  **Configuration Options:**
  - `all` (default): Load all 36 tools
  - `core` or `lean`: Load only 7 essential tools for daily development
    - Includes: `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task`
  - `standard`: Load 15 commonly used tools (all core tools plus 8 more)
    - Additional tools: `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `generate`, `add_task`, `complexity_report`
  - Custom list: Comma-separated tool names (e.g., `get_tasks,next_task,set_task_status`)

  **Example .mcp.json configuration:**

  ```json
  {
    "mcpServers": {
      "task-master-ai": {
        "command": "npx",
        "args": ["-y", "task-master-ai"],
        "env": {
          "TASK_MASTER_TOOLS": "standard",
          "ANTHROPIC_API_KEY": "your_key_here"
        }
      }
    }
  }
  ```

  For complete details on all available tools, configuration examples, and usage guidelines, see the [MCP Tools documentation](https://docs.task-master.dev/capabilities/mcp#configurable-tool-loading).

- [#1312](https://github.com/eyaltoledano/claude-task-master/pull/1312) [`d7fca18`](https://github.com/eyaltoledano/claude-task-master/commit/d7fca1844f24ad8ce079c21d9799a3c4b4413381) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve next command to work with remote

- [#1317](https://github.com/eyaltoledano/claude-task-master/pull/1317) [`548beb4`](https://github.com/eyaltoledano/claude-task-master/commit/548beb434453c69041572eb5927ee7da7075c213) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add 4.5 haiku and sonnet to supported models for claude-code and anthropic ai providers

- [#1309](https://github.com/eyaltoledano/claude-task-master/pull/1309) [`ccb87a5`](https://github.com/eyaltoledano/claude-task-master/commit/ccb87a516a11f7ec4b03133c8f24f4fd8c3a45fc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add autonomous TDD workflow automation system with new `tm autopilot` commands and MCP tools for AI-driven test-driven development.

  **New CLI Commands:**
  - `tm autopilot start <taskId>` - Initialize TDD workflow
  - `tm autopilot next` - Get next action in workflow
  - `tm autopilot status` - Check workflow progress
  - `tm autopilot complete` - Advance phase with test results
  - `tm autopilot commit` - Save progress with metadata
  - `tm autopilot resume` - Continue from checkpoint
  - `tm autopilot abort` - Cancel workflow

  **New MCP Tools:**
  Seven new autopilot tools for programmatic control: `autopilot_start`, `autopilot_next`, `autopilot_status`, `autopilot_complete_phase`, `autopilot_commit`, `autopilot_resume`, `autopilot_abort`

  **Features:**
  - Complete RED → GREEN → COMMIT cycle enforcement
  - Intelligent commit message generation with metadata
  - Activity logging and state persistence
  - Configurable workflow settings via `.taskmaster/config.json`
  - Comprehensive AI agent integration documentation

  **Documentation:**
  - AI Agent Integration Guide (2,800+ lines)
  - TDD Quick Start Guide
  - Example prompts and integration patterns

  > **Learn more:** [TDD Workflow Quickstart Guide](https://dev.task-master.dev/tdd-workflow/quickstart)

  This release enables AI agents to autonomously execute test-driven development workflows with full state management and recovery capabilities.

### Patch Changes

- [#1314](https://github.com/eyaltoledano/claude-task-master/pull/1314) [`6bc75c0`](https://github.com/eyaltoledano/claude-task-master/commit/6bc75c0ac68b59cb10cee70574a689f83e4de768) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve auth token refresh flow

- [#1302](https://github.com/eyaltoledano/claude-task-master/pull/1302) [`3283506`](https://github.com/eyaltoledano/claude-task-master/commit/3283506444d59896ecb97721ef2e96e290eb84d3) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Enable Task Master commands to traverse parent directories to find project root from nested paths

  Fixes #1301

- [#1323](https://github.com/eyaltoledano/claude-task-master/pull/1323) [`dc6652c`](https://github.com/eyaltoledano/claude-task-master/commit/dc6652ccd2b50b91eb55d92899ebf70c7b4d6601) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server compatibility with Draft-07 clients (Augment IDE, gemini-cli, gemini code assist)
  - Resolves #1284

  **Problem:**
  - MCP tools were using Zod v4, which outputs JSON Schema Draft 2020-12
  - MCP clients only support Draft-07
  - Tools were not discoverable in gemini-cli and other clients

  **Solution:**
  - Updated all MCP tools to import from `zod/v3` instead of `zod`
  - Zod v3 schemas convert to Draft-07 via FastMCP's zod-to-json-schema
  - Fixed logger to use stderr instead of stdout (MCP protocol requirement)

  This is a temporary workaround until FastMCP adds JSON Schema version configuration.

## 0.30.0-rc.1

### Minor Changes

- [#1317](https://github.com/eyaltoledano/claude-task-master/pull/1317) [`548beb4`](https://github.com/eyaltoledano/claude-task-master/commit/548beb434453c69041572eb5927ee7da7075c213) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add 4.5 haiku and sonnet to supported models for claude-code and anthropic ai providers

- [#1309](https://github.com/eyaltoledano/claude-task-master/pull/1309) [`ccb87a5`](https://github.com/eyaltoledano/claude-task-master/commit/ccb87a516a11f7ec4b03133c8f24f4fd8c3a45fc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add autonomous TDD workflow automation system with new `tm autopilot` commands and MCP tools for AI-driven test-driven development.

  **New CLI Commands:**
  - `tm autopilot start <taskId>` - Initialize TDD workflow
  - `tm autopilot next` - Get next action in workflow
  - `tm autopilot status` - Check workflow progress
  - `tm autopilot complete` - Advance phase with test results
  - `tm autopilot commit` - Save progress with metadata
  - `tm autopilot resume` - Continue from checkpoint
  - `tm autopilot abort` - Cancel workflow

  **New MCP Tools:**
  Seven new autopilot tools for programmatic control: `autopilot_start`, `autopilot_next`, `autopilot_status`, `autopilot_complete_phase`, `autopilot_commit`, `autopilot_resume`, `autopilot_abort`

  **Features:**
  - Complete RED → GREEN → COMMIT cycle enforcement
  - Intelligent commit message generation with metadata
  - Activity logging and state persistence
  - Configurable workflow settings via `.taskmaster/config.json`
  - Comprehensive AI agent integration documentation

  **Documentation:**
  - AI Agent Integration Guide (2,800+ lines)
  - TDD Quick Start Guide
  - Example prompts and integration patterns

  > **Learn more:** [TDD Workflow Quickstart Guide](https://dev.task-master.dev/tdd-workflow/quickstart)

  This release enables AI agents to autonomously execute test-driven development workflows with full state management and recovery capabilities.

### Patch Changes

- [#1323](https://github.com/eyaltoledano/claude-task-master/pull/1323) [`dc6652c`](https://github.com/eyaltoledano/claude-task-master/commit/dc6652ccd2b50b91eb55d92899ebf70c7b4d6601) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server compatibility with Draft-07 clients (Augment IDE, gemini-cli, gemini code assist)
  - Resolves #1284

  **Problem:**
  - MCP tools were using Zod v4, which outputs JSON Schema Draft 2020-12
  - MCP clients only support Draft-07
  - Tools were not discoverable in gemini-cli and other clients

  **Solution:**
  - Updated all MCP tools to import from `zod/v3` instead of `zod`
  - Zod v3 schemas convert to Draft-07 via FastMCP's zod-to-json-schema
  - Fixed logger to use stderr instead of stdout (MCP protocol requirement)

  This is a temporary workaround until FastMCP adds JSON Schema version configuration.

## 0.30.0-rc.0

### Minor Changes

- [#1181](https://github.com/eyaltoledano/claude-task-master/pull/1181) [`a69d8c9`](https://github.com/eyaltoledano/claude-task-master/commit/a69d8c91dc9205a3fdaf9d32276144fa3bcad55d) Thanks [@karol-f](https://github.com/karol-f)! - Add configurable MCP tool loading to optimize LLM context usage

  You can now control which Task Master MCP tools are loaded by setting the `TASK_MASTER_TOOLS` environment variable in your MCP configuration. This helps reduce context usage for LLMs by only loading the tools you need.

  **Configuration Options:**
  - `all` (default): Load all 36 tools
  - `core` or `lean`: Load only 7 essential tools for daily development
    - Includes: `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task`
  - `standard`: Load 15 commonly used tools (all core tools plus 8 more)
    - Additional tools: `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `generate`, `add_task`, `complexity_report`
  - Custom list: Comma-separated tool names (e.g., `get_tasks,next_task,set_task_status`)

  **Example .mcp.json configuration:**

  ```json
  {
    "mcpServers": {
      "task-master-ai": {
        "command": "npx",
        "args": ["-y", "task-master-ai"],
        "env": {
          "TASK_MASTER_TOOLS": "standard",
          "ANTHROPIC_API_KEY": "your_key_here"
        }
      }
    }
  }
  ```

  For complete details on all available tools, configuration examples, and usage guidelines, see the [MCP Tools documentation](https://docs.task-master.dev/capabilities/mcp#configurable-tool-loading).

- [#1312](https://github.com/eyaltoledano/claude-task-master/pull/1312) [`d7fca18`](https://github.com/eyaltoledano/claude-task-master/commit/d7fca1844f24ad8ce079c21d9799a3c4b4413381) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve next command to work with remote

### Patch Changes

- [#1314](https://github.com/eyaltoledano/claude-task-master/pull/1314) [`6bc75c0`](https://github.com/eyaltoledano/claude-task-master/commit/6bc75c0ac68b59cb10cee70574a689f83e4de768) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve auth token refresh flow

- [#1302](https://github.com/eyaltoledano/claude-task-master/pull/1302) [`3283506`](https://github.com/eyaltoledano/claude-task-master/commit/3283506444d59896ecb97721ef2e96e290eb84d3) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Enable Task Master commands to traverse parent directories to find project root from nested paths

  Fixes #1301

## 0.29.0

### Minor Changes

- [#1286](https://github.com/eyaltoledano/claude-task-master/pull/1286) [`f12a16d`](https://github.com/eyaltoledano/claude-task-master/commit/f12a16d09649f62148515f11f616157c7d0bd2d5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add changelog highlights to auto-update notifications

  When the CLI auto-updates to a new version, it now displays a "What's New" section.

- [#1293](https://github.com/eyaltoledano/claude-task-master/pull/1293) [`3010b90`](https://github.com/eyaltoledano/claude-task-master/commit/3010b90d98f3a7d8636caa92fc33d6ee69d4bed0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code plugin with marketplace distribution

  This release introduces official Claude Code plugin support, marking the evolution from legacy `.claude` directory copying to a modern plugin-based architecture.

  ## 🎉 New: Claude Code Plugin

  Task Master AI commands and agents are now distributed as a proper Claude Code plugin:
  - **49 slash commands** with clean naming (`/taskmaster:command-name`)
  - **3 specialized AI agents** (task-orchestrator, task-executor, task-checker)
  - **MCP server integration** for deep Claude Code integration

  **Installation:**

  ```bash
  /plugin marketplace add eyaltoledano/claude-task-master
  /plugin install taskmaster@taskmaster
  ```

  ### The `rules add claude` command no longer copies commands and agents to `.claude/commands/` and `.claude/agents/`. Instead, it now
  - Shows plugin installation instructions
  - Only manages CLAUDE.md imports for agent instructions
  - Directs users to install the official plugin

  **Migration for Existing Users:**

  If you previously used `rules add claude`:
  1. The old commands in `.claude/commands/` will continue to work but won't receive updates
  2. Install the plugin for the latest features: `/plugin install taskmaster@taskmaster`
  3. remove old `.claude/commands/` and `.claude/agents/` directories

  **Why This Change?**

  Claude Code plugins provide:
  - ✅ Automatic updates when we release new features
  - ✅ Better command organization and naming
  - ✅ Seamless integration with Claude Code
  - ✅ No manual file copying or management

  The plugin system is the future of Task Master AI integration with Claude Code!

- [#1285](https://github.com/eyaltoledano/claude-task-master/pull/1285) [`2a910a4`](https://github.com/eyaltoledano/claude-task-master/commit/2a910a40bac375f9f61d797bf55597303d556b48) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add RPG (Repository Planning Graph) method template for structured PRD creation. The new `example_prd_rpg.txt` template teaches AI agents and developers the RPG methodology through embedded instructions, inline good/bad examples, and XML-style tags for structure. This template enables creation of dependency-aware PRDs that automatically generate topologically-ordered task graphs when parsed with Task Master.

  Key features:
  - Method-as-template: teaches RPG principles (dual-semantics, explicit dependencies, topological order) while being used
  - Inline instructions at decision points guide AI through each section
  - Good/bad examples for immediate pattern matching
  - Flexible plain-text format with XML-style tags for parseability
  - Critical dependency-graph section ensures correct task ordering
  - Automatic inclusion during `task-master init`
  - Comprehensive documentation at [docs.task-master.dev/capabilities/rpg-method](https://docs.task-master.dev/capabilities/rpg-method)
  - Tool recommendations for code-context-aware PRD creation (Claude Code, Cursor, Gemini CLI, Codex/Grok)

  The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains.

- [#1287](https://github.com/eyaltoledano/claude-task-master/pull/1287) [`90e6bdc`](https://github.com/eyaltoledano/claude-task-master/commit/90e6bdcf1c59f65ad27fcdfe3b13b9dca7e77654) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.

  The expand-all operation now automatically leverages recommendations from `analyze-complexity` to determine optimal subtask counts for each task, resulting in more accurate and context-aware task breakdowns.

  Key improvements:
  - Automatic integration with complexity analysis reports
  - Tag-aware complexity report path resolution
  - Intelligent subtask count determination based on task complexity
  - Falls back to defaults when complexity analysis is unavailable
  - Enhanced logging for better visibility into expansion decisions

  When you run `task-master expand --all` after `task-master analyze-complexity`, Task Master now uses the recommended subtask counts from the complexity analysis instead of applying uniform defaults, ensuring each task is broken down according to its actual complexity.

### Patch Changes

- [#1191](https://github.com/eyaltoledano/claude-task-master/pull/1191) [`aaf903f`](https://github.com/eyaltoledano/claude-task-master/commit/aaf903ff2f606c779a22e9a4b240ab57b3683815) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix cross-level task dependencies not being saved

  Fixes an issue where adding dependencies between subtasks and top-level tasks (e.g., `task-master add-dependency --id=2.2 --depends-on=11`) would report success but fail to persist the changes. Dependencies can now be created in both directions between any task levels.

- [#1299](https://github.com/eyaltoledano/claude-task-master/pull/1299) [`4c1ef2c`](https://github.com/eyaltoledano/claude-task-master/commit/4c1ef2ca94411c53bcd2a78ec710b06c500236dd) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve refresh token when authenticating

## 0.29.0-rc.1

### Patch Changes

- [#1299](https://github.com/eyaltoledano/claude-task-master/pull/1299) [`a6c5152`](https://github.com/eyaltoledano/claude-task-master/commit/a6c5152f20edd8717cf1aea34e7c178b1261aa99) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve refresh token when authenticating

## 0.29.0-rc.0

### Minor Changes

- [#1286](https://github.com/eyaltoledano/claude-task-master/pull/1286) [`f12a16d`](https://github.com/eyaltoledano/claude-task-master/commit/f12a16d09649f62148515f11f616157c7d0bd2d5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add changelog highlights to auto-update notifications

  When the CLI auto-updates to a new version, it now displays a "What's New" section.

- [#1293](https://github.com/eyaltoledano/claude-task-master/pull/1293) [`3010b90`](https://github.com/eyaltoledano/claude-task-master/commit/3010b90d98f3a7d8636caa92fc33d6ee69d4bed0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code plugin with marketplace distribution

  This release introduces official Claude Code plugin support, marking the evolution from legacy `.claude` directory copying to a modern plugin-based architecture.

  ## 🎉 New: Claude Code Plugin

  Task Master AI commands and agents are now distributed as a proper Claude Code plugin:
  - **49 slash commands** with clean naming (`/task-master-ai:command-name`)
  - **3 specialized AI agents** (task-orchestrator, task-executor, task-checker)
  - **MCP server integration** for deep Claude Code integration

  **Installation:**

  ```bash
  /plugin marketplace add eyaltoledano/claude-task-master
  /plugin install taskmaster@taskmaster
  ```

  ### The `rules add claude` command no longer copies commands and agents to `.claude/commands/` and `.claude/agents/`. Instead, it now
  - Shows plugin installation instructions
  - Only manages CLAUDE.md imports for agent instructions
  - Directs users to install the official plugin

  **Migration for Existing Users:**

  If you previously used `rules add claude`:
  1. The old commands in `.claude/commands/` will continue to work but won't receive updates
  2. Install the plugin for the latest features: `/plugin install taskmaster@taskmaster`
  3. remove old `.claude/commands/` and `.claude/agents/` directories

  **Why This Change?**

  Claude Code plugins provide:
  - ✅ Automatic updates when we release new features
  - ✅ Better command organization and naming
  - ✅ Seamless integration with Claude Code
  - ✅ No manual file copying or management

  The plugin system is the future of Task Master AI integration with Claude Code!

- [#1285](https://github.com/eyaltoledano/claude-task-master/pull/1285) [`2a910a4`](https://github.com/eyaltoledano/claude-task-master/commit/2a910a40bac375f9f61d797bf55597303d556b48) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add RPG (Repository Planning Graph) method template for structured PRD creation. The new `example_prd_rpg.txt` template teaches AI agents and developers the RPG methodology through embedded instructions, inline good/bad examples, and XML-style tags for structure. This template enables creation of dependency-aware PRDs that automatically generate topologically-ordered task graphs when parsed with Task Master.

  Key features:
  - Method-as-template: teaches RPG principles (dual-semantics, explicit dependencies, topological order) while being used
  - Inline instructions at decision points guide AI through each section
  - Good/bad examples for immediate pattern matching
  - Flexible plain-text format with XML-style tags for parseability
  - Critical dependency-graph section ensures correct task ordering
  - Automatic inclusion during `task-master init`
  - Comprehensive documentation at [docs.task-master.dev/capabilities/rpg-method](https://docs.task-master.dev/capabilities/rpg-method)
  - Tool recommendations for code-context-aware PRD creation (Claude Code, Cursor, Gemini CLI, Codex/Grok)

  The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains.

- [#1287](https://github.com/eyaltoledano/claude-task-master/pull/1287) [`90e6bdc`](https://github.com/eyaltoledano/claude-task-master/commit/90e6bdcf1c59f65ad27fcdfe3b13b9dca7e77654) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.

  The expand-all operation now automatically leverages recommendations from `analyze-complexity` to determine optimal subtask counts for each task, resulting in more accurate and context-aware task breakdowns.

  Key improvements:
  - Automatic integration with complexity analysis reports
  - Tag-aware complexity report path resolution
  - Intelligent subtask count determination based on task complexity
  - Falls back to defaults when complexity analysis is unavailable
  - Enhanced logging for better visibility into expansion decisions

  When you run `task-master expand --all` after `task-master analyze-complexity`, Task Master now uses the recommended subtask counts from the complexity analysis instead of applying uniform defaults, ensuring each task is broken down according to its actual complexity.

### Patch Changes

- [#1191](https://github.com/eyaltoledano/claude-task-master/pull/1191) [`aaf903f`](https://github.com/eyaltoledano/claude-task-master/commit/aaf903ff2f606c779a22e9a4b240ab57b3683815) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix cross-level task dependencies not being saved

  Fixes an issue where adding dependencies between subtasks and top-level tasks (e.g., `task-master add-dependency --id=2.2 --depends-on=11`) would report success but fail to persist the changes. Dependencies can now be created in both directions between any task levels.

## 0.28.0

### Minor Changes

- [#1273](https://github.com/eyaltoledano/claude-task-master/pull/1273) [`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add Codex CLI provider with OAuth authentication
  - Added codex-cli provider for GPT-5 and GPT-5-Codex models (272K input / 128K output)
  - OAuth-first authentication via `codex login` - no API key required
  - Optional OPENAI_CODEX_API_KEY support
  - Codebase analysis capabilities automatically enabled
  - Command-specific settings and approval/sandbox modes

- [#1215](https://github.com/eyaltoledano/claude-task-master/pull/1215) [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d) Thanks [@joedanz](https://github.com/joedanz)! - Add Cursor IDE custom slash command support

  Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Move to AI SDK v5:
  - Works better with claude-code and gemini-cli as ai providers
  - Improved openai model family compatibility
  - Migrate ollama provider to v2
  - Closes #1223, #1013, #1161, #1174

- [#1262](https://github.com/eyaltoledano/claude-task-master/pull/1262) [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Migrate AI services to use generateObject for structured data generation

  This update migrates all AI service calls from generateText to generateObject, ensuring more reliable and structured responses across all commands.

  ### Key Changes:
  - **Unified AI Service**: Replaced separate generateText implementations with a single generateObjectService that handles structured data generation
  - **JSON Mode Support**: Added proper JSON mode configuration for providers that support it (OpenAI, Anthropic, Google, Groq)
  - **Schema Validation**: Integrated Zod schemas for all AI-generated content with automatic validation
  - **Provider Compatibility**: Maintained compatibility with all existing providers while leveraging their native structured output capabilities
  - **Improved Reliability**: Structured output generation reduces parsing errors and ensures consistent data formats

  ### Technical Improvements:
  - Centralized provider configuration in `ai-providers-unified.js`
  - Added `generateObject` support detection for each provider
  - Implemented proper error handling for schema validation failures
  - Maintained backward compatibility with existing prompt structures

  ### Bug Fixes:
  - Fixed subtask ID numbering issue where AI was generating inconsistent IDs (101-105, 601-603) instead of sequential numbering (1, 2, 3...)
  - Enhanced prompt instructions to enforce proper ID generation patterns
  - Ensured subtasks display correctly as X.1, X.2, X.3 format

  This migration improves the reliability and consistency of AI-generated content throughout the Task Master application.

- [#1112](https://github.com/eyaltoledano/claude-task-master/pull/1112) [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541) Thanks [@olssonsten](https://github.com/olssonsten)! - Enhanced Roo Code profile with MCP timeout configuration for improved reliability during long-running AI operations. The Roo profile now automatically configures a 300-second timeout for MCP server operations, preventing timeouts during complex tasks like `parse-prd`, `expand-all`, `analyze-complexity`, and `research` operations. This change also replaces static MCP configuration files with programmatic generation for better maintainability.

  **What's New:**
  - 300-second timeout for MCP operations (up from default 60 seconds)
  - Programmatic MCP configuration generation (replaces static asset files)
  - Enhanced reliability for AI-powered operations
  - Consistent with other AI coding assistant profiles

  **Migration:** No user action required - existing Roo Code installations will automatically receive the enhanced MCP configuration on next initialization.

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Upgrade grok-cli ai provider to ai sdk v5

### Patch Changes

- [#1235](https://github.com/eyaltoledano/claude-task-master/pull/1235) [`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve `analyze-complexity` cli docs and `--research` flag documentation

- [#1251](https://github.com/eyaltoledano/claude-task-master/pull/1251) [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Change parent task back to "pending" when all subtasks are in "pending" state

- [#1274](https://github.com/eyaltoledano/claude-task-master/pull/1274) [`4f984f8`](https://github.com/eyaltoledano/claude-task-master/commit/4f984f8a6965da9f9c7edd60ddfd6560ac022917) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Do a quick fix on build

- [#1277](https://github.com/eyaltoledano/claude-task-master/pull/1277) [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations.

- [#1276](https://github.com/eyaltoledano/claude-task-master/pull/1276) [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.

- [#1172](https://github.com/eyaltoledano/claude-task-master/pull/1172) [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d) Thanks [@jujax](https://github.com/jujax)! - Fix Claude Code settings validation for pathToClaudeCodeExecutable

- [#1192](https://github.com/eyaltoledano/claude-task-master/pull/1192) [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a) Thanks [@nukunga](https://github.com/nukunga)! - Fix sonar deep research model failing, should be called `sonar-deep-research`

- [#1270](https://github.com/eyaltoledano/claude-task-master/pull/1270) [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix complexity score not showing for `task-master show` and `task-master list`
  - Added complexity score on "next task" when running `task-master list`
  - Added colors to complexity to reflect complexity (easy, medium, hard)

## 0.28.0-rc.2

### Minor Changes

- [#1273](https://github.com/eyaltoledano/claude-task-master/pull/1273) [`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add Codex CLI provider with OAuth authentication
  - Added codex-cli provider for GPT-5 and GPT-5-Codex models (272K input / 128K output)
  - OAuth-first authentication via `codex login` - no API key required
  - Optional OPENAI_CODEX_API_KEY support
  - Codebase analysis capabilities automatically enabled
  - Command-specific settings and approval/sandbox modes

### Patch Changes

- [#1277](https://github.com/eyaltoledano/claude-task-master/pull/1277) [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations.

- [#1276](https://github.com/eyaltoledano/claude-task-master/pull/1276) [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.

## 0.28.0-rc.1

### Patch Changes

- [#1274](https://github.com/eyaltoledano/claude-task-master/pull/1274) [`4f984f8`](https://github.com/eyaltoledano/claude-task-master/commit/4f984f8a6965da9f9c7edd60ddfd6560ac022917) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Do a quick fix on build

## 0.28.0-rc.0

### Minor Changes

- [#1215](https://github.com/eyaltoledano/claude-task-master/pull/1215) [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d) Thanks [@joedanz](https://github.com/joedanz)! - Add Cursor IDE custom slash command support

  Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Move to AI SDK v5:
  - Works better with claude-code and gemini-cli as ai providers
  - Improved openai model family compatibility
  - Migrate ollama provider to v2
  - Closes #1223, #1013, #1161, #1174

- [#1262](https://github.com/eyaltoledano/claude-task-master/pull/1262) [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Migrate AI services to use generateObject for structured data generation

  This update migrates all AI service calls from generateText to generateObject, ensuring more reliable and structured responses across all commands.

  ### Key Changes:
  - **Unified AI Service**: Replaced separate generateText implementations with a single generateObjectService that handles structured data generation
  - **JSON Mode Support**: Added proper JSON mode configuration for providers that support it (OpenAI, Anthropic, Google, Groq)
  - **Schema Validation**: Integrated Zod schemas for all AI-generated content with automatic validation
  - **Provider Compatibility**: Maintained compatibility with all existing providers while leveraging their native structured output capabilities
  - **Improved Reliability**: Structured output generation reduces parsing errors and ensures consistent data formats

  ### Technical Improvements:
  - Centralized provider configuration in `ai-providers-unified.js`
  - Added `generateObject` support detection for each provider
  - Implemented proper error handling for schema validation failures
  - Maintained backward compatibility with existing prompt structures

  ### Bug Fixes:
  - Fixed subtask ID numbering issue where AI was generating inconsistent IDs (101-105, 601-603) instead of sequential numbering (1, 2, 3...)
  - Enhanced prompt instructions to enforce proper ID generation patterns
  - Ensured subtasks display correctly as X.1, X.2, X.3 format

  This migration improves the reliability and consistency of AI-generated content throughout the Task Master application.

- [#1112](https://github.com/eyaltoledano/claude-task-master/pull/1112) [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541) Thanks [@olssonsten](https://github.com/olssonsten)! - Enhanced Roo Code profile with MCP timeout configuration for improved reliability during long-running AI operations. The Roo profile now automatically configures a 300-second timeout for MCP server operations, preventing timeouts during complex tasks like `parse-prd`, `expand-all`, `analyze-complexity`, and `research` operations. This change also replaces static MCP configuration files with programmatic generation for better maintainability.

  **What's New:**
  - 300-second timeout for MCP operations (up from default 60 seconds)
  - Programmatic MCP configuration generation (replaces static asset files)
  - Enhanced reliability for AI-powered operations
  - Consistent with other AI coding assistant profiles

  **Migration:** No user action required - existing Roo Code installations will automatically receive the enhanced MCP configuration on next initialization.

- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Upgrade grok-cli ai provider to ai sdk v5

### Patch Changes

- [#1235](https://github.com/eyaltoledano/claude-task-master/pull/1235) [`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve `analyze-complexity` cli docs and `--research` flag documentation

- [#1251](https://github.com/eyaltoledano/claude-task-master/pull/1251) [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Change parent task back to "pending" when all subtasks are in "pending" state

- [#1172](https://github.com/eyaltoledano/claude-task-master/pull/1172) [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d) Thanks [@jujax](https://github.com/jujax)! - Fix Claude Code settings validation for pathToClaudeCodeExecutable

- [#1192](https://github.com/eyaltoledano/claude-task-master/pull/1192) [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a) Thanks [@nukunga](https://github.com/nukunga)! - Fix sonar deep research model failing, should be called `sonar-deep-research`

- [#1270](https://github.com/eyaltoledano/claude-task-master/pull/1270) [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix complexity score not showing for `task-master show` and `task-master list`
  - Added complexity score on "next task" when running `task-master list`
  - Added colors to complexity to reflect complexity (easy, medium, hard)

## 0.27.3

### Patch Changes

- [#1254](https://github.com/eyaltoledano/claude-task-master/pull/1254) [`af53525`](https://github.com/eyaltoledano/claude-task-master/commit/af53525cbc660a595b67d4bb90d906911c71f45d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed issue where `tm show` command could not find subtasks using dotted notation IDs (e.g., '8.1').
  - The command now properly searches within parent task subtasks and returns the correct subtask information.

## 0.27.2

### Patch Changes

- [#1248](https://github.com/eyaltoledano/claude-task-master/pull/1248) [`044a7bf`](https://github.com/eyaltoledano/claude-task-master/commit/044a7bfc98049298177bc655cf341d7a8b6a0011) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix set-status for subtasks:
  - Parent tasks are now set as `done` when subtasks are all `done`
  - Parent tasks are now set as `in-progress` when at least one subtask is `in-progress` or `done`

## 0.27.1

### Patch Changes

- [#1232](https://github.com/eyaltoledano/claude-task-master/pull/1232) [`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix module not found for new 0.27.0 release

- [#1233](https://github.com/eyaltoledano/claude-task-master/pull/1233) [`c911608`](https://github.com/eyaltoledano/claude-task-master/commit/c911608f60454253f4e024b57ca84e5a5a53f65c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix Zed MCP configuration by adding required "source" property
  - Add "source": "custom" property to task-master-ai server in Zed settings.json

## 0.27.1-rc.1

### Patch Changes

- [#1233](https://github.com/eyaltoledano/claude-task-master/pull/1233) [`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - One last testing final final

## 0.27.1-rc.0

### Patch Changes

- [#1232](https://github.com/eyaltoledano/claude-task-master/pull/1232) [`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix module not found for new 0.27.0 release

## 0.27.0

### Minor Changes

- [#1220](https://github.com/eyaltoledano/claude-task-master/pull/1220) [`4e12643`](https://github.com/eyaltoledano/claude-task-master/commit/4e126430a092fb54afb035514fb3d46115714f97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - No longer need --package=task-master-ai in mcp server
  - A lot of users were having issues with Taskmaster and usually a simple fix was to remove --package from your mcp.json
  - we now bundle our whole package, so we no longer need the --package

- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add new `task-master start` command for automated task execution with Claude Code
  - You can now start working on tasks directly by running `task-master start <task-id>` which will automatically launch Claude Code with a comprehensive prompt containing all task details, implementation guidelines, and context.
  - `task-master start` will automatically detect next-task when no ID is provided.

- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Move from javascript to typescript, not a full refactor but we now have a typescript environment and are moving our javascript commands slowly into typescript

- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add grok-cli as a provider with full codebase context support. You can now use Grok models (grok-2, grok-3, grok-4, etc.) with Task Master for AI operations that have access to your entire codebase context, enabling more informed task generation and PRD parsing.

  ## Setup Instructions
  1. **Get your Grok API key** from [console.x.ai](https://console.x.ai)
  2. **Set the environment variable**:
     ```bash
     export GROK_CLI_API_KEY="your-api-key-here"
     ```
  3. **Configure Task Master to use Grok**:
     ```bash
     task-master models --set-main grok-beta
     # or
     task-master models --set-research grok-beta
     # or
     task-master models --set-fallback grok-beta
     ```

  ## Key Features
  - **Full codebase context**: Grok models can analyze your entire project when generating tasks or parsing PRDs
  - **xAI model access**: Support for latest Grok models (grok-2, grok-3, grok-4, etc.)
  - **Code-aware task generation**: Create more accurate and contextual tasks based on your actual codebase
  - **Intelligent PRD parsing**: Parse requirements with understanding of your existing code structure

  ## Available Models
  - `grok-beta` - Latest Grok model with codebase context
  - `grok-vision-beta` - Grok with vision capabilities and codebase context

  The Grok CLI provider integrates with xAI's Grok models via grok-cli and can also use the local Grok CLI configuration file (`~/.grok/user-settings.json`) if available.

  ## Credits

  Built using the [grok-cli](https://github.com/superagent-ai/grok-cli) by Superagent AI for seamless integration with xAI's Grok models.

- [#1225](https://github.com/eyaltoledano/claude-task-master/pull/1225) [`a621ff0`](https://github.com/eyaltoledano/claude-task-master/commit/a621ff05eafb51a147a9aabd7b37ddc0e45b0869) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve taskmaster ai provider defaults
  - moving from main anthropic 3.7 to anthropic sonnet 4
  - moving from fallback anthropic 3.5 to anthropic 3.7

- [#1217](https://github.com/eyaltoledano/claude-task-master/pull/1217) [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - @tm/cli: add auto-update functionality to every command

- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix Grok model configuration validation and update deprecated Claude fallback model. Grok models now properly support their full 131K token capacity, and the fallback model has been upgraded to Claude Sonnet 4 for better performance and future compatibility.

## 0.27.0-rc.2

### Minor Changes

- [#1217](https://github.com/eyaltoledano/claude-task-master/pull/1217) [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - @tm/cli: add auto-update functionality to every command

## 0.27.0-rc.1

### Minor Changes

- [`255b9f0`](https://github.com/eyaltoledano/claude-task-master/commit/255b9f0334555b0063280abde701445cd62fa11b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Testing one more pre-release iteration

## 0.27.0-rc.0

### Minor Changes

- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213) [`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Test out the RC

### Patch Changes

- Updated dependencies [[`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)]:
  - @tm/cli@0.27.0-rc.0

## 0.26.0

### Minor Changes

- [#1133](https://github.com/eyaltoledano/claude-task-master/pull/1133) [`df26c65`](https://github.com/eyaltoledano/claude-task-master/commit/df26c65632000874a73504963b08f18c46283144) Thanks [@neonwatty](https://github.com/neonwatty)! - Restore Taskmaster claude-code commands and move clear commands under /remove to avoid collision with the claude-code /clear command.

- [#1163](https://github.com/eyaltoledano/claude-task-master/pull/1163) [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Gemini CLI provider with codebase-aware task generation

  Added automatic codebase analysis for Gemini CLI provider in parse-prd, and analyze-complexity, add-task, udpate-task, update, update-subtask commands
  When using Gemini CLI as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
  Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs

- [#1165](https://github.com/eyaltoledano/claude-task-master/pull/1165) [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add configurable codebase analysis feature flag with multiple configuration sources

  Users can now control whether codebase analysis features (Claude Code and Gemini CLI integration) are enabled through environment variables, MCP configuration, or project config files.

  Priority order: .env > MCP session env > .taskmaster/config.json.

  Set `TASKMASTER_ENABLE_CODEBASE_ANALYSIS=false` in `.env` to disable codebase analysis prompts and tool integration.

- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - feat(move): improve cross-tag move UX and safety
  - CLI: print "Next Steps" tips after cross-tag moves that used --ignore-dependencies (validate/fix guidance)
  - CLI: show dedicated help block on ID collisions (destination tag already has the ID)
  - Core: add structured suggestions to TASK_ALREADY_EXISTS errors
  - MCP: map ID collision errors to TASK_ALREADY_EXISTS and include suggestions
  - Tests: cover MCP options, error suggestions, CLI tips printing, and integration error payload suggestions

  ***

- [#1162](https://github.com/eyaltoledano/claude-task-master/pull/1162) [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code and Google CLI integration with automatic codebase analysis for task operations

  When using Claude Code as the AI provider, task management commands now automatically analyze your codebase before generating or updating tasks. This provides more accurate, context-aware implementation details that align with your project's existing architecture and patterns.

  Commands contextualised:
  - add-task
  - update-subtask
  - update-task
  - update

### Patch Changes

- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - docs(move): clarify cross-tag move docs; deprecate "force"; add explicit --with-dependencies/--ignore-dependencies examples

## 0.26.0-rc.1

### Minor Changes

- [#1165](https://github.com/eyaltoledano/claude-task-master/pull/1165) [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add configurable codebase analysis feature flag with multiple configuration sources

  Users can now control whether codebase analysis features (Claude Code and Gemini CLI integration) are enabled through environment variables, MCP configuration, or project config files.

  Priority order: .env > MCP session env > .taskmaster/config.json.

  Set `TASKMASTER_ENABLE_CODEBASE_ANALYSIS=false` in `.env` to disable codebase analysis prompts and tool integration.

## 0.26.0-rc.0

### Minor Changes

- [#1163](https://github.com/eyaltoledano/claude-task-master/pull/1163) [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Gemini CLI provider with codebase-aware task generation

  Added automatic codebase analysis for Gemini CLI provider in parse-prd, and analyze-complexity, add-task, udpate-task, update, update-subtask commands
  When using Gemini CLI as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
  Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs

- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - feat(move): improve cross-tag move UX and safety
  - CLI: print "Next Steps" tips after cross-tag moves that used --ignore-dependencies (validate/fix guidance)
  - CLI: show dedicated help block on ID collisions (destination tag already has the ID)
  - Core: add structured suggestions to TASK_ALREADY_EXISTS errors
  - MCP: map ID collision errors to TASK_ALREADY_EXISTS and include suggestions
  - Tests: cover MCP options, error suggestions, CLI tips printing, and integration error payload suggestions

  ***

- [#1162](https://github.com/eyaltoledano/claude-task-master/pull/1162) [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code and Google CLI integration with automatic codebase analysis for task operations

  When using Claude Code as the AI provider, task management commands now automatically analyze your codebase before generating or updating tasks. This provides more accurate, context-aware implementation details that align with your project's existing architecture and patterns.

  Commands contextualised:
  - add-task
  - update-subtask
  - update-task
  - update

### Patch Changes

- [#1135](https://github.com/eyaltoledano/claude-task-master/pull/1135) [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f) Thanks [@mm-parthy](https://github.com/mm-parthy)! - docs(move): clarify cross-tag move docs; deprecate "force"; add explicit --with-dependencies/--ignore-dependencies examples

## 0.25.1

### Patch Changes

- [#1152](https://github.com/eyaltoledano/claude-task-master/pull/1152) [`8933557`](https://github.com/eyaltoledano/claude-task-master/commit/89335578ffffc65504b2055c0c85aa7521e5e79b) Thanks [@ben-vargas](https://github.com/ben-vargas)! - fix(claude-code): prevent crash/hang when the optional `@anthropic-ai/claude-code` SDK is missing by guarding `AbortError instanceof` checks and adding explicit SDK presence checks in `doGenerate`/`doStream`. Also bump the optional dependency to `^1.0.88` for improved export consistency.

  Related to JSON truncation handling in #920; this change addresses a separate error-path crash reported in #1142.

- [#1151](https://github.com/eyaltoledano/claude-task-master/pull/1151) [`db720a9`](https://github.com/eyaltoledano/claude-task-master/commit/db720a954d390bb44838cd021b8813dde8f3d8de) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Temporarily disable streaming for improved model compatibility - will be re-enabled in upcoming release

## 0.25.0

### Minor Changes

- [#1088](https://github.com/eyaltoledano/claude-task-master/pull/1088) [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Add cross-tag task movement functionality for organizing tasks across different contexts.

  This feature enables moving tasks between different tags (contexts) in your project, making it easier to organize work across different branches, environments, or project phases.

  ## CLI Usage Examples

  Move a single task from one tag to another:

  ```bash
  # Move task 5 from backlog tag to in-progress tag
  task-master move --from=5 --from-tag=backlog --to-tag=feature-1

  # Move task with its dependencies
  task-master move --from=5 --from-tag=backlog --to-tag=feature-2 --with-dependencies

  # Move task without checking dependencies
  task-master move --from=5 --from-tag=backlog --to-tag=bug-3 --ignore-dependencies
  ```

  Move multiple tasks at once:

  ```bash
  # Move multiple tasks between tags
  task-master move --from=5,6,7 --from-tag=backlog --to-tag=bug-4 --with-dependencies
  ```

- [#1040](https://github.com/eyaltoledano/claude-task-master/pull/1040) [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1) Thanks [@DomVidja](https://github.com/DomVidja)! - "Add Kilo Code profile integration with custom modes and MCP configuration"

- [#1054](https://github.com/eyaltoledano/claude-task-master/pull/1054) [`782728f`](https://github.com/eyaltoledano/claude-task-master/commit/782728ff95aa2e3b766d48273b57f6c6753e8573) Thanks [@martincik](https://github.com/martincik)! - Add compact mode --compact / -c flag to the `tm list` CLI command
  - outputs tasks in a minimal, git-style one-line format. This reduces verbose output from ~30+ lines of dashboards and tables to just 1 line per task, making it much easier to quickly scan available tasks.
    - Git-style format: ID STATUS TITLE (PRIORITY) → DEPS
    - Color-coded status, priority, and dependencies
    - Smart title truncation and dependency abbreviation
    - Subtask support with indentation
    - Full backward compatibility with existing list options

- [#1048](https://github.com/eyaltoledano/claude-task-master/pull/1048) [`e3ed4d7`](https://github.com/eyaltoledano/claude-task-master/commit/e3ed4d7c14b56894d7da675eb2b757423bea8f9d) Thanks [@joedanz](https://github.com/joedanz)! - Add CLI & MCP progress tracking for parse-prd command.

- [#1124](https://github.com/eyaltoledano/claude-task-master/pull/1124) [`95640dc`](https://github.com/eyaltoledano/claude-task-master/commit/95640dcde87ce7879858c0a951399fb49f3b6397) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for ollama `gpt-oss:20b` and `gpt-oss:120b`

- [#1123](https://github.com/eyaltoledano/claude-task-master/pull/1123) [`311b243`](https://github.com/eyaltoledano/claude-task-master/commit/311b2433e23c771c8d3a4d3f5ac577302b8321e5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove `clear` Taskmaster claude code commands since they were too close to the claude-code clear command

### Patch Changes

- [#1131](https://github.com/eyaltoledano/claude-task-master/pull/1131) [`3dee60d`](https://github.com/eyaltoledano/claude-task-master/commit/3dee60dc3d566e3cff650accb30f994b8bb3a15e) Thanks [@joedanz](https://github.com/joedanz)! - Update Cursor one-click install link to new URL format

- [#1088](https://github.com/eyaltoledano/claude-task-master/pull/1088) [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Fix `add-tag --from-branch` command error where `projectRoot` was not properly referenced

  The command was failing with "projectRoot is not defined" error because the code was directly referencing `projectRoot` instead of `context.projectRoot` in the git repository checks. This fix corrects the variable references to use the proper context object.

## 0.25.0-rc.0

### Minor Changes

- [#1088](https://github.com/eyaltoledano/claude-task-master/pull/1088) [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Add cross-tag task movement functionality for organizing tasks across different contexts.

  This feature enables moving tasks between different tags (contexts) in your project, making it easier to organize work across different branches, environments, or project phases.

  ## CLI Usage Examples

  Move a single task from one tag to another:

  ```bash
  # Move task 5 from backlog tag to in-progress tag
  task-master move --from=5 --from-tag=backlog --to-tag=feature-1

  # Move task with its dependencies
  task-master move --from=5 --from-tag=backlog --to-tag=feature-2 --with-dependencies

  # Move task without checking dependencies
  task-master move --from=5 --from-tag=backlog --to-tag=bug-3 --ignore-dependencies
  ```

  Move multiple tasks at once:

  ```bash
  # Move multiple tasks between tags
  task-master move --from=5,6,7 --from-tag=backlog --to-tag=bug-4 --with-dependencies
  ```

- [#1040](https://github.com/eyaltoledano/claude-task-master/pull/1040) [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1) Thanks [@DomVidja](https://github.com/DomVidja)! - "Add Kilo Code profile integration with custom modes and MCP configuration"

- [#1054](https://github.com/eyaltoledano/claude-task-master/pull/1054) [`782728f`](https://github.com/eyaltoledano/claude-task-master/commit/782728ff95aa2e3b766d48273b57f6c6753e8573) Thanks [@martincik](https://github.com/martincik)! - Add compact mode --compact / -c flag to the `tm list` CLI command
  - outputs tasks in a minimal, git-style one-line format. This reduces verbose output from ~30+ lines of dashboards and tables to just 1 line per task, making it much easier to quickly scan available tasks.
    - Git-style format: ID STATUS TITLE (PRIORITY) → DEPS
    - Color-coded status, priority, and dependencies
    - Smart title truncation and dependency abbreviation
    - Subtask support with indentation
    - Full backward compatibility with existing list options

- [#1048](https://github.com/eyaltoledano/claude-task-master/pull/1048) [`e3ed4d7`](https://github.com/eyaltoledano/claude-task-master/commit/e3ed4d7c14b56894d7da675eb2b757423bea8f9d) Thanks [@joedanz](https://github.com/joedanz)! - Add CLI & MCP progress tracking for parse-prd command.

- [#1124](https://github.com/eyaltoledano/claude-task-master/pull/1124) [`95640dc`](https://github.com/eyaltoledano/claude-task-master/commit/95640dcde87ce7879858c0a951399fb49f3b6397) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for ollama `gpt-oss:20b` and `gpt-oss:120b`

- [#1123](https://github.com/eyaltoledano/claude-task-master/pull/1123) [`311b243`](https://github.com/eyaltoledano/claude-task-master/commit/311b2433e23c771c8d3a4d3f5ac577302b8321e5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove `clear` Taskmaster claude code commands since they were too close to the claude-code clear command

### Patch Changes

- [#1131](https://github.com/eyaltoledano/claude-task-master/pull/1131) [`3dee60d`](https://github.com/eyaltoledano/claude-task-master/commit/3dee60dc3d566e3cff650accb30f994b8bb3a15e) Thanks [@joedanz](https://github.com/joedanz)! - Update Cursor one-click install link to new URL format

- [#1088](https://github.com/eyaltoledano/claude-task-master/pull/1088) [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Fix `add-tag --from-branch` command error where `projectRoot` was not properly referenced

  The command was failing with "projectRoot is not defined" error because the code was directly referencing `projectRoot` instead of `context.projectRoot` in the git repository checks. This fix corrects the variable references to use the proper context object.

## 0.24.0

### Minor Changes

- [#1098](https://github.com/eyaltoledano/claude-task-master/pull/1098) [`36468f3`](https://github.com/eyaltoledano/claude-task-master/commit/36468f3c93faf4035a5c442ccbc501077f3440f1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code provider with codebase-aware task generation
  - Added automatic codebase analysis for Claude Code provider in `parse-prd`, `expand-task`, and `analyze-complexity` commands
  - When using Claude Code as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
  - Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs

- [#1105](https://github.com/eyaltoledano/claude-task-master/pull/1105) [`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add GPT-5 support with proper parameter handling
  - Added GPT-5 model to supported models configuration with SWE score of 0.749

- [#1091](https://github.com/eyaltoledano/claude-task-master/pull/1091) [`4bb6370`](https://github.com/eyaltoledano/claude-task-master/commit/4bb63706b80c28d1b2d782ba868a725326f916c7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code subagent support with task-orchestrator, task-executor, and task-checker

  ## New Claude Code Agents

  Added specialized agents for Claude Code users to enable parallel task execution, intelligent task orchestration, and quality assurance:

  ### task-orchestrator

  Coordinates and manages the execution of Task Master tasks with intelligent dependency analysis:
  - Analyzes task dependencies to identify parallelizable work
  - Deploys multiple task-executor agents for concurrent execution
  - Monitors task completion and updates the dependency graph
  - Automatically identifies and starts newly unblocked tasks

  ### task-executor

  Handles the actual implementation of individual tasks:
  - Executes specific tasks identified by the orchestrator
  - Works on concrete implementation rather than planning
  - Updates task status and logs progress
  - Can work in parallel with other executors on independent tasks

  ### task-checker

  Verifies that completed tasks meet their specifications:
  - Reviews tasks marked as 'review' status
  - Validates implementation against requirements
  - Runs tests and checks for best practices
  - Ensures quality before marking tasks as 'done'

  ## Installation

  When using the Claude profile (`task-master rules add claude`), the agents are automatically installed to `.claude/agents/` directory.

  ## Usage Example

  ```bash
  # In Claude Code, after initializing a project with tasks:

  # Use task-orchestrator to analyze and coordinate work
  # The orchestrator will:
  # 1. Check task dependencies
  # 2. Identify tasks that can run in parallel
  # 3. Deploy executors for available work
  # 4. Monitor progress and deploy new executors as tasks complete

  # Use task-executor for specific task implementation
  # When the orchestrator identifies task 2.3 needs work:
  # The executor will implement that specific task
  ```

  ## Benefits
  - **Parallel Execution**: Multiple independent tasks can be worked on simultaneously
  - **Intelligent Scheduling**: Orchestrator understands dependencies and optimizes execution order
  - **Separation of Concerns**: Planning (orchestrator) is separated from execution (executor)
  - **Progress Tracking**: Real-time updates as tasks are completed
  - **Automatic Progression**: As tasks complete, newly unblocked tasks are automatically started

### Patch Changes

- [#1094](https://github.com/eyaltoledano/claude-task-master/pull/1094) [`4357af3`](https://github.com/eyaltoledano/claude-task-master/commit/4357af3f13859d90bca8795215e5d5f1d94abde5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix expand task generating unrelated generic subtasks

  Fixed an issue where `task-master expand` would generate generic authentication-related subtasks regardless of the parent task context when using complexity reports. The expansion now properly includes the parent task details alongside any expansion guidance.

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix scope-up/down prompts to include all required fields for better AI model compatibility
  - Added missing `priority` field to scope adjustment prompts to prevent validation errors with Claude-code and other models
  - Ensures generated JSON includes all fields required by the schema

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP scope-up/down tools not finding tasks
  - Fixed task ID parsing in MCP layer - now correctly converts string IDs to numbers
  - scope_up_task and scope_down_task MCP tools now work properly

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve AI provider compatibility for JSON generation
  - Fixed schema compatibility issues between Perplexity and OpenAI o3 models
  - Removed nullable/default modifiers from Zod schemas for broader compatibility
  - Added automatic JSON repair for malformed AI responses (handles cases like missing array values)
  - Perplexity now uses JSON mode for more reliable structured output
  - Post-processing handles default values separately from schema validation

## 0.24.0-rc.2

### Minor Changes

- [#1105](https://github.com/eyaltoledano/claude-task-master/pull/1105) [`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add GPT-5 support with proper parameter handling
  - Added GPT-5 model to supported models configuration with SWE score of 0.749

## 0.24.0-rc.1

### Minor Changes

- [#1093](https://github.com/eyaltoledano/claude-task-master/pull/1093) [`36468f3`](https://github.com/eyaltoledano/claude-task-master/commit/36468f3c93faf4035a5c442ccbc501077f3440f1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhanced Claude Code provider with codebase-aware task generation
  - Added automatic codebase analysis for Claude Code provider in `parse-prd`, `expand-task`, and `analyze-complexity` commands
  - When using Claude Code as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
  - Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs

- [#1091](https://github.com/eyaltoledano/claude-task-master/pull/1091) [`4bb6370`](https://github.com/eyaltoledano/claude-task-master/commit/4bb63706b80c28d1b2d782ba868a725326f916c7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code subagent support with task-orchestrator, task-executor, and task-checker

  ## New Claude Code Agents

  Added specialized agents for Claude Code users to enable parallel task execution, intelligent task orchestration, and quality assurance:

  ### task-orchestrator

  Coordinates and manages the execution of Task Master tasks with intelligent dependency analysis:
  - Analyzes task dependencies to identify parallelizable work
  - Deploys multiple task-executor agents for concurrent execution
  - Monitors task completion and updates the dependency graph
  - Automatically identifies and starts newly unblocked tasks

  ### task-executor

  Handles the actual implementation of individual tasks:
  - Executes specific tasks identified by the orchestrator
  - Works on concrete implementation rather than planning
  - Updates task status and logs progress
  - Can work in parallel with other executors on independent tasks

  ### task-checker

  Verifies that completed tasks meet their specifications:
  - Reviews tasks marked as 'review' status
  - Validates implementation against requirements
  - Runs tests and checks for best practices
  - Ensures quality before marking tasks as 'done'

  ## Installation

  When using the Claude profile (`task-master rules add claude`), the agents are automatically installed to `.claude/agents/` directory.

  ## Usage Example

  ```bash
  # In Claude Code, after initializing a project with tasks:

  # Use task-orchestrator to analyze and coordinate work
  # The orchestrator will:
  # 1. Check task dependencies
  # 2. Identify tasks that can run in parallel
  # 3. Deploy executors for available work
  # 4. Monitor progress and deploy new executors as tasks complete

  # Use task-executor for specific task implementation
  # When the orchestrator identifies task 2.3 needs work:
  # The executor will implement that specific task
  ```

  ## Benefits
  - **Parallel Execution**: Multiple independent tasks can be worked on simultaneously
  - **Intelligent Scheduling**: Orchestrator understands dependencies and optimizes execution order
  - **Separation of Concerns**: Planning (orchestrator) is separated from execution (executor)
  - **Progress Tracking**: Real-time updates as tasks are completed
  - **Automatic Progression**: As tasks complete, newly unblocked tasks are automatically started

### Patch Changes

- [#1094](https://github.com/eyaltoledano/claude-task-master/pull/1094) [`4357af3`](https://github.com/eyaltoledano/claude-task-master/commit/4357af3f13859d90bca8795215e5d5f1d94abde5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix expand task generating unrelated generic subtasks

  Fixed an issue where `task-master expand` would generate generic authentication-related subtasks regardless of the parent task context when using complexity reports. The expansion now properly includes the parent task details alongside any expansion guidance.

## 0.23.1-rc.0

### Patch Changes

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix scope-up/down prompts to include all required fields for better AI model compatibility
  - Added missing `priority` field to scope adjustment prompts to prevent validation errors with Claude-code and other models
  - Ensures generated JSON includes all fields required by the schema

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP scope-up/down tools not finding tasks
  - Fixed task ID parsing in MCP layer - now correctly converts string IDs to numbers
  - scope_up_task and scope_down_task MCP tools now work properly

- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve AI provider compatibility for JSON generation
  - Fixed schema compatibility issues between Perplexity and OpenAI o3 models
  - Removed nullable/default modifiers from Zod schemas for broader compatibility
  - Added automatic JSON repair for malformed AI responses (handles cases like missing array values)
  - Perplexity now uses JSON mode for more reliable structured output
  - Post-processing handles default values separately from schema validation

## 0.23.0

### Minor Changes

- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`53903f1`](https://github.com/eyaltoledano/claude-task-master/commit/53903f1e8eee23ac512eb13a6d81d8cbcfe658cb) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add new `scope-up` and `scope-down` commands for dynamic task complexity adjustment

  This release introduces two powerful new commands that allow you to dynamically adjust the complexity of your tasks and subtasks without recreating them from scratch.

  **New CLI Commands:**
  - `task-master scope-up` - Increase task complexity (add more detail, requirements, or implementation steps)
  - `task-master scope-down` - Decrease task complexity (simplify, remove unnecessary details, or streamline)

  **Key Features:**
  - **Multiple tasks**: Support comma-separated IDs to adjust multiple tasks at once (`--id=5,7,12`)
  - **Strength levels**: Choose adjustment intensity with `--strength=light|regular|heavy` (defaults to regular)
  - **Custom prompts**: Use `--prompt` flag to specify exactly how you want tasks adjusted
  - **MCP integration**: Available as `scope_up_task` and `scope_down_task` tools in Cursor and other MCP environments
  - **Smart context**: AI considers your project context and task dependencies when making adjustments

  **Usage Examples:**

  ```bash
  # Make a task more detailed
  task-master scope-up --id=5

  # Simplify multiple tasks with light touch
  task-master scope-down --id=10,11,12 --strength=light

  # Custom adjustment with specific instructions
  task-master scope-up --id=7 --prompt="Add more error handling and edge cases"
  ```

  **Why use this?**
  - **Iterative refinement**: Adjust task complexity as your understanding evolves
  - **Project phase adaptation**: Scale tasks up for implementation, down for planning
  - **Team coordination**: Adjust complexity based on team member experience levels
  - **Milestone alignment**: Fine-tune tasks to match project phase requirements

  Perfect for agile workflows where task requirements change as you learn more about the problem space.

### Patch Changes

- [#1063](https://github.com/eyaltoledano/claude-task-master/pull/1063) [`2ae6e7e`](https://github.com/eyaltoledano/claude-task-master/commit/2ae6e7e6be3605c3c4d353f34666e54750dba973) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix for tasks not found when using string IDs

- [#1049](https://github.com/eyaltoledano/claude-task-master/pull/1049) [`45a14c3`](https://github.com/eyaltoledano/claude-task-master/commit/45a14c323d21071c15106335e89ad1f4a20976ab) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix tag-specific complexity report detection in expand command

  The expand command now correctly finds and uses tag-specific complexity reports (e.g., `task-complexity-report_feature-xyz.json`) when operating in a tag context. Previously, it would always look for the generic `task-complexity-report.json` file due to a default value in the CLI option definition.

## 0.23.0-rc.2

### Minor Changes

- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`53903f1`](https://github.com/eyaltoledano/claude-task-master/commit/53903f1e8eee23ac512eb13a6d81d8cbcfe658cb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add new `scope-up` and `scope-down` commands for dynamic task complexity adjustment

  This release introduces two powerful new commands that allow you to dynamically adjust the complexity of your tasks and subtasks without recreating them from scratch.

  **New CLI Commands:**
  - `task-master scope-up` - Increase task complexity (add more detail, requirements, or implementation steps)
  - `task-master scope-down` - Decrease task complexity (simplify, remove unnecessary details, or streamline)

  **Key Features:**
  - **Multiple tasks**: Support comma-separated IDs to adjust multiple tasks at once (`--id=5,7,12`)
  - **Strength levels**: Choose adjustment intensity with `--strength=light|regular|heavy` (defaults to regular)
  - **Custom prompts**: Use `--prompt` flag to specify exactly how you want tasks adjusted
  - **MCP integration**: Available as `scope_up_task` and `scope_down_task` tools in Cursor and other MCP environments
  - **Smart context**: AI considers your project context and task dependencies when making adjustments

  **Usage Examples:**

  ```bash
  # Make a task more detailed
  task-master scope-up --id=5

  # Simplify multiple tasks with light touch
  task-master scope-down --id=10,11,12 --strength=light

  # Custom adjustment with specific instructions
  task-master scope-up --id=7 --prompt="Add more error handling and edge cases"
  ```

  **Why use this?**
  - **Iterative refinement**: Adjust task complexity as your understanding evolves
  - **Project phase adaptation**: Scale tasks up for implementation, down for planning
  - **Team coordination**: Adjust complexity based on team member experience levels
  - **Milestone alignment**: Fine-tune tasks to match project phase requirements

  Perfect for agile workflows where task requirements change as you learn more about the problem space.

## 0.22.1-rc.1

### Patch Changes

- [#1069](https://github.com/eyaltoledano/claude-task-master/pull/1069) [`72ca68e`](https://github.com/eyaltoledano/claude-task-master/commit/72ca68edeb870ff7a3b0d2d632e09dae921dc16a) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add new `scope-up` and `scope-down` commands for dynamic task complexity adjustment

  This release introduces two powerful new commands that allow you to dynamically adjust the complexity of your tasks and subtasks without recreating them from scratch.

  **New CLI Commands:**
  - `task-master scope-up` - Increase task complexity (add more detail, requirements, or implementation steps)
  - `task-master scope-down` - Decrease task complexity (simplify, remove unnecessary details, or streamline)

  **Key Features:**
  - **Multiple tasks**: Support comma-separated IDs to adjust multiple tasks at once (`--id=5,7,12`)
  - **Strength levels**: Choose adjustment intensity with `--strength=light|regular|heavy` (defaults to regular)
  - **Custom prompts**: Use `--prompt` flag to specify exactly how you want tasks adjusted
  - **MCP integration**: Available as `scope_up_task` and `scope_down_task` tools in Cursor and other MCP environments
  - **Smart context**: AI considers your project context and task dependencies when making adjustments

  **Usage Examples:**

  ```bash
  # Make a task more detailed
  task-master scope-up --id=5

  # Simplify multiple tasks with light touch
  task-master scope-down --id=10,11,12 --strength=light

  # Custom adjustment with specific instructions
  task-master scope-up --id=7 --prompt="Add more error handling and edge cases"
  ```

  **Why use this?**
  - **Iterative refinement**: Adjust task complexity as your understanding evolves
  - **Project phase adaptation**: Scale tasks up for implementation, down for planning
  - **Team coordination**: Adjust complexity based on team member experience levels
  - **Milestone alignment**: Fine-tune tasks to match project phase requirements

  Perfect for agile workflows where task requirements change as you learn more about the problem space.

## 0.22.1-rc.0

### Patch Changes

- [#1063](https://github.com/eyaltoledano/claude-task-master/pull/1063) [`2ae6e7e`](https://github.com/eyaltoledano/claude-task-master/commit/2ae6e7e6be3605c3c4d353f34666e54750dba973) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix for tasks not found when using string IDs

- [#1049](https://github.com/eyaltoledano/claude-task-master/pull/1049) [`45a14c3`](https://github.com/eyaltoledano/claude-task-master/commit/45a14c323d21071c15106335e89ad1f4a20976ab) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix tag-specific complexity report detection in expand command

  The expand command now correctly finds and uses tag-specific complexity reports (e.g., `task-complexity-report_feature-xyz.json`) when operating in a tag context. Previously, it would always look for the generic `task-complexity-report.json` file due to a default value in the CLI option definition.

## 0.22.0

### Minor Changes

- [#1043](https://github.com/eyaltoledano/claude-task-master/pull/1043) [`dc44ed9`](https://github.com/eyaltoledano/claude-task-master/commit/dc44ed9de8a57aca5d39d3a87565568bd0a82068) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Prompt to generate a complexity report when it is missing

- [#1032](https://github.com/eyaltoledano/claude-task-master/pull/1032) [`4423119`](https://github.com/eyaltoledano/claude-task-master/commit/4423119a5ec53958c9dffa8bf564da8be7a2827d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add comprehensive Kiro IDE integration with autonomous task management hooks
  - **Kiro Profile**: Added full support for Kiro IDE with automatic installation of 7 Taskmaster agent hooks
  - **Hook-Driven Workflow**: Introduced natural language automation hooks that eliminate manual task status updates
  - **Automatic Hook Installation**: Hooks are now automatically copied to `.kiro/hooks/` when running `task-master rules add kiro`
  - **Language-Agnostic Support**: All hooks support multiple programming languages (JS, Python, Go, Rust, Java, etc.)
  - **Frontmatter Transformation**: Kiro rules use simplified `inclusion: always` format instead of Cursor's complex frontmatter
  - **Special Rule**: Added `taskmaster_hooks_workflow.md` that guides AI assistants to prefer hook-driven completion

  Key hooks included:
  - Task Dependency Auto-Progression: Automatically starts tasks when dependencies complete
  - Code Change Task Tracker: Updates task progress as you save files
  - Test Success Task Completer: Marks tasks done when tests pass
  - Daily Standup Assistant: Provides personalized task status summaries
  - PR Readiness Checker: Validates task completion before creating pull requests
  - Complexity Analyzer: Auto-expands complex tasks into manageable subtasks
  - Git Commit Task Linker: Links commits to tasks for better traceability

  This creates a truly autonomous development workflow where task management happens naturally as you code!

### Patch Changes

- [#1033](https://github.com/eyaltoledano/claude-task-master/pull/1033) [`7b90568`](https://github.com/eyaltoledano/claude-task-master/commit/7b9056832653464f934c91c22997077065d738c4) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix compatibility with @google/gemini-cli-core v0.1.12+ by updating ai-sdk-provider-gemini-cli to v0.1.1.

- [#1038](https://github.com/eyaltoledano/claude-task-master/pull/1038) [`77cc5e4`](https://github.com/eyaltoledano/claude-task-master/commit/77cc5e4537397642f2664f61940a101433ee6fb4) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix 'expand --all' and 'show' commands to correctly handle tag contexts for complexity reports and task display.

- [#1025](https://github.com/eyaltoledano/claude-task-master/pull/1025) [`8781794`](https://github.com/eyaltoledano/claude-task-master/commit/8781794c56d454697fc92c88a3925982d6b81205) Thanks [@joedanz](https://github.com/joedanz)! - Clean up remaining automatic task file generation calls

- [#1035](https://github.com/eyaltoledano/claude-task-master/pull/1035) [`fb7d588`](https://github.com/eyaltoledano/claude-task-master/commit/fb7d588137e8c53b0d0f54bd1dd8d387648583ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix max_tokens limits for OpenRouter and Groq models
  - Add special handling in config-manager.js for custom OpenRouter models to use a conservative default of 32,768 max_tokens
  - Update qwen/qwen-turbo model max_tokens from 1,000,000 to 32,768 to match OpenRouter's actual limits
  - Fix moonshotai/kimi-k2-instruct max_tokens to 16,384 to match Groq's actual limit (fixes #1028)
  - This prevents "maximum context length exceeded" errors when using OpenRouter models not in our supported models list

- [#1027](https://github.com/eyaltoledano/claude-task-master/pull/1027) [`6ae66b2`](https://github.com/eyaltoledano/claude-task-master/commit/6ae66b2afbfe911340fa25e0236c3db83deaa7eb) Thanks [@andreswebs](https://github.com/andreswebs)! - Fix VSCode profile generation to use correct rule file names (using `.instructions.md` extension instead of `.md`) and front-matter properties (removing the unsupported `alwaysApply` property from instructions files' front-matter).

## 0.22.0-rc.1

### Minor Changes

- [#1043](https://github.com/eyaltoledano/claude-task-master/pull/1043) [`dc44ed9`](https://github.com/eyaltoledano/claude-task-master/commit/dc44ed9de8a57aca5d39d3a87565568bd0a82068) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Prompt to generate a complexity report when it is missing

## 0.22.0-rc.0

### Minor Changes

- [#1032](https://github.com/eyaltoledano/claude-task-master/pull/1032) [`4423119`](https://github.com/eyaltoledano/claude-task-master/commit/4423119a5ec53958c9dffa8bf564da8be7a2827d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add comprehensive Kiro IDE integration with autonomous task management hooks
  - **Kiro Profile**: Added full support for Kiro IDE with automatic installation of 7 Taskmaster agent hooks
  - **Hook-Driven Workflow**: Introduced natural language automation hooks that eliminate manual task status updates
  - **Automatic Hook Installation**: Hooks are now automatically copied to `.kiro/hooks/` when running `task-master rules add kiro`
  - **Language-Agnostic Support**: All hooks support multiple programming languages (JS, Python, Go, Rust, Java, etc.)
  - **Frontmatter Transformation**: Kiro rules use simplified `inclusion: always` format instead of Cursor's complex frontmatter
  - **Special Rule**: Added `taskmaster_hooks_workflow.md` that guides AI assistants to prefer hook-driven completion

  Key hooks included:
  - Task Dependency Auto-Progression: Automatically starts tasks when dependencies complete
  - Code Change Task Tracker: Updates task progress as you save files
  - Test Success Task Completer: Marks tasks done when tests pass
  - Daily Standup Assistant: Provides personalized task status summaries
  - PR Readiness Checker: Validates task completion before creating pull requests
  - Complexity Analyzer: Auto-expands complex tasks into manageable subtasks
  - Git Commit Task Linker: Links commits to tasks for better traceability

  This creates a truly autonomous development workflow where task management happens naturally as you code!

### Patch Changes

- [#1033](https://github.com/eyaltoledano/claude-task-master/pull/1033) [`7b90568`](https://github.com/eyaltoledano/claude-task-master/commit/7b9056832653464f934c91c22997077065d738c4) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix compatibility with @google/gemini-cli-core v0.1.12+ by updating ai-sdk-provider-gemini-cli to v0.1.1.

- [#1038](https://github.com/eyaltoledano/claude-task-master/pull/1038) [`77cc5e4`](https://github.com/eyaltoledano/claude-task-master/commit/77cc5e4537397642f2664f61940a101433ee6fb4) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix 'expand --all' and 'show' commands to correctly handle tag contexts for complexity reports and task display.

- [#1025](https://github.com/eyaltoledano/claude-task-master/pull/1025) [`8781794`](https://github.com/eyaltoledano/claude-task-master/commit/8781794c56d454697fc92c88a3925982d6b81205) Thanks [@joedanz](https://github.com/joedanz)! - Clean up remaining automatic task file generation calls

- [#1035](https://github.com/eyaltoledano/claude-task-master/pull/1035) [`fb7d588`](https://github.com/eyaltoledano/claude-task-master/commit/fb7d588137e8c53b0d0f54bd1dd8d387648583ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix max_tokens limits for OpenRouter and Groq models
  - Add special handling in config-manager.js for custom OpenRouter models to use a conservative default of 32,768 max_tokens
  - Update qwen/qwen-turbo model max_tokens from 1,000,000 to 32,768 to match OpenRouter's actual limits
  - Fix moonshotai/kimi-k2-instruct max_tokens to 16,384 to match Groq's actual limit (fixes #1028)
  - This prevents "maximum context length exceeded" errors when using OpenRouter models not in our supported models list

- [#1027](https://github.com/eyaltoledano/claude-task-master/pull/1027) [`6ae66b2`](https://github.com/eyaltoledano/claude-task-master/commit/6ae66b2afbfe911340fa25e0236c3db83deaa7eb) Thanks [@andreswebs](https://github.com/andreswebs)! - Fix VSCode profile generation to use correct rule file names (using `.instructions.md` extension instead of `.md`) and front-matter properties (removing the unsupported `alwaysApply` property from instructions files' front-matter).

## 0.21.0

### Minor Changes

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`9c58a92`](https://github.com/eyaltoledano/claude-task-master/commit/9c58a922436c0c5e7ff1b20ed2edbc269990c772) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Kiro editor rule profile support
  - Add support for Kiro IDE with custom rule files and MCP configuration
  - Generate rule files in `.kiro/steering/` directory with markdown format
  - Include MCP server configuration with enhanced file inclusion patterns

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Created a comprehensive documentation site for Task Master AI. Visit https://docs.task-master.dev to explore guides, API references, and examples.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`58a301c`](https://github.com/eyaltoledano/claude-task-master/commit/58a301c380d18a9d9509137f3e989d24200a5faa) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Complete Groq provider integration and add MoonshotAI Kimi K2 model support
  - Fixed Groq provider registration
  - Added Groq API key validation
  - Added GROQ_API_KEY to .env.example
  - Added moonshotai/kimi-k2-instruct model with $1/$3 per 1M token pricing and 16k max output

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`b0e09c7`](https://github.com/eyaltoledano/claude-task-master/commit/b0e09c76ed73b00434ac95606679f570f1015a3d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - feat: Add Zed editor rule profile with agent rules and MCP config
  - Resolves #637

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`6c5e0f9`](https://github.com/eyaltoledano/claude-task-master/commit/6c5e0f97f8403c4da85c1abba31cb8b1789511a7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Amp rule profile with AGENT.md and MCP config

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve project root detection
  - No longer creates an infinite loop when unable to detect your code workspace

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`36c4a7a`](https://github.com/eyaltoledano/claude-task-master/commit/36c4a7a86924c927ad7f86a4f891f66ad55eb4d2) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add OpenCode profile with AGENTS.md and MCP config
  - Resolves #965

### Patch Changes

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Make `task-master update` more reliable with AI responses

  The `update` command now handles AI responses more robustly. If the AI forgets to include certain task fields, the command will automatically fill in the missing data from your original tasks instead of failing. This means smoother bulk task updates without losing important information like IDs, dependencies, or completed subtasks.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask dependency validation when expanding tasks

  When using `task-master expand` to break down tasks into subtasks, dependencies between subtasks are now properly validated. Previously, subtasks with dependencies would fail validation. Now subtasks can correctly depend on their siblings within the same parent task.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`6d69d02`](https://github.com/eyaltoledano/claude-task-master/commit/6d69d02fe03edcc785380415995d5cfcdd97acbb) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Prevent CLAUDE.md overwrite by using Claude Code's import feature
  - Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
  - Adds an import section to the user's CLAUDE.md that references the Task Master instructions
  - Preserves existing user content in CLAUDE.md files
  - Provides clean uninstall that only removes Task Master's additions

  **Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`fd005c4`](https://github.com/eyaltoledano/claude-task-master/commit/fd005c4c5481ffac58b11f01a448fa5b29056b8d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Implement Boundary-First Tag Resolution to ensure consistent and deterministic tag handling across CLI and MCP, resolving potential race conditions.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`444aa5a`](https://github.com/eyaltoledano/claude-task-master/commit/444aa5ae1943ba72d012b3f01b1cc9362a328248) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix `task-master lang --setup` breaking when no language is defined, now defaults to English

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`624922c`](https://github.com/eyaltoledano/claude-task-master/commit/624922ca598c4ce8afe9a5646ebb375d4616db63) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix: show command no longer requires complexity report file to exist

  The `tm show` command was incorrectly requiring the complexity report file to exist even when not needed. Now it only validates the complexity report path when a custom report file is explicitly provided via the -r/--report option.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`858d4a1`](https://github.com/eyaltoledano/claude-task-master/commit/858d4a1c5486d20e7e3a8e37e3329d7fb8200310) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Update VS Code profile with MCP config transformation

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0451ebc`](https://github.com/eyaltoledano/claude-task-master/commit/0451ebcc32cd7e9d395b015aaa8602c4734157e1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when retrieving tools and resources

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0a70ab6`](https://github.com/eyaltoledano/claude-task-master/commit/0a70ab6179cb2b5b4b2d9dc256a7a3b69a0e5dd6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add MCP configuration support to Claude Code rules

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`4629128`](https://github.com/eyaltoledano/claude-task-master/commit/4629128943f6283385f4762c09cf2752f855cc33) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
  - Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`0886c83`](https://github.com/eyaltoledano/claude-task-master/commit/0886c83d0c678417c0313256a6dd96f7ee2c9ac6) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Correct MCP server name and use 'Add to Cursor' button with updated placeholder keys.

- [#1009](https://github.com/eyaltoledano/claude-task-master/pull/1009) [`88c434a`](https://github.com/eyaltoledano/claude-task-master/commit/88c434a9393e429d9277f59b3e20f1005076bbe0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add missing API keys to .env.example and README.md

## 0.21.0-rc.0

### Minor Changes

- [#1001](https://github.com/eyaltoledano/claude-task-master/pull/1001) [`75a36ea`](https://github.com/eyaltoledano/claude-task-master/commit/75a36ea99a1c738a555bdd4fe7c763d0c5925e37) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Kiro editor rule profile support
  - Add support for Kiro IDE with custom rule files and MCP configuration
  - Generate rule files in `.kiro/steering/` directory with markdown format
  - Include MCP server configuration with enhanced file inclusion patterns

- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Created a comprehensive documentation site for Task Master AI. Visit https://docs.task-master.dev to explore guides, API references, and examples.

- [#978](https://github.com/eyaltoledano/claude-task-master/pull/978) [`fedfd6a`](https://github.com/eyaltoledano/claude-task-master/commit/fedfd6a0f41a78094f7ee7f69be689b699475a79) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Complete Groq provider integration and add MoonshotAI Kimi K2 model support
  - Fixed Groq provider registration
  - Added Groq API key validation
  - Added GROQ_API_KEY to .env.example
  - Added moonshotai/kimi-k2-instruct model with $1/$3 per 1M token pricing and 16k max output

- [#974](https://github.com/eyaltoledano/claude-task-master/pull/974) [`5b0eda0`](https://github.com/eyaltoledano/claude-task-master/commit/5b0eda07f20a365aa2ec1736eed102bca81763a9) Thanks [@joedanz](https://github.com/joedanz)! - feat: Add Zed editor rule profile with agent rules and MCP config
  - Resolves #637

- [#973](https://github.com/eyaltoledano/claude-task-master/pull/973) [`6d05e86`](https://github.com/eyaltoledano/claude-task-master/commit/6d05e8622c1d761acef10414940ff9a766b3b57d) Thanks [@joedanz](https://github.com/joedanz)! - Add Amp rule profile with AGENT.md and MCP config

- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve project root detection
  - No longer creates an infinite loop when unable to detect your code workspace

- [#970](https://github.com/eyaltoledano/claude-task-master/pull/970) [`b87499b`](https://github.com/eyaltoledano/claude-task-master/commit/b87499b56e626001371a87ed56ffc72675d829f3) Thanks [@joedanz](https://github.com/joedanz)! - Add OpenCode profile with AGENTS.md and MCP config
  - Resolves #965

### Patch Changes

- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Make `task-master update` more reliable with AI responses

  The `update` command now handles AI responses more robustly. If the AI forgets to include certain task fields, the command will automatically fill in the missing data from your original tasks instead of failing. This means smoother bulk task updates without losing important information like IDs, dependencies, or completed subtasks.

- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix subtask dependency validation when expanding tasks

  When using `task-master expand` to break down tasks into subtasks, dependencies between subtasks are now properly validated. Previously, subtasks with dependencies would fail validation. Now subtasks can correctly depend on their siblings within the same parent task.

- [#949](https://github.com/eyaltoledano/claude-task-master/pull/949) [`f662654`](https://github.com/eyaltoledano/claude-task-master/commit/f662654afb8e7a230448655265d6f41adf6df62c) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Prevent CLAUDE.md overwrite by using Claude Code's import feature
  - Task Master now creates its instructions in `.taskmaster/CLAUDE.md` instead of overwriting the user's `CLAUDE.md`
  - Adds an import section to the user's CLAUDE.md that references the Task Master instructions
  - Preserves existing user content in CLAUDE.md files
  - Provides clean uninstall that only removes Task Master's additions

  **Breaking Change**: Task Master instructions for Claude Code are now stored in `.taskmaster/CLAUDE.md` and imported into the main CLAUDE.md file. Users who previously had Task Master content directly in their CLAUDE.md will need to run `task-master rules remove claude` followed by `task-master rules add claude` to migrate to the new structure.

- [#943](https://github.com/eyaltoledano/claude-task-master/pull/943) [`f98df5c`](https://github.com/eyaltoledano/claude-task-master/commit/f98df5c0fdb253b2b55d4278c11d626529c4dba4) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Implement Boundary-First Tag Resolution to ensure consistent and deterministic tag handling across CLI and MCP, resolving potential race conditions.

- [#1011](https://github.com/eyaltoledano/claude-task-master/pull/1011) [`3eb050a`](https://github.com/eyaltoledano/claude-task-master/commit/3eb050aaddb90fca1a04517e2ee24f73934323be) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix `task-master lang --setup` breaking when no language is defined, now defaults to English

- [#979](https://github.com/eyaltoledano/claude-task-master/pull/979) [`ab2e946`](https://github.com/eyaltoledano/claude-task-master/commit/ab2e94608749a2f148118daa0443bd32bca6e7a1) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix: show command no longer requires complexity report file to exist

  The `tm show` command was incorrectly requiring the complexity report file to exist even when not needed. Now it only validates the complexity report path when a custom report file is explicitly provided via the -r/--report option.

- [#971](https://github.com/eyaltoledano/claude-task-master/pull/971) [`5544222`](https://github.com/eyaltoledano/claude-task-master/commit/55442226d0aa4870470d2a9897f5538d6a0e329e) Thanks [@joedanz](https://github.com/joedanz)! - Update VS Code profile with MCP config transformation

- [#1002](https://github.com/eyaltoledano/claude-task-master/pull/1002) [`6d0654c`](https://github.com/eyaltoledano/claude-task-master/commit/6d0654cb4191cee794e1c8cbf2b92dc33d4fb410) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when retrieving tools and resources

- [#980](https://github.com/eyaltoledano/claude-task-master/pull/980) [`cc4fe20`](https://github.com/eyaltoledano/claude-task-master/commit/cc4fe205fb468e7144c650acc92486df30731560) Thanks [@joedanz](https://github.com/joedanz)! - Add MCP configuration support to Claude Code rules

- [#968](https://github.com/eyaltoledano/claude-task-master/pull/968) [`7b4803a`](https://github.com/eyaltoledano/claude-task-master/commit/7b4803a479105691c7ed032fd878fe3d48d82724) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed the comprehensive taskmaster system integration via custom slash commands with proper syntax
  - Provide claude clode with a complete set of of commands that can trigger task master events directly within Claude Code

- [#995](https://github.com/eyaltoledano/claude-task-master/pull/995) [`b78de8d`](https://github.com/eyaltoledano/claude-task-master/commit/b78de8dbb4d6dc93b48e2f81c32960ef069736ed) Thanks [@joedanz](https://github.com/joedanz)! - Correct MCP server name and use 'Add to Cursor' button with updated placeholder keys.

- [#972](https://github.com/eyaltoledano/claude-task-master/pull/972) [`1c7badf`](https://github.com/eyaltoledano/claude-task-master/commit/1c7badff2f5c548bfa90a3b2634e63087a382a84) Thanks [@joedanz](https://github.com/joedanz)! - Add missing API keys to .env.example and README.md

## 0.20.0

### Minor Changes

- [#950](https://github.com/eyaltoledano/claude-task-master/pull/950) [`699e9ee`](https://github.com/eyaltoledano/claude-task-master/commit/699e9eefb5d687b256e9402d686bdd5e3a358b4a) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add support for xAI Grok 4 model
  - Add grok-4 model to xAI provider with $3/$15 per 1M token pricing
  - Enable main, fallback, and research roles for grok-4
  - Max tokens set to 131,072 (matching other xAI models)

- [#946](https://github.com/eyaltoledano/claude-task-master/pull/946) [`5f009a5`](https://github.com/eyaltoledano/claude-task-master/commit/5f009a5e1fc10e37be26f5135df4b7f44a9c5320) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add stricter validation and clearer feedback for task priority when adding new tasks
  - if a task priority is invalid, it will default to medium
  - made taks priority case-insensitive, essentially making HIGH and high the same value

- [#863](https://github.com/eyaltoledano/claude-task-master/pull/863) [`b530657`](https://github.com/eyaltoledano/claude-task-master/commit/b53065713c8da0ae6f18eb2655397aa975004923) Thanks [@OrenMe](https://github.com/OrenMe)! - Add support for MCP Sampling as AI provider, requires no API key, uses the client LLM provider

- [#930](https://github.com/eyaltoledano/claude-task-master/pull/930) [`98d1c97`](https://github.com/eyaltoledano/claude-task-master/commit/98d1c974361a56ddbeb772b1272986b9d3913459) Thanks [@OmarElKadri](https://github.com/OmarElKadri)! - Added Groq provider support

### Patch Changes

- [#958](https://github.com/eyaltoledano/claude-task-master/pull/958) [`6c88a4a`](https://github.com/eyaltoledano/claude-task-master/commit/6c88a4a749083e3bd2d073a9240799771774495a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Recover from `@anthropic-ai/claude-code` JSON truncation bug that caused Task Master to crash when handling large (>8 kB) structured responses. The CLI/SDK still truncates, but Task Master now detects the error, preserves buffered text, and returns a usable response instead of throwing.

- [#958](https://github.com/eyaltoledano/claude-task-master/pull/958) [`3334e40`](https://github.com/eyaltoledano/claude-task-master/commit/3334e409ae659d5223bb136ae23fd22c5e219073) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Updating dependency ai-sdk-provider-gemini-cli to 0.0.4 to address breaking change Google made to Gemini CLI and add better 'api-key' in addition to 'gemini-api-key' AI-SDK compatibility.

- [#853](https://github.com/eyaltoledano/claude-task-master/pull/853) [`95c299d`](https://github.com/eyaltoledano/claude-task-master/commit/95c299df642bd8e6d75f8fa5110ac705bcc72edf) Thanks [@joedanz](https://github.com/joedanz)! - Unify and streamline profile system architecture for improved maintainability

## 0.20.0-rc.0

### Minor Changes

- [#950](https://github.com/eyaltoledano/claude-task-master/pull/950) [`699e9ee`](https://github.com/eyaltoledano/claude-task-master/commit/699e9eefb5d687b256e9402d686bdd5e3a358b4a) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add support for xAI Grok 4 model
  - Add grok-4 model to xAI provider with $3/$15 per 1M token pricing
  - Enable main, fallback, and research roles for grok-4
  - Max tokens set to 131,072 (matching other xAI models)

- [#946](https://github.com/eyaltoledano/claude-task-master/pull/946) [`5f009a5`](https://github.com/eyaltoledano/claude-task-master/commit/5f009a5e1fc10e37be26f5135df4b7f44a9c5320) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add stricter validation and clearer feedback for task priority when adding new tasks
  - if a task priority is invalid, it will default to medium
  - made taks priority case-insensitive, essentially making HIGH and high the same value

- [#863](https://github.com/eyaltoledano/claude-task-master/pull/863) [`b530657`](https://github.com/eyaltoledano/claude-task-master/commit/b53065713c8da0ae6f18eb2655397aa975004923) Thanks [@OrenMe](https://github.com/OrenMe)! - Add support for MCP Sampling as AI provider, requires no API key, uses the client LLM provider

- [#930](https://github.com/eyaltoledano/claude-task-master/pull/930) [`98d1c97`](https://github.com/eyaltoledano/claude-task-master/commit/98d1c974361a56ddbeb772b1272986b9d3913459) Thanks [@OmarElKadri](https://github.com/OmarElKadri)! - Added Groq provider support

### Patch Changes

- [#916](https://github.com/eyaltoledano/claude-task-master/pull/916) [`6c88a4a`](https://github.com/eyaltoledano/claude-task-master/commit/6c88a4a749083e3bd2d073a9240799771774495a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Recover from `@anthropic-ai/claude-code` JSON truncation bug that caused Task Master to crash when handling large (>8 kB) structured responses. The CLI/SDK still truncates, but Task Master now detects the error, preserves buffered text, and returns a usable response instead of throwing.

- [#916](https://github.com/eyaltoledano/claude-task-master/pull/916) [`3334e40`](https://github.com/eyaltoledano/claude-task-master/commit/3334e409ae659d5223bb136ae23fd22c5e219073) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Updating dependency ai-sdk-provider-gemini-cli to 0.0.4 to address breaking change Google made to Gemini CLI and add better 'api-key' in addition to 'gemini-api-key' AI-SDK compatibility.

- [#853](https://github.com/eyaltoledano/claude-task-master/pull/853) [`95c299d`](https://github.com/eyaltoledano/claude-task-master/commit/95c299df642bd8e6d75f8fa5110ac705bcc72edf) Thanks [@joedanz](https://github.com/joedanz)! - Unify and streamline profile system architecture for improved maintainability

## 0.19.0

### Minor Changes

- [#897](https://github.com/eyaltoledano/claude-task-master/pull/897) [`dd96f51`](https://github.com/eyaltoledano/claude-task-master/commit/dd96f51179d9901f6ae854b0c60f0bcc8c13ae0d) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Adds support for gemini-cli as a provider, enabling free or subscription use through Google Accounts and paid Gemini Cloud Assist (GCA) subscriptions.

- [#884](https://github.com/eyaltoledano/claude-task-master/pull/884) [`5eafc5e`](https://github.com/eyaltoledano/claude-task-master/commit/5eafc5ea112c91326bb8abda7a78d7c2a4fa16a1) Thanks [@geoh](https://github.com/geoh)! - Added option for the AI to determine the number of tasks required based entirely on complexity

- [#872](https://github.com/eyaltoledano/claude-task-master/pull/872) [`f7fbdd6`](https://github.com/eyaltoledano/claude-task-master/commit/f7fbdd6755c4a1ee3ab2a3f435961f249fa19c15) Thanks [@geoh](https://github.com/geoh)! - Add advanced settings for Claude Code AI Provider

- [#870](https://github.com/eyaltoledano/claude-task-master/pull/870) [`6fd5e23`](https://github.com/eyaltoledano/claude-task-master/commit/6fd5e23396a7e348ea2300e67cbd0c97141c081f) Thanks [@nishedcob](https://github.com/nishedcob)! - Include additional Anthropic models running on Bedrock in what is supported

- [#510](https://github.com/eyaltoledano/claude-task-master/pull/510) [`c99df64`](https://github.com/eyaltoledano/claude-task-master/commit/c99df64f651fb40bae5d7979ee2b2428586f44d3) Thanks [@shenysun](https://github.com/shenysun)! - Add support for custom response language

### Patch Changes

- [#892](https://github.com/eyaltoledano/claude-task-master/pull/892) [`56a415e`](https://github.com/eyaltoledano/claude-task-master/commit/56a415ef795c5aa0e52e7419af8d4f4862611a8c) Thanks [@joedanz](https://github.com/joedanz)! - Ensure projectRoot is a string (potential WSL fix)

- [#856](https://github.com/eyaltoledano/claude-task-master/pull/856) [`43e0025`](https://github.com/eyaltoledano/claude-task-master/commit/43e0025f4c5870a3c56682cbb8fe0348d711953b) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Fix bulk update tag corruption in tagged task lists

- [#857](https://github.com/eyaltoledano/claude-task-master/pull/857) [`598e687`](https://github.com/eyaltoledano/claude-task-master/commit/598e687067d1af44f1a9916266ae94af3e752067) Thanks [@mm-parthy](https://github.com/mm-parthy)! - Fix expand-task to use tag-specific complexity reports

  The expand-task function now correctly uses complexity reports specific to the current tag context (e.g., task-complexity-report_feature-branch.json) instead of always using the default task-complexity-report.json file. This enables proper task expansion behavior when working with multiple tag contexts.

- [#855](https://github.com/eyaltoledano/claude-task-master/pull/855) [`e4456b1`](https://github.com/eyaltoledano/claude-task-master/commit/e4456b11bc3ae46e120d244fc32c1807a8a58a57) Thanks [@joedanz](https://github.com/joedanz)! - Fix .gitignore missing trailing newline during project initialization

- [#846](https://github.com/eyaltoledano/claude-task-master/pull/846) [`59a4ec9`](https://github.com/eyaltoledano/claude-task-master/commit/59a4ec9e1a452079e5c78c00428d140f13a1c8f6) Thanks [@joedanz](https://github.com/joedanz)! - Default to Cursor profile for MCP init when no rules specified

- [#852](https://github.com/eyaltoledano/claude-task-master/pull/852) [`f38abd6`](https://github.com/eyaltoledano/claude-task-master/commit/f38abd68436ea5d093b2e22c2b8520b6e6906251) Thanks [@hrmshandy](https://github.com/hrmshandy)! - fixes a critical issue where subtask generation fails on gemini-2.5-pro unless explicitly prompted to return 'details' field as a string not an object

- [#908](https://github.com/eyaltoledano/claude-task-master/pull/908) [`24e9206`](https://github.com/eyaltoledano/claude-task-master/commit/24e9206da0d5d3f2f7819ed94fa0c9b459fc9f9b) Thanks [@joedanz](https://github.com/joedanz)! - Fix rules command to use reliable project root detection like other commands

## 0.18.0

### Minor Changes

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Can now configure baseURL of provider with `<PROVIDER>_BASE_URL`
  - For example:
    - `OPENAI_BASE_URL`

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added comprehensive rule profile management:

  **New Profile Support**: Added comprehensive IDE profile support with eight specialized profiles: Claude Code, Cline, Codex, Cursor, Roo, Trae, VS Code, and Windsurf. Each profile is optimized for its respective IDE with appropriate mappings and configuration.
  **Initialization**: You can now specify which rule profiles to include at project initialization using `--rules <profiles>` or `-r <profiles>` (e.g., `task-master init -r cursor,roo`). Only the selected profiles and configuration are included.
  **Add/Remove Commands**: `task-master rules add <profiles>` and `task-master rules remove <profiles>` let you manage specific rule profiles and MCP config after initialization, supporting multiple profiles at once.
  **Interactive Setup**: `task-master rules setup` launches an interactive prompt to select which rule profiles to add to your project. This does **not** re-initialize your project or affect shell aliases; it only manages rules.
  **Selective Removal**: Rules removal intelligently preserves existing non-Task Master rules and files and only removes Task Master-specific rules. Profile directories are only removed when completely empty and all conditions are met (no existing rules, no other files/folders, MCP config completely removed).
  **Safety Features**: Confirmation messages clearly explain that only Task Master-specific rules and MCP configurations will be removed, while preserving existing custom rules and other files.
  **Robust Validation**: Includes comprehensive checks for array types in MCP config processing and error handling throughout the rules management system.

  This enables more flexible, rule-specific project setups with intelligent cleanup that preserves user customizations while safely managing Task Master components.
  - Resolves #338

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Make task-master more compatible with the "o" family models of OpenAI

  Now works well with:
  - o3
  - o3-mini
  - etc.

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add better support for python projects by adding `pyproject.toml` as a projectRoot marker

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - - **Git Worktree Detection:**
  - Now properly skips Git initialization when inside existing Git worktree
  - Prevents accidental nested repository creation
  - **Flag System Overhaul:**
    - `--git`/`--no-git` controls repository initialization
    - `--aliases`/`--no-aliases` consistently manages shell alias creation
    - `--git-tasks`/`--no-git-tasks` controls whether task files are stored in Git
    - `--dry-run` accurately previews all initialization behaviors
  - **GitTasks Functionality:**
    - New `--git-tasks` flag includes task files in Git (comments them out in .gitignore)
    - New `--no-git-tasks` flag excludes task files from Git (default behavior)
    - Supports both CLI and MCP interfaces with proper parameter passing

  **Implementation Details:**
  - Added explicit Git worktree detection before initialization
  - Refactored flag processing to ensure consistent behavior
  - Fixes #734

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code provider support

  Introduces a new provider that enables using Claude models (Opus and Sonnet) through the Claude Code CLI without requiring an API key.

  Key features:
  - New claude-code provider with support for opus and sonnet models
  - No API key required - uses local Claude Code CLI installation
  - Optional dependency - won't affect users who don't need Claude Code
  - Lazy loading ensures the provider only loads when requested
  - Full integration with existing Task Master commands and workflows
  - Comprehensive test coverage for reliability
  - New --claude-code flag for the models command

  Users can now configure Claude Code models with:
  task-master models --set-main sonnet --claude-code
  task-master models --set-research opus --claude-code

  The @anthropic-ai/claude-code package is optional and won't be installed unless explicitly needed.

### Patch Changes

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix expand command preserving tagged task structure and preventing data corruption
  - Enhance E2E tests with comprehensive tag-aware expand testing to verify tag corruption fix
  - Add new test section for feature-expand tag creation and testing during expand operations
  - Verify tag preservation during expand, force expand, and expand --all operations
  - Test that master tag remains intact while feature-expand tag receives subtasks correctly
  - Fix file path references to use correct .taskmaster/config.json and .taskmaster/tasks/tasks.json locations
  - All tag corruption verification tests pass successfully, confirming the expand command tag corruption bug fix works as expected

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix Cursor deeplink installation by providing copy-paste instructions for GitHub compatibility

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Call rules interactive setup during init

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Update o3 model price

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improves Amazon Bedrock support

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix issues with task creation/update where subtasks are being created like id: <parent_task>.<subtask> instead if just id: <subtask>

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixes issue with expand CLI command "Complexity report not found"
  - Closes #735
  - Closes #728

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Store tasks in Git by default

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve provider validation system with clean constants structure
  - **Fixed "Invalid provider hint" errors**: Resolved validation failures for Azure, Vertex, and Bedrock providers
  - **Improved search UX**: Integrated search for better model discovery with real-time filtering
  - **Better organization**: Moved custom provider options to bottom of model selection with clear section separators

  This change ensures all custom providers (Azure, Vertex, Bedrock, OpenRouter, Ollama) work correctly in `task-master models --setup`

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix weird `task-master init` bug when using in certain environments

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Rename Roo Code Boomerang role to Orchestrator

- [#840](https://github.com/eyaltoledano/claude-task-master/pull/840) [`b40139c`](https://github.com/eyaltoledano/claude-task-master/commit/b40139ca0517fd76aea4f41d0ed4c10e658a5d2b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve mcp keys check in cursor

## 0.18.0-rc.0

### Minor Changes

- [#830](https://github.com/eyaltoledano/claude-task-master/pull/830) [`e9d1bc2`](https://github.com/eyaltoledano/claude-task-master/commit/e9d1bc2385521c08374a85eba7899e878a51066c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Can now configure baseURL of provider with `<PROVIDER>_BASE_URL`
  - For example:
    - `OPENAI_BASE_URL`

- [#460](https://github.com/eyaltoledano/claude-task-master/pull/460) [`a09a2d0`](https://github.com/eyaltoledano/claude-task-master/commit/a09a2d0967a10276623e3f3ead3ed577c15ce62f) Thanks [@joedanz](https://github.com/joedanz)! - Added comprehensive rule profile management:

  **New Profile Support**: Added comprehensive IDE profile support with eight specialized profiles: Claude Code, Cline, Codex, Cursor, Roo, Trae, VS Code, and Windsurf. Each profile is optimized for its respective IDE with appropriate mappings and configuration.
  **Initialization**: You can now specify which rule profiles to include at project initialization using `--rules <profiles>` or `-r <profiles>` (e.g., `task-master init -r cursor,roo`). Only the selected profiles and configuration are included.
  **Add/Remove Commands**: `task-master rules add <profiles>` and `task-master rules remove <profiles>` let you manage specific rule profiles and MCP config after initialization, supporting multiple profiles at once.
  **Interactive Setup**: `task-master rules setup` launches an interactive prompt to select which rule profiles to add to your project. This does **not** re-initialize your project or affect shell aliases; it only manages rules.
  **Selective Removal**: Rules removal intelligently preserves existing non-Task Master rules and files and only removes Task Master-specific rules. Profile directories are only removed when completely empty and all conditions are met (no existing rules, no other files/folders, MCP config completely removed).
  **Safety Features**: Confirmation messages clearly explain that only Task Master-specific rules and MCP configurations will be removed, while preserving existing custom rules and other files.
  **Robust Validation**: Includes comprehensive checks for array types in MCP config processing and error handling throughout the rules management system.

  This enables more flexible, rule-specific project setups with intelligent cleanup that preserves user customizations while safely managing Task Master components.
  - Resolves #338

- [#804](https://github.com/eyaltoledano/claude-task-master/pull/804) [`1b8c320`](https://github.com/eyaltoledano/claude-task-master/commit/1b8c320c570473082f1eb4bf9628bff66e799092) Thanks [@ejones40](https://github.com/ejones40)! - Add better support for python projects by adding `pyproject.toml` as a projectRoot marker

- [#743](https://github.com/eyaltoledano/claude-task-master/pull/743) [`a2a3229`](https://github.com/eyaltoledano/claude-task-master/commit/a2a3229fd01e24a5838f11a3938a77250101e184) Thanks [@joedanz](https://github.com/joedanz)! - - **Git Worktree Detection:**
  - Now properly skips Git initialization when inside existing Git worktree
  - Prevents accidental nested repository creation
  - **Flag System Overhaul:**
    - `--git`/`--no-git` controls repository initialization
    - `--aliases`/`--no-aliases` consistently manages shell alias creation
    - `--git-tasks`/`--no-git-tasks` controls whether task files are stored in Git
    - `--dry-run` accurately previews all initialization behaviors
  - **GitTasks Functionality:**
    - New `--git-tasks` flag includes task files in Git (comments them out in .gitignore)
    - New `--no-git-tasks` flag excludes task files from Git (default behavior)
    - Supports both CLI and MCP interfaces with proper parameter passing

  **Implementation Details:**
  - Added explicit Git worktree detection before initialization
  - Refactored flag processing to ensure consistent behavior
  - Fixes #734

- [#829](https://github.com/eyaltoledano/claude-task-master/pull/829) [`4b0c9d9`](https://github.com/eyaltoledano/claude-task-master/commit/4b0c9d9af62d00359fca3f43283cf33223d410bc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code provider support

  Introduces a new provider that enables using Claude models (Opus and Sonnet) through the Claude Code CLI without requiring an API key.

  Key features:
  - New claude-code provider with support for opus and sonnet models
  - No API key required - uses local Claude Code CLI installation
  - Optional dependency - won't affect users who don't need Claude Code
  - Lazy loading ensures the provider only loads when requested
  - Full integration with existing Task Master commands and workflows
  - Comprehensive test coverage for reliability
  - New --claude-code flag for the models command

  Users can now configure Claude Code models with:
  task-master models --set-main sonnet --claude-code
  task-master models --set-research opus --claude-code

  The @anthropic-ai/claude-code package is optional and won't be installed unless explicitly needed.

### Patch Changes

- [#827](https://github.com/eyaltoledano/claude-task-master/pull/827) [`5da5b59`](https://github.com/eyaltoledano/claude-task-master/commit/5da5b59bdeeb634dcb3adc7a9bc0fc37e004fa0c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix expand command preserving tagged task structure and preventing data corruption
  - Enhance E2E tests with comprehensive tag-aware expand testing to verify tag corruption fix
  - Add new test section for feature-expand tag creation and testing during expand operations
  - Verify tag preservation during expand, force expand, and expand --all operations
  - Test that master tag remains intact while feature-expand tag receives subtasks correctly
  - Fix file path references to use correct .taskmaster/config.json and .taskmaster/tasks/tasks.json locations
  - All tag corruption verification tests pass successfully, confirming the expand command tag corruption bug fix works as expected

- [#833](https://github.com/eyaltoledano/claude-task-master/pull/833) [`cf2c066`](https://github.com/eyaltoledano/claude-task-master/commit/cf2c06697a0b5b952fb6ca4b3c923e9892604d08) Thanks [@joedanz](https://github.com/joedanz)! - Call rules interactive setup during init

- [#826](https://github.com/eyaltoledano/claude-task-master/pull/826) [`7811227`](https://github.com/eyaltoledano/claude-task-master/commit/78112277b3caa4539e6e29805341a944799fb0e7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improves Amazon Bedrock support

- [#834](https://github.com/eyaltoledano/claude-task-master/pull/834) [`6483537`](https://github.com/eyaltoledano/claude-task-master/commit/648353794eb60d11ffceda87370a321ad310fbd7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix issues with task creation/update where subtasks are being created like id: <parent_task>.<subtask> instead if just id: <subtask>

- [#835](https://github.com/eyaltoledano/claude-task-master/pull/835) [`727f1ec`](https://github.com/eyaltoledano/claude-task-master/commit/727f1ec4ebcbdd82547784c4c113b666af7e122e) Thanks [@joedanz](https://github.com/joedanz)! - Store tasks in Git by default

- [#822](https://github.com/eyaltoledano/claude-task-master/pull/822) [`1bd6d4f`](https://github.com/eyaltoledano/claude-task-master/commit/1bd6d4f2468070690e152e6e63e15a57bc550d90) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve provider validation system with clean constants structure
  - **Fixed "Invalid provider hint" errors**: Resolved validation failures for Azure, Vertex, and Bedrock providers
  - **Improved search UX**: Integrated search for better model discovery with real-time filtering
  - **Better organization**: Moved custom provider options to bottom of model selection with clear section separators

  This change ensures all custom providers (Azure, Vertex, Bedrock, OpenRouter, Ollama) work correctly in `task-master models --setup`

- [#633](https://github.com/eyaltoledano/claude-task-master/pull/633) [`3a2325a`](https://github.com/eyaltoledano/claude-task-master/commit/3a2325a963fed82377ab52546eedcbfebf507a7e) Thanks [@nmarley](https://github.com/nmarley)! - Fix weird `task-master init` bug when using in certain environments

- [#831](https://github.com/eyaltoledano/claude-task-master/pull/831) [`b592dff`](https://github.com/eyaltoledano/claude-task-master/commit/b592dff8bc5c5d7966843fceaa0adf4570934336) Thanks [@joedanz](https://github.com/joedanz)! - Rename Roo Code Boomerang role to Orchestrator

- [#830](https://github.com/eyaltoledano/claude-task-master/pull/830) [`e9d1bc2`](https://github.com/eyaltoledano/claude-task-master/commit/e9d1bc2385521c08374a85eba7899e878a51066c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve mcp keys check in cursor

## 0.17.1

### Patch Changes

- [#789](https://github.com/eyaltoledano/claude-task-master/pull/789) [`8cde6c2`](https://github.com/eyaltoledano/claude-task-master/commit/8cde6c27087f401d085fe267091ae75334309d96) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix contextGatherer bug when adding a task `Cannot read properties of undefined (reading 'forEach')`

## 0.18.0-rc.0

### Minor Changes

- [#830](https://github.com/eyaltoledano/claude-task-master/pull/830) [`e9d1bc2`](https://github.com/eyaltoledano/claude-task-master/commit/e9d1bc2385521c08374a85eba7899e878a51066c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Can now configure baseURL of provider with `<PROVIDER>_BASE_URL`
  - For example:
    - `OPENAI_BASE_URL`

- [#460](https://github.com/eyaltoledano/claude-task-master/pull/460) [`a09a2d0`](https://github.com/eyaltoledano/claude-task-master/commit/a09a2d0967a10276623e3f3ead3ed577c15ce62f) Thanks [@joedanz](https://github.com/joedanz)! - Added comprehensive rule profile management:

  **New Profile Support**: Added comprehensive IDE profile support with eight specialized profiles: Claude Code, Cline, Codex, Cursor, Roo, Trae, VS Code, and Windsurf. Each profile is optimized for its respective IDE with appropriate mappings and configuration.
  **Initialization**: You can now specify which rule profiles to include at project initialization using `--rules <profiles>` or `-r <profiles>` (e.g., `task-master init -r cursor,roo`). Only the selected profiles and configuration are included.
  **Add/Remove Commands**: `task-master rules add <profiles>` and `task-master rules remove <profiles>` let you manage specific rule profiles and MCP config after initialization, supporting multiple profiles at once.
  **Interactive Setup**: `task-master rules setup` launches an interactive prompt to select which rule profiles to add to your project. This does **not** re-initialize your project or affect shell aliases; it only manages rules.
  **Selective Removal**: Rules removal intelligently preserves existing non-Task Master rules and files and only removes Task Master-specific rules. Profile directories are only removed when completely empty and all conditions are met (no existing rules, no other files/folders, MCP config completely removed).
  **Safety Features**: Confirmation messages clearly explain that only Task Master-specific rules and MCP configurations will be removed, while preserving existing custom rules and other files.
  **Robust Validation**: Includes comprehensive checks for array types in MCP config processing and error handling throughout the rules management system.

  This enables more flexible, rule-specific project setups with intelligent cleanup that preserves user customizations while safely managing Task Master components.
  - Resolves #338

- [#804](https://github.com/eyaltoledano/claude-task-master/pull/804) [`1b8c320`](https://github.com/eyaltoledano/claude-task-master/commit/1b8c320c570473082f1eb4bf9628bff66e799092) Thanks [@ejones40](https://github.com/ejones40)! - Add better support for python projects by adding `pyproject.toml` as a projectRoot marker

- [#743](https://github.com/eyaltoledano/claude-task-master/pull/743) [`a2a3229`](https://github.com/eyaltoledano/claude-task-master/commit/a2a3229fd01e24a5838f11a3938a77250101e184) Thanks [@joedanz](https://github.com/joedanz)! - - **Git Worktree Detection:**
  - Now properly skips Git initialization when inside existing Git worktree
  - Prevents accidental nested repository creation
  - **Flag System Overhaul:**
    - `--git`/`--no-git` controls repository initialization
    - `--aliases`/`--no-aliases` consistently manages shell alias creation
    - `--git-tasks`/`--no-git-tasks` controls whether task files are stored in Git
    - `--dry-run` accurately previews all initialization behaviors
  - **GitTasks Functionality:**
    - New `--git-tasks` flag includes task files in Git (comments them out in .gitignore)
    - New `--no-git-tasks` flag excludes task files from Git (default behavior)
    - Supports both CLI and MCP interfaces with proper parameter passing

  **Implementation Details:**
  - Added explicit Git worktree detection before initialization
  - Refactored flag processing to ensure consistent behavior
  - Fixes #734

- [#829](https://github.com/eyaltoledano/claude-task-master/pull/829) [`4b0c9d9`](https://github.com/eyaltoledano/claude-task-master/commit/4b0c9d9af62d00359fca3f43283cf33223d410bc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code provider support

  Introduces a new provider that enables using Claude models (Opus and Sonnet) through the Claude Code CLI without requiring an API key.

  Key features:
  - New claude-code provider with support for opus and sonnet models
  - No API key required - uses local Claude Code CLI installation
  - Optional dependency - won't affect users who don't need Claude Code
  - Lazy loading ensures the provider only loads when requested
  - Full integration with existing Task Master commands and workflows
  - Comprehensive test coverage for reliability
  - New --claude-code flag for the models command

  Users can now configure Claude Code models with:
  task-master models --set-main sonnet --claude-code
  task-master models --set-research opus --claude-code

  The @anthropic-ai/claude-code package is optional and won't be installed unless explicitly needed.

### Patch Changes

- [#827](https://github.com/eyaltoledano/claude-task-master/pull/827) [`5da5b59`](https://github.com/eyaltoledano/claude-task-master/commit/5da5b59bdeeb634dcb3adc7a9bc0fc37e004fa0c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix expand command preserving tagged task structure and preventing data corruption
  - Enhance E2E tests with comprehensive tag-aware expand testing to verify tag corruption fix
  - Add new test section for feature-expand tag creation and testing during expand operations
  - Verify tag preservation during expand, force expand, and expand --all operations
  - Test that master tag remains intact while feature-expand tag receives subtasks correctly
  - Fix file path references to use correct .taskmaster/config.json and .taskmaster/tasks/tasks.json locations
  - All tag corruption verification tests pass successfully, confirming the expand command tag corruption bug fix works as expected

- [#833](https://github.com/eyaltoledano/claude-task-master/pull/833) [`cf2c066`](https://github.com/eyaltoledano/claude-task-master/commit/cf2c06697a0b5b952fb6ca4b3c923e9892604d08) Thanks [@joedanz](https://github.com/joedanz)! - Call rules interactive setup during init

- [#826](https://github.com/eyaltoledano/claude-task-master/pull/826) [`7811227`](https://github.com/eyaltoledano/claude-task-master/commit/78112277b3caa4539e6e29805341a944799fb0e7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improves Amazon Bedrock support

- [#834](https://github.com/eyaltoledano/claude-task-master/pull/834) [`6483537`](https://github.com/eyaltoledano/claude-task-master/commit/648353794eb60d11ffceda87370a321ad310fbd7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix issues with task creation/update where subtasks are being created like id: <parent_task>.<subtask> instead if just id: <subtask>

- [#835](https://github.com/eyaltoledano/claude-task-master/pull/835) [`727f1ec`](https://github.com/eyaltoledano/claude-task-master/commit/727f1ec4ebcbdd82547784c4c113b666af7e122e) Thanks [@joedanz](https://github.com/joedanz)! - Store tasks in Git by default

- [#822](https://github.com/eyaltoledano/claude-task-master/pull/822) [`1bd6d4f`](https://github.com/eyaltoledano/claude-task-master/commit/1bd6d4f2468070690e152e6e63e15a57bc550d90) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve provider validation system with clean constants structure
  - **Fixed "Invalid provider hint" errors**: Resolved validation failures for Azure, Vertex, and Bedrock providers
  - **Improved search UX**: Integrated search for better model discovery with real-time filtering
  - **Better organization**: Moved custom provider options to bottom of model selection with clear section separators

  This change ensures all custom providers (Azure, Vertex, Bedrock, OpenRouter, Ollama) work correctly in `task-master models --setup`

- [#633](https://github.com/eyaltoledano/claude-task-master/pull/633) [`3a2325a`](https://github.com/eyaltoledano/claude-task-master/commit/3a2325a963fed82377ab52546eedcbfebf507a7e) Thanks [@nmarley](https://github.com/nmarley)! - Fix weird `task-master init` bug when using in certain environments

- [#831](https://github.com/eyaltoledano/claude-task-master/pull/831) [`b592dff`](https://github.com/eyaltoledano/claude-task-master/commit/b592dff8bc5c5d7966843fceaa0adf4570934336) Thanks [@joedanz](https://github.com/joedanz)! - Rename Roo Code Boomerang role to Orchestrator

- [#830](https://github.com/eyaltoledano/claude-task-master/pull/830) [`e9d1bc2`](https://github.com/eyaltoledano/claude-task-master/commit/e9d1bc2385521c08374a85eba7899e878a51066c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve mcp keys check in cursor

## 0.17.1

### Patch Changes

- [#789](https://github.com/eyaltoledano/claude-task-master/pull/789) [`8cde6c2`](https://github.com/eyaltoledano/claude-task-master/commit/8cde6c27087f401d085fe267091ae75334309d96) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix contextGatherer bug when adding a task `Cannot read properties of undefined (reading 'forEach')`

## 0.17.0

### Minor Changes

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add comprehensive AI-powered research command with intelligent context gathering and interactive follow-ups.

  The new `research` command provides AI-powered research capabilities that automatically gather relevant project context to answer your questions. The command intelligently selects context from multiple sources and supports interactive follow-up questions in CLI mode.

  **Key Features:**
  - **Intelligent Task Discovery**: Automatically finds relevant tasks and subtasks using fuzzy search based on your query keywords, supplementing any explicitly provided task IDs
  - **Multi-Source Context**: Gathers context from tasks, files, project structure, and custom text to provide comprehensive answers
  - **Interactive Follow-ups**: CLI users can ask follow-up questions that build on the conversation history while allowing fresh context discovery for each question
  - **Flexible Detail Levels**: Choose from low (concise), medium (balanced), or high (comprehensive) response detail levels
  - **Token Transparency**: Displays detailed token breakdown showing context size, sources, and estimated costs
  - **Enhanced Display**: Syntax-highlighted code blocks and structured output with clear visual separation

  **Usage Examples:**

  ```bash
  # Basic research with auto-discovered context
  task-master research "How should I implement user authentication?"

  # Research with specific task context
  task-master research "What's the best approach for this?" --id=15,23.2

  # Research with file context and project tree
  task-master research "How does the current auth system work?" --files=src/auth.js,config/auth.json --tree

  # Research with custom context and low detail
  task-master research "Quick implementation steps?" --context="Using JWT tokens" --detail=low
  ```

  **Context Sources:**
  - **Tasks**: Automatically discovers relevant tasks/subtasks via fuzzy search, plus any explicitly specified via `--id`
  - **Files**: Include specific files via `--files` for code-aware responses
  - **Project Tree**: Add `--tree` to include project structure overview
  - **Custom Context**: Provide additional context via `--context` for domain-specific information

  **Interactive Features (CLI only):**
  - Follow-up questions that maintain conversation history
  - Fresh fuzzy search for each follow-up to discover newly relevant tasks
  - Cumulative context building across the conversation
  - Clean visual separation between exchanges
  - **Save to Tasks**: Save entire research conversations (including follow-ups) directly to task or subtask details with timestamps
  - **Clean Menu Interface**: Streamlined inquirer-based menu for follow-up actions without redundant UI elements

  **Save Functionality:**

  The research command now supports saving complete conversation threads to tasks or subtasks:
  - Save research results and follow-up conversations to any task (e.g., "15") or subtask (e.g., "15.2")
  - Automatic timestamping and formatting of conversation history
  - Validation of task/subtask existence before saving
  - Appends to existing task details without overwriting content
  - Supports both CLI interactive mode and MCP programmatic access via `--save-to` flag

  **Enhanced CLI Options:**

  ```bash
  # Auto-save research results to a task
  task-master research "Implementation approach?" --save-to=15

  # Combine auto-save with context gathering
  task-master research "How to optimize this?" --id=23 --save-to=23.1
  ```

  **MCP Integration:**
  - `saveTo` parameter for automatic saving to specified task/subtask ID
  - Structured response format with telemetry data
  - Silent operation mode for programmatic usage
  - Full feature parity with CLI except interactive follow-ups

  The research command integrates with the existing AI service layer and supports all configured AI providers. Both CLI and MCP interfaces provide comprehensive research capabilities with intelligent context gathering and flexible output options.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhance update-task with --append flag for timestamped task updates

  Adds the `--append` flag to `update-task` command, enabling it to behave like `update-subtask` with timestamped information appending. This provides more flexible task updating options:

  **CLI Enhancement:**
  - `task-master update-task --id=5 --prompt="New info"` - Full task update (existing behavior)
  - `task-master update-task --id=5 --append --prompt="Progress update"` - Append timestamped info to task details

  **Full MCP Integration:**
  - MCP tool `update_task` now supports `append` parameter
  - Seamless integration with Cursor and other MCP clients
  - Consistent behavior between CLI and MCP interfaces

  Instead of requiring separate subtask creation for progress tracking, you can now append timestamped information directly to parent tasks while preserving the option for comprehensive task updates.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add --tag flag support to core commands for multi-context task management. Commands like parse-prd, analyze-complexity, and others now support targeting specific task lists, enabling rapid prototyping and parallel development workflows.

  Key features:
  - parse-prd --tag=feature-name: Parse PRDs into separate task contexts on the fly
  - analyze-complexity --tag=branch: Generate tag-specific complexity reports
  - All task operations can target specific contexts while preserving other lists
  - Non-existent tags are created automatically for seamless workflow

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Introduces Tagged Lists: AI Multi-Context Task Management System

  This major feature release introduces Tagged Lists, a comprehensive system that transforms Taskmaster into a multi-context task management powerhouse. You can now organize tasks into completely isolated contexts, enabling parallel (agentic) development workflows, team collaboration, and project experimentation without conflicts.

  **🏷️ Tagged Task Lists Architecture:**

  The new tagged system fundamentally improves how tasks are organized:
  - **Legacy Format**: `{ "tasks": [...] }`
  - **New Tagged Format**: `{ "master": { "tasks": [...], "metadata": {...} }, "feature-xyz": { "tasks": [...], "metadata": {...} } }`
  - **Automatic Migration**: Existing projects will seamlessly migrate to tagged format with zero user intervention
  - **State Management**: New `.taskmaster/state.json` tracks current tag, last switched time, migration status and more.
  - **Configuration Integration**: Enhanced `.taskmaster/config.json` with tag-specific settings and defaults.

  By default, your existing task list will be migrated to the `master` tag.

  **🚀 Complete Tag Management Suite:**

  **Core Tag Commands:**
  - `task-master tags [--show-metadata]` - List all tags with task counts, completion stats, and metadata
  - `task-master add-tag <name> [options]` - Create new tag contexts with optional task copying
  - `task-master delete-tag <name> [--yes]` - Delete tags (and attached tasks) with double confirmation protection
  - `task-master use-tag <name>` - Switch contexts and immediately see next available task
  - `task-master rename-tag <old> <new>` - Rename tags with automatic current tag reference updates
  - `task-master copy-tag <source> <target> [options]` - Duplicate tag contexts for experimentation

  **🤖 Full MCP Integration for Tag Management:**

  Task Master's multi-context capabilities are now fully exposed through the MCP server, enabling powerful agentic workflows:
  - **`list_tags`**: List all available tag contexts.
  - **`add_tag`**: Programmatically create new tags.
  - **`delete_tag`**: Remove tag contexts.
  - **`use_tag`**: Switch the agent's active task context.
  - **`rename_tag`**: Rename existing tags.
  - **`copy_tag`**: Duplicate entire task contexts for experimentation.

  **Tag Creation Options:**
  - `--copy-from-current` - Copy tasks from currently active tag
  - `--copy-from=<tag>` - Copy tasks from specific tag
  - `--from-branch` - Creates a new tag using the active git branch name (for `add-tag` only)
  - `--description="<text>"` - Add custom tag descriptions
  - Empty tag creation for fresh contexts

  **🎯 Universal --tag Flag Support:**

  Every task operation now supports tag-specific execution:
  - `task-master list --tag=feature-branch` - View tasks in specific context
  - `task-master add-task --tag=experiment --prompt="..."` - Create tasks in specific tag
  - `task-master parse-prd document.txt --tag=v2-redesign` - Parse PRDs into dedicated contexts
  - `task-master analyze-complexity --tag=performance-work` - Generate tag-specific reports
  - `task-master set-status --tag=hotfix --id=5 --status=done` - Update tasks in specific contexts
  - `task-master expand --tag=research --id=3` - Break down tasks within tag contexts

  This way you or your agent can store out of context tasks into the appropriate tags for later, allowing you to maintain a groomed and scoped master list. Focus on value, not chores.

  **📊 Enhanced Workflow Features:**

  **Smart Context Switching:**
  - `use-tag` command shows immediate next task after switching
  - Automatic tag creation when targeting non-existent tags
  - Current tag persistence across terminal sessions
  - Branch-tag mapping for future Git integration

  **Intelligent File Management:**
  - Tag-specific complexity reports: `task-complexity-report_tagname.json`
  - Master tag uses default filenames: `task-complexity-report.json`
  - Automatic file isolation prevents cross-tag contamination

  **Advanced Confirmation Logic:**
  - Commands only prompt when target tag has existing tasks
  - Empty tags allow immediate operations without confirmation
  - Smart append vs overwrite detection

  **🔄 Seamless Migration & Compatibility:**

  **Zero-Disruption Migration:**
  - Existing `tasks.json` files automatically migrate on first command
  - Master tag receives proper metadata (creation date, description)
  - Migration notice shown once with helpful explanation
  - All existing commands work identically to before

  **State Management:**
  - `.taskmaster/state.json` tracks current tag and migration status
  - Automatic state creation and maintenance
  - Branch-tag mapping foundation for Git integration
  - Migration notice tracking to avoid repeated notifications
  - Grounds for future context additions

  **Backward Compatibility:**
  - All existing workflows continue unchanged
  - Legacy commands work exactly as before
  - Gradual adoption - users can ignore tags entirely if desired
  - No breaking changes to existing tasks or file formats

  **💡 Real-World Use Cases:**

  **Team Collaboration:**
  - `task-master add-tag alice --copy-from-current` - Create teammate-specific contexts
  - `task-master add-tag bob --copy-from=master` - Onboard new team members
  - `task-master use-tag alice` - Switch to teammate's work context

  **Feature Development:**
  - `task-master parse-prd feature-spec.txt --tag=user-auth` - Dedicated feature planning
  - `task-master add-tag experiment --copy-from=user-auth` - Safe experimentation
  - `task-master analyze-complexity --tag=user-auth` - Feature-specific analysis

  **Release Management:**
  - `task-master add-tag v2.0 --description="Next major release"` - Version-specific planning
  - `task-master copy-tag master v2.1` - Release branch preparation
  - `task-master use-tag hotfix` - Emergency fix context

  **Project Phases:**
  - `task-master add-tag research --description="Discovery phase"` - Research tasks
  - `task-master add-tag implementation --copy-from=research` - Development phase
  - `task-master add-tag testing --copy-from=implementation` - QA phase

  **🛠️ Technical Implementation:**

  **Data Structure:**
  - Tagged format with complete isolation between contexts
  - Rich metadata per tag (creation date, description, update tracking)
  - Automatic metadata enhancement for existing tags
  - Clean separation of tag data and internal state

  **Performance Optimizations:**
  - Dynamic task counting without stored counters
  - Efficient tag resolution and caching
  - Minimal file I/O with smart data loading
  - Responsive table layouts adapting to terminal width

  **Error Handling:**
  - Comprehensive validation for tag names (alphanumeric, hyphens, underscores)
  - Reserved name protection (master, main, default)
  - Graceful handling of missing tags and corrupted data
  - Detailed error messages with suggested corrections

  This release establishes the foundation for advanced multi-context workflows while maintaining the simplicity and power that makes Task Master effective for individual developers.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Research Save-to-File Feature & Critical MCP Tag Corruption Fix

  **🔬 New Research Save-to-File Functionality:**

  Added comprehensive save-to-file capability to the research command, enabling users to preserve research sessions for future reference and documentation.

  **CLI Integration:**
  - New `--save-file` flag for `task-master research` command
  - Consistent with existing `--save` and `--save-to` flags for intuitive usage
  - Interactive "Save to file" option in follow-up questions menu

  **MCP Integration:**
  - New `saveToFile` boolean parameter for the `research` MCP tool
  - Enables programmatic research saving for AI agents and integrated tools

  **File Management:**
  - Automatically creates `.taskmaster/docs/research/` directory structure
  - Generates timestamped, slugified filenames (e.g., `2025-01-13_what-is-typescript.md`)
  - Comprehensive Markdown format with metadata headers including query, timestamp, and context sources
  - Clean conversation history formatting without duplicate information

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - No longer automatically creates individual task files as they are not used by the applicatoin. You can still generate them anytime using the `generate` command.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhanced get-task/show command to support comma-separated task IDs for efficient batch operations

  **New Features:**
  - **Multiple Task Retrieval**: Pass comma-separated IDs to get/show multiple tasks at once (e.g., `task-master show 1,3,5` or MCP `get_task` with `id: "1,3,5"`)
  - **Smart Display Logic**: Single ID shows detailed view, multiple IDs show compact summary table with interactive options
  - **Batch Action Menu**: Interactive menu for multiple tasks with copy-paste ready commands for common operations (mark as done/in-progress, expand all, view dependencies, etc.)
  - **MCP Array Response**: MCP tool returns structured array of task objects for efficient AI agent context gathering

  **Benefits:**
  - **Faster Context Gathering**: AI agents can collect multiple tasks/subtasks in one call instead of iterating
  - **Improved Workflow**: Interactive batch operations reduce repetitive command execution
  - **Better UX**: Responsive layout adapts to terminal width, maintains consistency with existing UI patterns
  - **API Efficiency**: RESTful array responses in MCP format enable more sophisticated integrations

  This enhancement maintains full backward compatibility while significantly improving efficiency for both human users and AI agents working with multiple tasks.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds support for filtering tasks by multiple statuses at once using comma-separated statuses.

  Example: `cancelled,deferred`

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds tag to CLI and MCP outputs/responses so you know which tag you are performing operations on.

### Patch Changes

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`5ec1f61`](https://github.com/eyaltoledano/claude-task-master/commit/5ec1f61c13f468648b7fdc8fa112e95aec25f76d) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix Cursor deeplink installation by providing copy-paste instructions for GitHub compatibility

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix critical bugs in task move functionality:
  - **Fixed moving tasks to become subtasks of empty parents**: When moving a task to become a subtask of a parent that had no existing subtasks (e.g., task 89 → task 98.1), the operation would fail with validation errors.
  - **Fixed moving subtasks between parents**: Subtasks can now be properly moved between different parent tasks, including to parents that previously had no subtasks.
  - **Improved comma-separated batch moves**: Multiple tasks can now be moved simultaneously using comma-separated IDs (e.g., "88,90" → "92,93") with proper error handling and atomic operations.

  These fixes enables proper task hierarchy reorganization for corner cases that were previously broken.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`d76bea4`](https://github.com/eyaltoledano/claude-task-master/commit/d76bea49b381c523183f39e33c2a4269371576ed) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Update o3 model price

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`0849c0c`](https://github.com/eyaltoledano/claude-task-master/commit/0849c0c2cedb16ac44ba5cc2d109625a9b4efd67) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes issue with expand CLI command "Complexity report not found"
  - Closes #735
  - Closes #728

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix issue with generate command which was creating tasks in the legacy tasks location.

      - No longer creates individual task files automatically. You can still use `generate` if you need to create our update your task files.

- [#779](https://github.com/eyaltoledano/claude-task-master/pull/779) [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Improves dependency management when moving tasks by updating subtask dependencies that reference sibling subtasks by their old parent-based ID

- Updated dependencies [[`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`5ec1f61`](https://github.com/eyaltoledano/claude-task-master/commit/5ec1f61c13f468648b7fdc8fa112e95aec25f76d), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`d76bea4`](https://github.com/eyaltoledano/claude-task-master/commit/d76bea49b381c523183f39e33c2a4269371576ed), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`0849c0c`](https://github.com/eyaltoledano/claude-task-master/commit/0849c0c2cedb16ac44ba5cc2d109625a9b4efd67), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f), [`c0b3f43`](https://github.com/eyaltoledano/claude-task-master/commit/c0b3f432a60891550b00acb113dc877bd432995f)]:
  - task-master-ai@0.17.0

## 0.16.2

### Patch Changes

- [#695](https://github.com/eyaltoledano/claude-task-master/pull/695) [`1ece6f1`](https://github.com/eyaltoledano/claude-task-master/commit/1ece6f19048df6ae2a0b25cbfb84d2c0f430642c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - improve findTasks algorithm for resolving tasks path

- [#695](https://github.com/eyaltoledano/claude-task-master/pull/695) [`ee0be04`](https://github.com/eyaltoledano/claude-task-master/commit/ee0be04302cc602246de5cd296291db69bc8b300) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix update tool on MCP giving `No valid tasks found`

- [#699](https://github.com/eyaltoledano/claude-task-master/pull/699) [`27edbd8`](https://github.com/eyaltoledano/claude-task-master/commit/27edbd8f3fe5e2ac200b80e7f27f4c0e74a074d6) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhanced add-task fuzzy search intelligence and improved user experience

  **Smarter Task Discovery:**
  - Remove hardcoded category system that always matched "Task management"
  - Eliminate arbitrary limits on fuzzy search results (5→25 high relevance, 3→10 medium relevance, 8→20 detailed tasks)
  - Improve semantic weighting in Fuse.js search (details=3, description=2, title=1.5) for better relevance
  - Generate context-driven task recommendations based on true semantic similarity

  **Enhanced Terminal Experience:**
  - Fix duplicate banner display issue that was "eating" terminal history (closes #553)
  - Remove console.clear() and redundant displayBanner() calls from UI functions
  - Preserve command history for better development workflow
  - Streamline banner display across all commands (list, next, show, set-status, clear-subtasks, dependency commands)

  **Visual Improvements:**
  - Replace emoji complexity indicators with clean filled circle characters (●) for professional appearance
  - Improve consistency and readability of task complexity display

  **AI Provider Compatibility:**
  - Change generateObject mode from 'tool' to 'auto' for better cross-provider compatibility
  - Add qwen3-235n-a22b:free model support (closes #687)
  - Add smart warnings for free OpenRouter models with limitations (rate limits, restricted context, no tool_use)

  **Technical Improvements:**
  - Enhanced context generation in add-task to rely on semantic similarity rather than rigid pattern matching
  - Improved dependency analysis and common pattern detection
  - Better handling of task relationships and relevance scoring
  - More intelligent task suggestion algorithms

  The add-task system now provides truly relevant task context based on semantic understanding rather than arbitrary categories and limits, while maintaining a cleaner and more professional terminal experience.

- [#655](https://github.com/eyaltoledano/claude-task-master/pull/655) [`edaa5fe`](https://github.com/eyaltoledano/claude-task-master/commit/edaa5fe0d56e0e4e7c4370670a7a388eebd922ac) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix double .taskmaster directory paths in file resolution utilities
  - Closes #636

- [#671](https://github.com/eyaltoledano/claude-task-master/pull/671) [`86ea6d1`](https://github.com/eyaltoledano/claude-task-master/commit/86ea6d1dbc03eeb39f524f565b50b7017b1d2c9c) Thanks [@joedanz](https://github.com/joedanz)! - Add one-click MCP server installation for Cursor

- [#699](https://github.com/eyaltoledano/claude-task-master/pull/699) [`2e55757`](https://github.com/eyaltoledano/claude-task-master/commit/2e55757b2698ba20b78f09ec0286951297510b8e) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add sync-readme command for a task export to GitHub README

  Introduces a new `sync-readme` command that exports your task list to your project's README.md file.

  **Features:**
  - **Flexible filtering**: Supports `--status` filtering (e.g., pending, done) and `--with-subtasks` flag
  - **Smart content management**: Automatically replaces existing exports or appends to new READMEs
  - **Metadata display**: Shows export timestamp, subtask inclusion status, and filter settings

  **Usage:**
  - `task-master sync-readme` - Export tasks without subtasks
  - `task-master sync-readme --with-subtasks` - Include subtasks in export
  - `task-master sync-readme --status=pending` - Only export pending tasks
  - `task-master sync-readme --status=done --with-subtasks` - Export completed tasks with subtasks

  Perfect for showcasing project progress on GitHub. Experimental. Open to feedback.

## 0.16.2

### Patch Changes

- [#695](https://github.com/eyaltoledano/claude-task-master/pull/695) [`1ece6f1`](https://github.com/eyaltoledano/claude-task-master/commit/1ece6f19048df6ae2a0b25cbfb84d2c0f430642c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - improve findTasks algorithm for resolving tasks path

- [#695](https://github.com/eyaltoledano/claude-task-master/pull/695) [`ee0be04`](https://github.com/eyaltoledano/claude-task-master/commit/ee0be04302cc602246de5cd296291db69bc8b300) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix update tool on MCP giving `No valid tasks found`

- [#699](https://github.com/eyaltoledano/claude-task-master/pull/699) [`27edbd8`](https://github.com/eyaltoledano/claude-task-master/commit/27edbd8f3fe5e2ac200b80e7f27f4c0e74a074d6) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhanced add-task fuzzy search intelligence and improved user experience

  **Smarter Task Discovery:**
  - Remove hardcoded category system that always matched "Task management"
  - Eliminate arbitrary limits on fuzzy search results (5→25 high relevance, 3→10 medium relevance, 8→20 detailed tasks)
  - Improve semantic weighting in Fuse.js search (details=3, description=2, title=1.5) for better relevance
  - Generate context-driven task recommendations based on true semantic similarity

  **Enhanced Terminal Experience:**
  - Fix duplicate banner display issue that was "eating" terminal history (closes #553)
  - Remove console.clear() and redundant displayBanner() calls from UI functions
  - Preserve command history for better development workflow
  - Streamline banner display across all commands (list, next, show, set-status, clear-subtasks, dependency commands)

  **Visual Improvements:**
  - Replace emoji complexity indicators with clean filled circle characters (●) for professional appearance
  - Improve consistency and readability of task complexity display

  **AI Provider Compatibility:**
  - Change generateObject mode from 'tool' to 'auto' for better cross-provider compatibility
  - Add qwen3-235n-a22b:free model support (closes #687)
  - Add smart warnings for free OpenRouter models with limitations (rate limits, restricted context, no tool_use)

  **Technical Improvements:**
  - Enhanced context generation in add-task to rely on semantic similarity rather than rigid pattern matching
  - Improved dependency analysis and common pattern detection
  - Better handling of task relationships and relevance scoring
  - More intelligent task suggestion algorithms

  The add-task system now provides truly relevant task context based on semantic understanding rather than arbitrary categories and limits, while maintaining a cleaner and more professional terminal experience.

- [#655](https://github.com/eyaltoledano/claude-task-master/pull/655) [`edaa5fe`](https://github.com/eyaltoledano/claude-task-master/commit/edaa5fe0d56e0e4e7c4370670a7a388eebd922ac) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix double .taskmaster directory paths in file resolution utilities
  - Closes #636

- [#671](https://github.com/eyaltoledano/claude-task-master/pull/671) [`86ea6d1`](https://github.com/eyaltoledano/claude-task-master/commit/86ea6d1dbc03eeb39f524f565b50b7017b1d2c9c) Thanks [@joedanz](https://github.com/joedanz)! - Add one-click MCP server installation for Cursor

- [#699](https://github.com/eyaltoledano/claude-task-master/pull/699) [`2e55757`](https://github.com/eyaltoledano/claude-task-master/commit/2e55757b2698ba20b78f09ec0286951297510b8e) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add sync-readme command for a task export to GitHub README

  Introduces a new `sync-readme` command that exports your task list to your project's README.md file.

  **Features:**
  - **Flexible filtering**: Supports `--status` filtering (e.g., pending, done) and `--with-subtasks` flag
  - **Smart content management**: Automatically replaces existing exports or appends to new READMEs
  - **Metadata display**: Shows export timestamp, subtask inclusion status, and filter settings

  **Usage:**
  - `task-master sync-readme` - Export tasks without subtasks
  - `task-master sync-readme --with-subtasks` - Include subtasks in export
  - `task-master sync-readme --status=pending` - Only export pending tasks
  - `task-master sync-readme --status=done --with-subtasks` - Export completed tasks with subtasks

  Perfect for showcasing project progress on GitHub. Experimental. Open to feedback.

## 0.16.2-rc.0

### Patch Changes

- [#655](https://github.com/eyaltoledano/claude-task-master/pull/655) [`edaa5fe`](https://github.com/eyaltoledano/claude-task-master/commit/edaa5fe0d56e0e4e7c4370670a7a388eebd922ac) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix double .taskmaster directory paths in file resolution utilities
  - Closes #636

- [#671](https://github.com/eyaltoledano/claude-task-master/pull/671) [`86ea6d1`](https://github.com/eyaltoledano/claude-task-master/commit/86ea6d1dbc03eeb39f524f565b50b7017b1d2c9c) Thanks [@joedanz](https://github.com/joedanz)! - Add one-click MCP server installation for Cursor

## 0.16.1

### Patch Changes

- [#641](https://github.com/eyaltoledano/claude-task-master/pull/641) [`ad61276`](https://github.com/eyaltoledano/claude-task-master/commit/ad612763ffbdd35aa1b593c9613edc1dc27a8856) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix bedrock issues

- [#648](https://github.com/eyaltoledano/claude-task-master/pull/648) [`9b4168b`](https://github.com/eyaltoledano/claude-task-master/commit/9b4168bb4e4dfc2f4fb0cf6bd5f81a8565879176) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP tool calls logging errors

- [#641](https://github.com/eyaltoledano/claude-task-master/pull/641) [`ad61276`](https://github.com/eyaltoledano/claude-task-master/commit/ad612763ffbdd35aa1b593c9613edc1dc27a8856) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Update rules for new directory structure

- [#648](https://github.com/eyaltoledano/claude-task-master/pull/648) [`9b4168b`](https://github.com/eyaltoledano/claude-task-master/commit/9b4168bb4e4dfc2f4fb0cf6bd5f81a8565879176) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix bug in expand_all mcp tool

- [#641](https://github.com/eyaltoledano/claude-task-master/pull/641) [`ad61276`](https://github.com/eyaltoledano/claude-task-master/commit/ad612763ffbdd35aa1b593c9613edc1dc27a8856) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP crashing after certain commands due to console logs

## 0.16.0

### Minor Changes

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add AWS bedrock support

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - # Add Google Vertex AI Provider Integration
  - Implemented `VertexAIProvider` class extending BaseAIProvider
  - Added authentication and configuration handling for Vertex AI
  - Updated configuration manager with Vertex-specific getters
  - Modified AI services unified system to integrate the provider
  - Added documentation for Vertex AI setup and configuration
  - Updated environment variable examples for Vertex AI support
  - Implemented specialized error handling for Vertex-specific issues

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for Azure

- [#612](https://github.com/eyaltoledano/claude-task-master/pull/612) [`669b744`](https://github.com/eyaltoledano/claude-task-master/commit/669b744ced454116a7b29de6c58b4b8da977186a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Increased minimum required node version to > 18 (was > 14)

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Renamed baseUrl to baseURL

- [#604](https://github.com/eyaltoledano/claude-task-master/pull/604) [`80735f9`](https://github.com/eyaltoledano/claude-task-master/commit/80735f9e60c7dda7207e169697f8ac07b6733634) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add TASK_MASTER_PROJECT_ROOT env variable supported in mcp.json and .env for project root resolution
  - Some users were having issues where the MCP wasn't able to detect the location of their project root, you can now set the `TASK_MASTER_PROJECT_ROOT` environment variable to the root of your project.

- [#619](https://github.com/eyaltoledano/claude-task-master/pull/619) [`3f64202`](https://github.com/eyaltoledano/claude-task-master/commit/3f64202c9feef83f2bf383c79e4367d337c37e20) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Consolidate Task Master files into unified .taskmaster directory structure

  This release introduces a new consolidated directory structure that organizes all Task Master files under a single `.taskmaster/` directory for better project organization and cleaner workspace management.

  **New Directory Structure:**
  - `.taskmaster/tasks/` - Task files (previously `tasks/`)
  - `.taskmaster/docs/` - Documentation including PRD files (previously `scripts/`)
  - `.taskmaster/reports/` - Complexity analysis reports (previously `scripts/`)
  - `.taskmaster/templates/` - Template files like example PRD
  - `.taskmaster/config.json` - Configuration (previously `.taskmasterconfig`)

  **Migration & Backward Compatibility:**
  - Existing projects continue to work with legacy file locations
  - New projects use the consolidated structure automatically
  - Run `task-master migrate` to move existing projects to the new structure
  - All CLI commands and MCP tools automatically detect and use appropriate file locations

  **Benefits:**
  - Cleaner project root with Task Master files organized in one location
  - Reduced file scatter across multiple directories
  - Improved project navigation and maintenance
  - Consistent file organization across all Task Master projects

  This change maintains full backward compatibility while providing a migration path to the improved structure.

### Patch Changes

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix max_tokens error when trying to use claude-sonnet-4 and claude-opus-4

- [#625](https://github.com/eyaltoledano/claude-task-master/pull/625) [`2d520de`](https://github.com/eyaltoledano/claude-task-master/commit/2d520de2694da3efe537b475ca52baf3c869edda) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix add-task MCP command causing an error

## 0.16.0-rc.0

### Minor Changes

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add AWS bedrock support

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - # Add Google Vertex AI Provider Integration
  - Implemented `VertexAIProvider` class extending BaseAIProvider
  - Added authentication and configuration handling for Vertex AI
  - Updated configuration manager with Vertex-specific getters
  - Modified AI services unified system to integrate the provider
  - Added documentation for Vertex AI setup and configuration
  - Updated environment variable examples for Vertex AI support
  - Implemented specialized error handling for Vertex-specific issues

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add support for Azure

- [#612](https://github.com/eyaltoledano/claude-task-master/pull/612) [`669b744`](https://github.com/eyaltoledano/claude-task-master/commit/669b744ced454116a7b29de6c58b4b8da977186a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Increased minimum required node version to > 18 (was > 14)

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Renamed baseUrl to baseURL

- [#604](https://github.com/eyaltoledano/claude-task-master/pull/604) [`80735f9`](https://github.com/eyaltoledano/claude-task-master/commit/80735f9e60c7dda7207e169697f8ac07b6733634) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add TASK_MASTER_PROJECT_ROOT env variable supported in mcp.json and .env for project root resolution
  - Some users were having issues where the MCP wasn't able to detect the location of their project root, you can now set the `TASK_MASTER_PROJECT_ROOT` environment variable to the root of your project.

- [#619](https://github.com/eyaltoledano/claude-task-master/pull/619) [`3f64202`](https://github.com/eyaltoledano/claude-task-master/commit/3f64202c9feef83f2bf383c79e4367d337c37e20) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Consolidate Task Master files into unified .taskmaster directory structure

  This release introduces a new consolidated directory structure that organizes all Task Master files under a single `.taskmaster/` directory for better project organization and cleaner workspace management.

  **New Directory Structure:**
  - `.taskmaster/tasks/` - Task files (previously `tasks/`)
  - `.taskmaster/docs/` - Documentation including PRD files (previously `scripts/`)
  - `.taskmaster/reports/` - Complexity analysis reports (previously `scripts/`)
  - `.taskmaster/templates/` - Template files like example PRD
  - `.taskmaster/config.json` - Configuration (previously `.taskmasterconfig`)

  **Migration & Backward Compatibility:**
  - Existing projects continue to work with legacy file locations
  - New projects use the consolidated structure automatically
  - Run `task-master migrate` to move existing projects to the new structure
  - All CLI commands and MCP tools automatically detect and use appropriate file locations

  **Benefits:**
  - Cleaner project root with Task Master files organized in one location
  - Reduced file scatter across multiple directories
  - Improved project navigation and maintenance
  - Consistent file organization across all Task Master projects

  This change maintains full backward compatibility while providing a migration path to the improved structure.

### Patch Changes

- [#607](https://github.com/eyaltoledano/claude-task-master/pull/607) [`6a8a68e`](https://github.com/eyaltoledano/claude-task-master/commit/6a8a68e1a3f34dcdf40b355b4602a08d291f8e38) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix max_tokens error when trying to use claude-sonnet-4 and claude-opus-4

- [#597](https://github.com/eyaltoledano/claude-task-master/pull/597) [`2d520de`](https://github.com/eyaltoledano/claude-task-master/commit/2d520de2694da3efe537b475ca52baf3c869edda) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix add-task MCP command causing an error

## 0.15.0

### Minor Changes

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`09add37`](https://github.com/eyaltoledano/claude-task-master/commit/09add37423d70b809d5c28f3cde9fccd5a7e64e7) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Added comprehensive Ollama model validation and interactive setup support
  - **Interactive Setup Enhancement**: Added "Custom Ollama model" option to `task-master models --setup`, matching the existing OpenRouter functionality
  - **Live Model Validation**: When setting Ollama models, Taskmaster now validates against the local Ollama instance by querying `/api/tags` endpoint
  - **Configurable Endpoints**: Uses the `ollamaBaseUrl` from `.taskmasterconfig` (with role-specific `baseUrl` overrides supported)
  - **Robust Error Handling**:
    - Detects when Ollama server is not running and provides clear error messages
    - Validates model existence and lists available alternatives when model not found
    - Graceful fallback behavior for connection issues
  - **Full Platform Support**: Both MCP server tools and CLI commands support the new validation
  - **Improved User Experience**: Clear feedback during model validation with informative success/error messages

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`4c83526`](https://github.com/eyaltoledano/claude-task-master/commit/4c835264ac6c1f74896cddabc3b3c69a5c435417) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds and updates supported AI models with costs:
  - Added new OpenRouter models: GPT-4.1 series, O3, Codex Mini, Llama 4 Maverick, Llama 4 Scout, Qwen3-235b
  - Added Mistral models: Devstral Small, Mistral Nemo
  - Updated Ollama models with latest variants: Devstral, Qwen3, Mistral-small3.1, Llama3.3
  - Updated Gemini model to latest 2.5 Flash preview version

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`70f4054`](https://github.com/eyaltoledano/claude-task-master/commit/70f4054f268f9f8257870e64c24070263d4e2966) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add `--research` flag to parse-prd command, enabling enhanced task generation from PRD files. When used, Taskmaster leverages the research model to:
  - Research current technologies and best practices relevant to the project
  - Identify technical challenges and security concerns not explicitly mentioned in the PRD
  - Include specific library recommendations with version numbers
  - Provide more detailed implementation guidance based on industry standards
  - Create more accurate dependency relationships between tasks

  This results in higher quality, more actionable tasks with minimal additional effort.

  _NOTE_ That this is an experimental feature. Research models don't typically do great at structured output. You may find some failures when using research mode, so please share your feedback so we can improve this.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`5e9bc28`](https://github.com/eyaltoledano/claude-task-master/commit/5e9bc28abea36ec7cd25489af7fcc6cbea51038b) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - This change significantly enhances the `add-task` command's intelligence. When you add a new task, Taskmaster now automatically: - Analyzes your existing tasks to find those most relevant to your new task's description. - Provides the AI with detailed context from these relevant tasks.

  This results in newly created tasks being more accurately placed within your project's dependency structure, saving you time and any need to update tasks just for dependencies, all without significantly increasing AI costs. You'll get smarter, more connected tasks right from the start.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`34c769b`](https://github.com/eyaltoledano/claude-task-master/commit/34c769bcd0faf65ddec3b95de2ba152a8be3ec5c) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhance analyze-complexity to support analyzing specific task IDs. - You can now analyze individual tasks or selected task groups by using the new `--id` option with comma-separated IDs, or `--from` and `--to` options to specify a range of tasks. - The feature intelligently merges analysis results with existing reports, allowing incremental analysis while preserving previous results.

- [#558](https://github.com/eyaltoledano/claude-task-master/pull/558) [`86d8f00`](https://github.com/eyaltoledano/claude-task-master/commit/86d8f00af809887ee0ba0ba7157cc555e0d07c38) Thanks [@ShreyPaharia](https://github.com/ShreyPaharia)! - Add next task to set task status response
  Status: DONE

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`04af16d`](https://github.com/eyaltoledano/claude-task-master/commit/04af16de27295452e134b17b3c7d0f44bbb84c29) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add move command to enable moving tasks and subtasks within the task hierarchy. This new command supports moving standalone tasks to become subtasks, subtasks to become standalone tasks, and moving subtasks between different parents. The implementation handles circular dependencies, validation, and proper updating of parent-child relationships.

  **Usage:**
  - CLI command: `task-master move --from=<id> --to=<id>`
  - MCP tool: `move_task` with parameters:
    - `from`: ID of task/subtask to move (e.g., "5" or "5.2")
    - `to`: ID of destination (e.g., "7" or "7.3")
    - `file` (optional): Custom path to tasks.json

  **Example scenarios:**
  - Move task to become subtask: `--from="5" --to="7"`
  - Move subtask to standalone task: `--from="5.2" --to="7"`
  - Move subtask to different parent: `--from="5.2" --to="7.3"`
  - Reorder subtask within same parent: `--from="5.2" --to="5.4"`
  - Move multiple tasks at once: `--from="10,11,12" --to="16,17,18"`
  - Move task to new ID: `--from="5" --to="25"` (creates a new task with ID 25)

  **Multiple Task Support:**
  The command supports moving multiple tasks simultaneously by providing comma-separated lists for both `--from` and `--to` parameters. The number of source and destination IDs must match. This is particularly useful for resolving merge conflicts in task files when multiple team members have created tasks on different branches.

  **Validation Features:**
  - Allows moving tasks to new, non-existent IDs (automatically creates placeholders)
  - Prevents moving to existing task IDs that already contain content (to avoid overwriting)
  - Validates source tasks exist before attempting to move them
  - Ensures proper parent-child relationships are maintained

### Patch Changes

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`231e569`](https://github.com/eyaltoledano/claude-task-master/commit/231e569e84804a2e5ba1f9da1a985d0851b7e949) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adjusts default main model model to Claude Sonnet 4. Adjusts default fallback to Claude Sonney 3.7"

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`b371808`](https://github.com/eyaltoledano/claude-task-master/commit/b371808524f2c2986f4940d78fcef32c125d01f2) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds llms-install.md to the root to enable AI agents to programmatically install the Taskmaster MCP server. This is specifically being introduced for the Cline MCP marketplace and will be adjusted over time for other MCP clients as needed.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`a59dd03`](https://github.com/eyaltoledano/claude-task-master/commit/a59dd037cfebb46d38bc44dd216c7c23933be641) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds AGENTS.md to power Claude Code integration more natively based on Anthropic's best practice and Claude-specific MCP client behaviours. Also adds in advanced workflows that tie Taskmaster commands together into one Claude workflow."

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`e0e1155`](https://github.com/eyaltoledano/claude-task-master/commit/e0e115526089bf41d5d60929956edf5601ff3e23) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes issue with force/append flag combinations for parse-prd.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`34df2c8`](https://github.com/eyaltoledano/claude-task-master/commit/34df2c8bbddc0e157c981d32502bbe6b9468202e) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - You can now add tasks to a newly initialized project without having to parse a prd. This will automatically create the missing tasks.json file and create the first task. Lets you vibe if you want to vibe."

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`d2e6431`](https://github.com/eyaltoledano/claude-task-master/commit/d2e64318e2f4bfc3457792e310cc4ff9210bba30) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes an issue where the research fallback would attempt to make API calls without checking for a valid API key first. This ensures proper error handling when the main task generation and first fallback both fail. Closes #421 #519.

## 0.15.0-rc.0

### Minor Changes

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`09add37`](https://github.com/eyaltoledano/claude-task-master/commit/09add37423d70b809d5c28f3cde9fccd5a7e64e7) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Added comprehensive Ollama model validation and interactive setup support
  - **Interactive Setup Enhancement**: Added "Custom Ollama model" option to `task-master models --setup`, matching the existing OpenRouter functionality
  - **Live Model Validation**: When setting Ollama models, Taskmaster now validates against the local Ollama instance by querying `/api/tags` endpoint
  - **Configurable Endpoints**: Uses the `ollamaBaseUrl` from `.taskmasterconfig` (with role-specific `baseUrl` overrides supported)
  - **Robust Error Handling**:
    - Detects when Ollama server is not running and provides clear error messages
    - Validates model existence and lists available alternatives when model not found
    - Graceful fallback behavior for connection issues
  - **Full Platform Support**: Both MCP server tools and CLI commands support the new validation
  - **Improved User Experience**: Clear feedback during model validation with informative success/error messages

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`4c83526`](https://github.com/eyaltoledano/claude-task-master/commit/4c835264ac6c1f74896cddabc3b3c69a5c435417) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds and updates supported AI models with costs:
  - Added new OpenRouter models: GPT-4.1 series, O3, Codex Mini, Llama 4 Maverick, Llama 4 Scout, Qwen3-235b
  - Added Mistral models: Devstral Small, Mistral Nemo
  - Updated Ollama models with latest variants: Devstral, Qwen3, Mistral-small3.1, Llama3.3
  - Updated Gemini model to latest 2.5 Flash preview version

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`70f4054`](https://github.com/eyaltoledano/claude-task-master/commit/70f4054f268f9f8257870e64c24070263d4e2966) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add `--research` flag to parse-prd command, enabling enhanced task generation from PRD files. When used, Taskmaster leverages the research model to:
  - Research current technologies and best practices relevant to the project
  - Identify technical challenges and security concerns not explicitly mentioned in the PRD
  - Include specific library recommendations with version numbers
  - Provide more detailed implementation guidance based on industry standards
  - Create more accurate dependency relationships between tasks

  This results in higher quality, more actionable tasks with minimal additional effort.

  _NOTE_ That this is an experimental feature. Research models don't typically do great at structured output. You may find some failures when using research mode, so please share your feedback so we can improve this.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`5e9bc28`](https://github.com/eyaltoledano/claude-task-master/commit/5e9bc28abea36ec7cd25489af7fcc6cbea51038b) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - This change significantly enhances the `add-task` command's intelligence. When you add a new task, Taskmaster now automatically: - Analyzes your existing tasks to find those most relevant to your new task's description. - Provides the AI with detailed context from these relevant tasks.

  This results in newly created tasks being more accurately placed within your project's dependency structure, saving you time and any need to update tasks just for dependencies, all without significantly increasing AI costs. You'll get smarter, more connected tasks right from the start.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`34c769b`](https://github.com/eyaltoledano/claude-task-master/commit/34c769bcd0faf65ddec3b95de2ba152a8be3ec5c) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Enhance analyze-complexity to support analyzing specific task IDs. - You can now analyze individual tasks or selected task groups by using the new `--id` option with comma-separated IDs, or `--from` and `--to` options to specify a range of tasks. - The feature intelligently merges analysis results with existing reports, allowing incremental analysis while preserving previous results.

- [#558](https://github.com/eyaltoledano/claude-task-master/pull/558) [`86d8f00`](https://github.com/eyaltoledano/claude-task-master/commit/86d8f00af809887ee0ba0ba7157cc555e0d07c38) Thanks [@ShreyPaharia](https://github.com/ShreyPaharia)! - Add next task to set task status response
  Status: DONE

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`04af16d`](https://github.com/eyaltoledano/claude-task-master/commit/04af16de27295452e134b17b3c7d0f44bbb84c29) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add move command to enable moving tasks and subtasks within the task hierarchy. This new command supports moving standalone tasks to become subtasks, subtasks to become standalone tasks, and moving subtasks between different parents. The implementation handles circular dependencies, validation, and proper updating of parent-child relationships.

  **Usage:**
  - CLI command: `task-master move --from=<id> --to=<id>`
  - MCP tool: `move_task` with parameters:
    - `from`: ID of task/subtask to move (e.g., "5" or "5.2")
    - `to`: ID of destination (e.g., "7" or "7.3")
    - `file` (optional): Custom path to tasks.json

  **Example scenarios:**
  - Move task to become subtask: `--from="5" --to="7"`
  - Move subtask to standalone task: `--from="5.2" --to="7"`
  - Move subtask to different parent: `--from="5.2" --to="7.3"`
  - Reorder subtask within same parent: `--from="5.2" --to="5.4"`
  - Move multiple tasks at once: `--from="10,11,12" --to="16,17,18"`
  - Move task to new ID: `--from="5" --to="25"` (creates a new task with ID 25)

  **Multiple Task Support:**
  The command supports moving multiple tasks simultaneously by providing comma-separated lists for both `--from` and `--to` parameters. The number of source and destination IDs must match. This is particularly useful for resolving merge conflicts in task files when multiple team members have created tasks on different branches.

  **Validation Features:**
  - Allows moving tasks to new, non-existent IDs (automatically creates placeholders)
  - Prevents moving to existing task IDs that already contain content (to avoid overwriting)
  - Validates source tasks exist before attempting to move them
  - Ensures proper parent-child relationships are maintained

### Patch Changes

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`231e569`](https://github.com/eyaltoledano/claude-task-master/commit/231e569e84804a2e5ba1f9da1a985d0851b7e949) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adjusts default main model model to Claude Sonnet 4. Adjusts default fallback to Claude Sonney 3.7"

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`b371808`](https://github.com/eyaltoledano/claude-task-master/commit/b371808524f2c2986f4940d78fcef32c125d01f2) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds llms-install.md to the root to enable AI agents to programmatically install the Taskmaster MCP server. This is specifically being introduced for the Cline MCP marketplace and will be adjusted over time for other MCP clients as needed.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`a59dd03`](https://github.com/eyaltoledano/claude-task-master/commit/a59dd037cfebb46d38bc44dd216c7c23933be641) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds AGENTS.md to power Claude Code integration more natively based on Anthropic's best practice and Claude-specific MCP client behaviours. Also adds in advanced workflows that tie Taskmaster commands together into one Claude workflow."

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`e0e1155`](https://github.com/eyaltoledano/claude-task-master/commit/e0e115526089bf41d5d60929956edf5601ff3e23) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes issue with force/append flag combinations for parse-prd.

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`34df2c8`](https://github.com/eyaltoledano/claude-task-master/commit/34df2c8bbddc0e157c981d32502bbe6b9468202e) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - You can now add tasks to a newly initialized project without having to parse a prd. This will automatically create the missing tasks.json file and create the first task. Lets you vibe if you want to vibe."

- [#567](https://github.com/eyaltoledano/claude-task-master/pull/567) [`d2e6431`](https://github.com/eyaltoledano/claude-task-master/commit/d2e64318e2f4bfc3457792e310cc4ff9210bba30) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes an issue where the research fallback would attempt to make API calls without checking for a valid API key first. This ensures proper error handling when the main task generation and first fallback both fail. Closes #421 #519.

## 0.14.0

### Minor Changes

- [#521](https://github.com/eyaltoledano/claude-task-master/pull/521) [`ed17cb0`](https://github.com/eyaltoledano/claude-task-master/commit/ed17cb0e0a04dedde6c616f68f24f3660f68dd04) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - .taskmasterconfig now supports a baseUrl field per model role (main, research, fallback), allowing endpoint overrides for any provider.

- [#536](https://github.com/eyaltoledano/claude-task-master/pull/536) [`f4a83ec`](https://github.com/eyaltoledano/claude-task-master/commit/f4a83ec047b057196833e3a9b861d4bceaec805d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Ollama as a supported AI provider.
  - You can now add it by running `task-master models --setup` and selecting it.
  - Ollama is a local model provider, so no API key is required.
  - Ollama models are available at `http://localhost:11434/api` by default.
  - You can change the default URL by setting the `OLLAMA_BASE_URL` environment variable or by adding a `baseUrl` property to the `ollama` model role in `.taskmasterconfig`.
    - If you want to use a custom API key, you can set it in the `OLLAMA_API_KEY` environment variable.

- [#528](https://github.com/eyaltoledano/claude-task-master/pull/528) [`58b417a`](https://github.com/eyaltoledano/claude-task-master/commit/58b417a8ce697e655f749ca4d759b1c20014c523) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Display task complexity scores in task lists, next task, and task details views.

### Patch Changes

- [#402](https://github.com/eyaltoledano/claude-task-master/pull/402) [`01963af`](https://github.com/eyaltoledano/claude-task-master/commit/01963af2cb6f77f43b2ad8a6e4a838ec205412bc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Resolve all issues related to MCP

- [#478](https://github.com/eyaltoledano/claude-task-master/pull/478) [`4117f71`](https://github.com/eyaltoledano/claude-task-master/commit/4117f71c18ee4d321a9c91308d00d5d69bfac61e) Thanks [@joedanz](https://github.com/joedanz)! - Fix CLI --force flag for parse-prd command

  Previously, the --force flag was not respected when running `parse-prd`, causing the command to prompt for confirmation or fail even when --force was provided. This patch ensures that the flag is correctly passed and handled, allowing users to overwrite existing tasks.json files as intended.
  - Fixes #477

- [#511](https://github.com/eyaltoledano/claude-task-master/pull/511) [`17294ff`](https://github.com/eyaltoledano/claude-task-master/commit/17294ff25918d64278674e558698a1a9ad785098) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Task Master no longer tells you to update when you're already up to date

- [#442](https://github.com/eyaltoledano/claude-task-master/pull/442) [`2b3ae8b`](https://github.com/eyaltoledano/claude-task-master/commit/2b3ae8bf89dc471c4ce92f3a12ded57f61faa449) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds costs information to AI commands using input/output tokens and model costs.

- [#402](https://github.com/eyaltoledano/claude-task-master/pull/402) [`01963af`](https://github.com/eyaltoledano/claude-task-master/commit/01963af2cb6f77f43b2ad8a6e4a838ec205412bc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix ERR_MODULE_NOT_FOUND when trying to run MCP Server

- [#402](https://github.com/eyaltoledano/claude-task-master/pull/402) [`01963af`](https://github.com/eyaltoledano/claude-task-master/commit/01963af2cb6f77f43b2ad8a6e4a838ec205412bc) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add src directory to exports

- [#523](https://github.com/eyaltoledano/claude-task-master/pull/523) [`da317f2`](https://github.com/eyaltoledano/claude-task-master/commit/da317f2607ca34db1be78c19954996f634c40923) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix the error handling of task status settings

- [#527](https://github.com/eyaltoledano/claude-task-master/pull/527) [`a8dabf4`](https://github.com/eyaltoledano/claude-task-master/commit/a8dabf44856713f488960224ee838761716bba26) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove caching layer from MCP direct functions for task listing, next task, and complexity report
  - Fixes issues users where having where they were getting stale data

- [#417](https://github.com/eyaltoledano/claude-task-master/pull/417) [`a1f8d52`](https://github.com/eyaltoledano/claude-task-master/commit/a1f8d52474fdbdf48e17a63e3f567a6d63010d9f) Thanks [@ksylvan](https://github.com/ksylvan)! - Fix for issue #409 LOG_LEVEL Pydantic validation error

- [#442](https://github.com/eyaltoledano/claude-task-master/pull/442) [`0288311`](https://github.com/eyaltoledano/claude-task-master/commit/0288311965ae2a343ebee4a0c710dde94d2ae7e7) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Small fixes - `next` command no longer incorrectly suggests that subtasks be broken down into subtasks in the CLI - fixes the `append` flag so it properly works in the CLI

- [#501](https://github.com/eyaltoledano/claude-task-master/pull/501) [`0a61184`](https://github.com/eyaltoledano/claude-task-master/commit/0a611843b56a856ef0a479dc34078326e05ac3a8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix initial .env.example to work out of the box
  - Closes #419

- [#435](https://github.com/eyaltoledano/claude-task-master/pull/435) [`a96215a`](https://github.com/eyaltoledano/claude-task-master/commit/a96215a359b25061fd3b3f3c7b10e8ac0390c062) Thanks [@lebsral](https://github.com/lebsral)! - Fix default fallback model and maxTokens in Taskmaster initialization

- [#517](https://github.com/eyaltoledano/claude-task-master/pull/517) [`e96734a`](https://github.com/eyaltoledano/claude-task-master/commit/e96734a6cc6fec7731de72eb46b182a6e3743d02) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix bug when updating tasks on the MCP server (#412)

- [#496](https://github.com/eyaltoledano/claude-task-master/pull/496) [`efce374`](https://github.com/eyaltoledano/claude-task-master/commit/efce37469bc58eceef46763ba32df1ed45242211) Thanks [@joedanz](https://github.com/joedanz)! - Fix duplicate output on CLI help screen
  - Prevent the Task Master CLI from printing the help screen more than once when using `-h` or `--help`.
  - Removed redundant manual event handlers and guards for help output; now only the Commander `.helpInformation` override is used for custom help.
  - Simplified logic so that help is only shown once for both "no arguments" and help flag flows.
  - Ensures a clean, branded help experience with no repeated content.
  - Fixes #339

## 0.14.0-rc.1

### Minor Changes

- [#536](https://github.com/eyaltoledano/claude-task-master/pull/536) [`f4a83ec`](https://github.com/eyaltoledano/claude-task-master/commit/f4a83ec047b057196833e3a9b861d4bceaec805d) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Ollama as a supported AI provider.
  - You can now add it by running `task-master models --setup` and selecting it.
  - Ollama is a local model provider, so no API key is required.
  - Ollama models are available at `http://localhost:11434/api` by default.
  - You can change the default URL by setting the `OLLAMA_BASE_URL` environment variable or by adding a `baseUrl` property to the `ollama` model role in `.taskmasterconfig`.
    - If you want to use a custom API key, you can set it in the `OLLAMA_API_KEY` environment variable.

### Patch Changes

- [#442](https://github.com/eyaltoledano/claude-task-master/pull/442) [`2b3ae8b`](https://github.com/eyaltoledano/claude-task-master/commit/2b3ae8bf89dc471c4ce92f3a12ded57f61faa449) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds costs information to AI commands using input/output tokens and model costs.

- [#442](https://github.com/eyaltoledano/claude-task-master/pull/442) [`0288311`](https://github.com/eyaltoledano/claude-task-master/commit/0288311965ae2a343ebee4a0c710dde94d2ae7e7) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Small fixes - `next` command no longer incorrectly suggests that subtasks be broken down into subtasks in the CLI - fixes the `append` flag so it properly works in the CLI

## 0.14.0-rc.0

### Minor Changes

- [#521](https://github.com/eyaltoledano/claude-task-master/pull/521) [`ed17cb0`](https://github.com/eyaltoledano/claude-task-master/commit/ed17cb0e0a04dedde6c616f68f24f3660f68dd04) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - .taskmasterconfig now supports a baseUrl field per model role (main, research, fallback), allowing endpoint overrides for any provider.

- [#528](https://github.com/eyaltoledano/claude-task-master/pull/528) [`58b417a`](https://github.com/eyaltoledano/claude-task-master/commit/58b417a8ce697e655f749ca4d759b1c20014c523) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Display task complexity scores in task lists, next task, and task details views.

### Patch Changes

- [#478](https://github.com/eyaltoledano/claude-task-master/pull/478) [`4117f71`](https://github.com/eyaltoledano/claude-task-master/commit/4117f71c18ee4d321a9c91308d00d5d69bfac61e) Thanks [@joedanz](https://github.com/joedanz)! - Fix CLI --force flag for parse-prd command

  Previously, the --force flag was not respected when running `parse-prd`, causing the command to prompt for confirmation or fail even when --force was provided. This patch ensures that the flag is correctly passed and handled, allowing users to overwrite existing tasks.json files as intended.
  - Fixes #477

- [#511](https://github.com/eyaltoledano/claude-task-master/pull/511) [`17294ff`](https://github.com/eyaltoledano/claude-task-master/commit/17294ff25918d64278674e558698a1a9ad785098) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Task Master no longer tells you to update when you're already up to date

- [#523](https://github.com/eyaltoledano/claude-task-master/pull/523) [`da317f2`](https://github.com/eyaltoledano/claude-task-master/commit/da317f2607ca34db1be78c19954996f634c40923) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix the error handling of task status settings

- [#527](https://github.com/eyaltoledano/claude-task-master/pull/527) [`a8dabf4`](https://github.com/eyaltoledano/claude-task-master/commit/a8dabf44856713f488960224ee838761716bba26) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove caching layer from MCP direct functions for task listing, next task, and complexity report
  - Fixes issues users where having where they were getting stale data

- [#417](https://github.com/eyaltoledano/claude-task-master/pull/417) [`a1f8d52`](https://github.com/eyaltoledano/claude-task-master/commit/a1f8d52474fdbdf48e17a63e3f567a6d63010d9f) Thanks [@ksylvan](https://github.com/ksylvan)! - Fix for issue #409 LOG_LEVEL Pydantic validation error

- [#501](https://github.com/eyaltoledano/claude-task-master/pull/501) [`0a61184`](https://github.com/eyaltoledano/claude-task-master/commit/0a611843b56a856ef0a479dc34078326e05ac3a8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix initial .env.example to work out of the box
  - Closes #419

- [#435](https://github.com/eyaltoledano/claude-task-master/pull/435) [`a96215a`](https://github.com/eyaltoledano/claude-task-master/commit/a96215a359b25061fd3b3f3c7b10e8ac0390c062) Thanks [@lebsral](https://github.com/lebsral)! - Fix default fallback model and maxTokens in Taskmaster initialization

- [#517](https://github.com/eyaltoledano/claude-task-master/pull/517) [`e96734a`](https://github.com/eyaltoledano/claude-task-master/commit/e96734a6cc6fec7731de72eb46b182a6e3743d02) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix bug when updating tasks on the MCP server (#412)

- [#496](https://github.com/eyaltoledano/claude-task-master/pull/496) [`efce374`](https://github.com/eyaltoledano/claude-task-master/commit/efce37469bc58eceef46763ba32df1ed45242211) Thanks [@joedanz](https://github.com/joedanz)! - Fix duplicate output on CLI help screen
  - Prevent the Task Master CLI from printing the help screen more than once when using `-h` or `--help`.
  - Removed redundant manual event handlers and guards for help output; now only the Commander `.helpInformation` override is used for custom help.
  - Simplified logic so that help is only shown once for both "no arguments" and help flag flows.
  - Ensures a clean, branded help experience with no repeated content.
  - Fixes #339

## 0.13.1

### Patch Changes

- [#399](https://github.com/eyaltoledano/claude-task-master/pull/399) [`734a4fd`](https://github.com/eyaltoledano/claude-task-master/commit/734a4fdcfc89c2e089255618cf940561ad13a3c8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix ERR_MODULE_NOT_FOUND when trying to run MCP Server

## 0.13.0

### Minor Changes

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`ef782ff`](https://github.com/eyaltoledano/claude-task-master/commit/ef782ff5bd4ceb3ed0dc9ea82087aae5f79ac933) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - feat(expand): Enhance `expand` and `expand-all` commands
  - Integrate `task-complexity-report.json` to automatically determine the number of subtasks and use tailored prompts for expansion based on prior analysis. You no longer need to try copy-pasting the recommended prompt. If it exists, it will use it for you. You can just run `task-master update --id=[id of task] --research` and it will use that prompt automatically. No extra prompt needed.
  - Change default behavior to _append_ new subtasks to existing ones. Use the `--force` flag to clear existing subtasks before expanding. This is helpful if you need to add more subtasks to a task but you want to do it by the batch from a given prompt. Use force if you want to start fresh with a task's subtasks.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`87d97bb`](https://github.com/eyaltoledano/claude-task-master/commit/87d97bba00d84e905756d46ef96b2d5b984e0f38) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds support for the OpenRouter AI provider. Users can now configure models available through OpenRouter (requiring an `OPENROUTER_API_KEY`) via the `task-master models` command, granting access to a wide range of additional LLMs. - IMPORTANT FYI ABOUT OPENROUTER: Taskmaster relies on AI SDK, which itself relies on tool use. It looks like **free** models sometimes do not include tool use. For example, Gemini 2.5 pro (free) failed via OpenRouter (no tool use) but worked fine on the paid version of the model. Custom model support for Open Router is considered experimental and likely will not be further improved for some time.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`1ab836f`](https://github.com/eyaltoledano/claude-task-master/commit/1ab836f191cb8969153593a9a0bd47fc9aa4a831) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds model management and new configuration file .taskmasterconfig which houses the models used for main, research and fallback. Adds models command and setter flags. Adds a --setup flag with an interactive setup. We should be calling this during init. Shows a table of active and available models when models is called without flags. Includes SWE scores and token costs, which are manually entered into the supported_models.json, the new place where models are defined for support. Config-manager.js is the core module responsible for managing the new config."

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`c8722b0`](https://github.com/eyaltoledano/claude-task-master/commit/c8722b0a7a443a73b95d1bcd4a0b68e0fce2a1cd) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds custom model ID support for Ollama and OpenRouter providers.
  - Adds the `--ollama` and `--openrouter` flags to `task-master models --set-<role>` command to set models for those providers outside of the support models list.
  - Updated `task-master models --setup` interactive mode with options to explicitly enter custom Ollama or OpenRouter model IDs.
  - Implemented live validation against OpenRouter API (`/api/v1/models`) when setting a custom OpenRouter model ID (via flag or setup).
  - Refined logic to prioritize explicit provider flags/choices over internal model list lookups in case of ID conflicts.
  - Added warnings when setting custom/unvalidated models.
  - We obviously don't recommend going with a custom, unproven model. If you do and find performance is good, please let us know so we can add it to the list of supported models.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`2517bc1`](https://github.com/eyaltoledano/claude-task-master/commit/2517bc112c9a497110f3286ca4bfb4130c9addcb) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Integrate OpenAI as a new AI provider. - Enhance `models` command/tool to display API key status. - Implement model-specific `maxTokens` override based on `supported-models.json` to save you if you use an incorrect max token value.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`9a48278`](https://github.com/eyaltoledano/claude-task-master/commit/9a482789f7894f57f655fb8d30ba68542bd0df63) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Tweaks Perplexity AI calls for research mode to max out input tokens and get day-fresh information - Forces temp at 0.1 for highly deterministic output, no variations - Adds a system prompt to further improve the output - Correctly uses the maximum input tokens (8,719, used 8,700) for perplexity - Specificies to use a high degree of research across the web - Specifies to use information that is as fresh as today; this support stuff like capturing brand new announcements like new GPT models and being able to query for those in research. 🔥

### Patch Changes

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`842eaf7`](https://github.com/eyaltoledano/claude-task-master/commit/842eaf722498ddf7307800b4cdcef4ac4fd7e5b0) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - - Add support for Google Gemini models via Vercel AI SDK integration.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`ed79d4f`](https://github.com/eyaltoledano/claude-task-master/commit/ed79d4f4735dfab4124fa189214c0bd5e23a6860) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add xAI provider and Grok models support

- [#378](https://github.com/eyaltoledano/claude-task-master/pull/378) [`ad89253`](https://github.com/eyaltoledano/claude-task-master/commit/ad89253e313a395637aa48b9f92cc39b1ef94ad8) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Better support for file paths on Windows, Linux & WSL.
  - Standardizes handling of different path formats (URI encoded, Windows, Linux, WSL).
  - Ensures tools receive a clean, absolute path suitable for the server OS.
  - Simplifies tool implementation by centralizing normalization logic.

- [#285](https://github.com/eyaltoledano/claude-task-master/pull/285) [`2acba94`](https://github.com/eyaltoledano/claude-task-master/commit/2acba945c0afee9460d8af18814c87e80f747e9f) Thanks [@neno-is-ooo](https://github.com/neno-is-ooo)! - Add integration for Roo Code

- [#378](https://github.com/eyaltoledano/claude-task-master/pull/378) [`d63964a`](https://github.com/eyaltoledano/claude-task-master/commit/d63964a10eed9be17856757661ff817ad6bacfdc) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Improved update-subtask - Now it has context about the parent task details - It also has context about the subtask before it and the subtask after it (if they exist) - Not passing all subtasks to stay token efficient

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`5f504fa`](https://github.com/eyaltoledano/claude-task-master/commit/5f504fafb8bdaa0043c2d20dee8bbb8ec2040d85) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Improve and adjust `init` command for robustness and updated dependencies.
  - **Update Initialization Dependencies:** Ensure newly initialized projects (`task-master init`) include all required AI SDK dependencies (`@ai-sdk/*`, `ai`, provider wrappers) in their `package.json` for out-of-the-box AI feature compatibility. Remove unnecessary dependencies (e.g., `uuid`) from the init template.
  - **Silence `npm install` during `init`:** Prevent `npm install` output from interfering with non-interactive/MCP initialization by suppressing its stdio in silent mode.
  - **Improve Conditional Model Setup:** Reliably skip interactive `models --setup` during non-interactive `init` runs (e.g., `init -y` or MCP) by checking `isSilentMode()` instead of passing flags.
  - **Refactor `init.js`:** Remove internal `isInteractive` flag logic.
  - **Update `init` Instructions:** Tweak the "Getting Started" text displayed after `init`.
  - **Fix MCP Server Launch:** Update `.cursor/mcp.json` template to use `node ./mcp-server/server.js` instead of `npx task-master-mcp`.
  - **Update Default Model:** Change the default main model in the `.taskmasterconfig` template.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`96aeeff`](https://github.com/eyaltoledano/claude-task-master/commit/96aeeffc195372722c6a07370540e235bfe0e4d8) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes an issue with add-task which did not use the manually defined properties and still needlessly hit the AI endpoint.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`5aea93d`](https://github.com/eyaltoledano/claude-task-master/commit/5aea93d4c0490c242d7d7042a210611977848e0a) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fixes an issue that prevented remove-subtask with comma separated tasks/subtasks from being deleted (only the first ID was being deleted). Closes #140

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`66ac9ab`](https://github.com/eyaltoledano/claude-task-master/commit/66ac9ab9f66d006da518d6e8a3244e708af2764d) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Improves next command to be subtask-aware - The logic for determining the "next task" (findNextTask function, used by task-master next and the next_task MCP tool) has been significantly improved. Previously, it only considered top-level tasks, making its recommendation less useful when a parent task containing subtasks was already marked 'in-progress'. - The updated logic now prioritizes finding the next available subtask within any 'in-progress' parent task, considering subtask dependencies and priority. - If no suitable subtask is found within active parent tasks, it falls back to recommending the next eligible top-level task based on the original criteria (status, dependencies, priority).

  This change makes the next command much more relevant and helpful during the implementation phase of complex tasks.

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`ca7b045`](https://github.com/eyaltoledano/claude-task-master/commit/ca7b0457f1dc65fd9484e92527d9fd6d69db758d) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add `--status` flag to `show` command to filter displayed subtasks.

- [#328](https://github.com/eyaltoledano/claude-task-master/pull/328) [`5a2371b`](https://github.com/eyaltoledano/claude-task-master/commit/5a2371b7cc0c76f5e95d43921c1e8cc8081bf14e) Thanks [@knoxgraeme](https://github.com/knoxgraeme)! - Fix --task to --num-tasks in ui + related tests - issue #324

- [#240](https://github.com/eyaltoledano/claude-task-master/pull/240) [`6cb213e`](https://github.com/eyaltoledano/claude-task-master/commit/6cb213ebbd51116ae0688e35b575d09443d17c3b) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Adds a 'models' CLI and MCP command to get the current model configuration, available models, and gives the ability to set main/research/fallback models." - In the CLI, `task-master models` shows the current models config. Using the `--setup` flag launches an interactive set up that allows you to easily select the models you want to use for each of the three roles. Use `q` during the interactive setup to cancel the setup. - In the MCP, responses are simplified in RESTful format (instead of the full CLI output). The agent can use the `models` tool with different arguments, including `listAvailableModels` to get available models. Run without arguments, it will return the current configuration. Arguments are available to set the model for each of the three roles. This allows you to manage Taskmaster AI providers and models directly from either the CLI or MCP or both. - Updated the CLI help menu when you run `task-master` to include missing commands and .taskmasterconfig information. - Adds `--research` flag to `add-task` so you can hit up Perplexity right from the add-task flow, rather than having to add a task and then update it.

## 0.12.1

### Patch Changes

- [#307](https://github.com/eyaltoledano/claude-task-master/pull/307) [`2829194`](https://github.com/eyaltoledano/claude-task-master/commit/2829194d3c1dd5373d3bf40275cf4f63b12d49a7) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix add_dependency tool crashing the MCP Server

## 0.12.0

### Minor Changes

- [#253](https://github.com/eyaltoledano/claude-task-master/pull/253) [`b2ccd60`](https://github.com/eyaltoledano/claude-task-master/commit/b2ccd605264e47a61451b4c012030ee29011bb40) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add `npx task-master-ai` that runs mcp instead of using `task-master-mcp``

- [#267](https://github.com/eyaltoledano/claude-task-master/pull/267) [`c17d912`](https://github.com/eyaltoledano/claude-task-master/commit/c17d912237e6caaa2445e934fc48cd4841abf056) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve PRD parsing prompt with structured analysis and clearer task generation guidelines. We are testing a new prompt - please provide feedback on your experience.

### Patch Changes

- [#243](https://github.com/eyaltoledano/claude-task-master/pull/243) [`454a1d9`](https://github.com/eyaltoledano/claude-task-master/commit/454a1d9d37439c702656eedc0702c2f7a4451517) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - - Fixes shebang issue not allowing task-master to run on certain windows operating systems
  - Resolves #241 #211 #184 #193

- [#268](https://github.com/eyaltoledano/claude-task-master/pull/268) [`3e872f8`](https://github.com/eyaltoledano/claude-task-master/commit/3e872f8afbb46cd3978f3852b858c233450b9f33) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix remove-task command to handle multiple comma-separated task IDs

- [#239](https://github.com/eyaltoledano/claude-task-master/pull/239) [`6599cb0`](https://github.com/eyaltoledano/claude-task-master/commit/6599cb0bf9eccecab528207836e9d45b8536e5c2) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Updates the parameter descriptions for update, update-task and update-subtask to ensure the MCP server correctly reaches for the right update command based on what is being updated -- all tasks, one task, or a subtask.

- [#272](https://github.com/eyaltoledano/claude-task-master/pull/272) [`3aee9bc`](https://github.com/eyaltoledano/claude-task-master/commit/3aee9bc840eb8f31230bd1b761ed156b261cabc4) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhance the `parsePRD` to include `--append` flag. This flag allows users to append the parsed PRD to an existing file, making it easier to manage multiple PRD files without overwriting existing content.

- [#264](https://github.com/eyaltoledano/claude-task-master/pull/264) [`ff8e75c`](https://github.com/eyaltoledano/claude-task-master/commit/ff8e75cded91fb677903040002626f7a82fd5f88) Thanks [@joedanz](https://github.com/joedanz)! - Add quotes around numeric env vars in mcp.json (Windsurf, etc.)

- [#248](https://github.com/eyaltoledano/claude-task-master/pull/248) [`d99fa00`](https://github.com/eyaltoledano/claude-task-master/commit/d99fa00980fc61695195949b33dcda7781006f90) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - - Fix `task-master init` polluting codebase with new packages inside `package.json` and modifying project `README`
  - Now only initializes with cursor rules, windsurf rules, mcp.json, scripts/example_prd.txt, .gitignore modifications, and `README-task-master.md`

- [#266](https://github.com/eyaltoledano/claude-task-master/pull/266) [`41b979c`](https://github.com/eyaltoledano/claude-task-master/commit/41b979c23963483e54331015a86e7c5079f657e4) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fixed a bug that prevented the task-master from running in a Linux container

- [#265](https://github.com/eyaltoledano/claude-task-master/pull/265) [`0eb16d5`](https://github.com/eyaltoledano/claude-task-master/commit/0eb16d5ecbb8402d1318ca9509e9d4087b27fb25) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove the need for project name, description, and version. Since we no longer create a package.json for you

## 0.11.0

### Minor Changes

- [#71](https://github.com/eyaltoledano/claude-task-master/pull/71) [`7141062`](https://github.com/eyaltoledano/claude-task-master/commit/71410629ba187776d92a31ea0729b2ff341b5e38) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - - **Easier Ways to Use Taskmaster (CLI & MCP):**
  - You can now use Taskmaster either by installing it as a standard command-line tool (`task-master`) or as an MCP server directly within integrated development tools like Cursor (using its built-in features). **This makes Taskmaster accessible regardless of your preferred workflow.**
  - Setting up a new project is simpler in integrated tools, thanks to the new `initialize_project` capability.
  - **Complete MCP Implementation:**
    - NOTE: Many MCP clients charge on a per tool basis. In that regard, the most cost-efficient way to use Taskmaster is through the CLI directly. Otherwise, the MCP offers the smoothest and most recommended user experience.
    - All MCP tools now follow a standardized output format that mimicks RESTful API responses. They are lean JSON responses that are context-efficient. This is a net improvement over the last version which sent the whole CLI output directly, which needlessly wasted tokens.
    - Added a `remove-task` command to permanently delete tasks you no longer need.
    - Many new MCP tools are available for managing tasks (updating details, adding/removing subtasks, generating task files, setting status, finding the next task, breaking down complex tasks, handling dependencies, analyzing complexity, etc.), usable both from the command line and integrated tools. **(See the `taskmaster.mdc` reference guide and improved readme for a full list).**
  - **Better Task Tracking:**
    - Added a "cancelled" status option for tasks, providing more ways to categorize work.
  - **Smoother Experience in Integrated Tools:**
    - Long-running operations (like breaking down tasks or analysis) now run in the background **via an Async Operation Manager** with progress updates, so you know what's happening without waiting and can check status later.
  - **Improved Documentation:**
    - Added a comprehensive reference guide (`taskmaster.mdc`) detailing all commands and tools with examples, usage tips, and troubleshooting info. This is mostly for use by the AI but can be useful for human users as well.
    - Updated the main README with clearer instructions and added a new tutorial/examples guide.
    - Added documentation listing supported integrated tools (like Cursor).
  - **Increased Stability & Reliability:**
    - Using Taskmaster within integrated tools (like Cursor) is now **more stable and the recommended approach.**
    - Added automated testing (CI) to catch issues earlier, leading to a more reliable tool.
    - Fixed release process issues to ensure users get the correct package versions when installing or updating via npm.
  - **Better Command-Line Experience:**
    - Fixed bugs in the `expand-all` command that could cause **NaN errors or JSON formatting issues (especially when using `--research`).**
    - Fixed issues with parameter validation in the `analyze-complexity` command (specifically related to the `threshold` parameter).
    - Made the `add-task` command more consistent by adding standard flags like `--title`, `--description` for manual task creation so you don't have to use `--prompt` and can quickly drop new ideas and stay in your flow.
    - Improved error messages for incorrect commands or flags, making them easier to understand.
    - Added confirmation warnings before permanently deleting tasks (`remove-task`) to prevent mistakes. There's a known bug for deleting multiple tasks with comma-separated values. It'll be fixed next release.
    - Renamed some background tool names used by integrated tools (e.g., `list-tasks` is now `get_tasks`) to be more intuitive if seen in logs or AI interactions.
    - Smoother project start: **Improved the guidance provided to AI assistants immediately after setup** (related to `init` and `parse-prd` steps). This ensures the AI doesn't go on a tangent deciding its own workflow, and follows the exact process outlined in the Taskmaster workflow.
  - **Clearer Error Messages:**
    - When generating subtasks fails, error messages are now clearer, **including specific task IDs and potential suggestions.**
    - AI fallback from Claude to Perplexity now also works the other way around. If Perplexity is down, will switch to Claude.
  - **Simplified Setup & Configuration:**
    - Made it clearer how to configure API keys depending on whether you're using the command-line tool (`.env` file) or an integrated tool (`.cursor/mcp.json` file).
    - Taskmaster is now better at automatically finding your project files, especially in integrated tools, reducing the need for manual path settings.
    - Fixed an issue that could prevent Taskmaster from working correctly immediately after initialization in integrated tools (related to how the MCP server was invoked). This should solve the issue most users were experiencing with the last release (0.10.x)
    - Updated setup templates with clearer examples for API keys.
    - \*\*For advanced users setting up the MCP server manually, the command is now `npx -y task-master-ai task-master-mcp`.
  - **Enhanced Performance & AI:**
    - Updated underlying AI model settings:
      - **Increased Context Window:** Can now handle larger projects/tasks due to an increased Claude context window (64k -> 128k tokens).
      - **Reduced AI randomness:** More consistent and predictable AI outputs (temperature 0.4 -> 0.2).
      - **Updated default AI models:** Uses newer models like `claude-3-7-sonnet-20250219` and Perplexity `sonar-pro` by default.
      - **More granular breakdown:** Increased the default number of subtasks generated by `expand` to 5 (from 4).
      - **Consistent defaults:** Set the default priority for new tasks consistently to "medium".
    - Improved performance when viewing task details in integrated tools by sending less redundant data.
  - **Documentation Clarity:**
    - Clarified in documentation that Markdown files (`.md`) can be used for Product Requirements Documents (`parse_prd`).
    - Improved the description for the `numTasks` option in `parse_prd` for better guidance.
  - **Improved Visuals (CLI):**
    - Enhanced the look and feel of progress bars and status updates in the command line.
    - Added a helpful color-coded progress bar to the task details view (`show` command) to visualize subtask completion.
    - Made progress bars show a breakdown of task statuses (e.g., how many are pending vs. done).
    - Made status counts clearer with text labels next to icons.
    - Prevented progress bars from messing up the display on smaller terminal windows.
    - Adjusted how progress is calculated for 'deferred' and 'cancelled' tasks in the progress bar, while still showing their distinct status visually.
  - **Fixes for Integrated Tools:**
    - Fixed how progress updates are sent to integrated tools, ensuring they display correctly.
    - Fixed internal issues that could cause errors or invalid JSON responses when using Taskmaster with integrated tools.

## 0.10.1

### Patch Changes

- [#80](https://github.com/eyaltoledano/claude-task-master/pull/80) [`aa185b2`](https://github.com/eyaltoledano/claude-task-master/commit/aa185b28b248b4ca93f9195b502e2f5187868eaa) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Remove non-existent package `@model-context-protocol/sdk`

- [#45](https://github.com/eyaltoledano/claude-task-master/pull/45) [`757fd47`](https://github.com/eyaltoledano/claude-task-master/commit/757fd478d2e2eff8506ae746c3470c6088f4d944) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add license to repo

## 0.10.0

### Minor Changes

- [#44](https://github.com/eyaltoledano/claude-task-master/pull/44) [`eafdb47`](https://github.com/eyaltoledano/claude-task-master/commit/eafdb47418b444c03c092f653b438cc762d4bca8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - add github actions to automate github and npm releases

- [#20](https://github.com/eyaltoledano/claude-task-master/pull/20) [`4eed269`](https://github.com/eyaltoledano/claude-task-master/commit/4eed2693789a444f704051d5fbb3ef8d460e4e69) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Implement MCP server for all commands using tools.

### Patch Changes

- [#44](https://github.com/eyaltoledano/claude-task-master/pull/44) [`44db895`](https://github.com/eyaltoledano/claude-task-master/commit/44db895303a9209416236e3d519c8a609ad85f61) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added changeset config #39

- [#50](https://github.com/eyaltoledano/claude-task-master/pull/50) [`257160a`](https://github.com/eyaltoledano/claude-task-master/commit/257160a9670b5d1942e7c623bd2c1a3fde7c06a0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix addTask tool `projectRoot not defined`

- [#57](https://github.com/eyaltoledano/claude-task-master/pull/57) [`9fd42ee`](https://github.com/eyaltoledano/claude-task-master/commit/9fd42eeafdc25a96cdfb70aa3af01f525d26b4bc) Thanks [@github-actions](https://github.com/apps/github-actions)! - fix mcp server not connecting to cursor

- [#48](https://github.com/eyaltoledano/claude-task-master/pull/48) [`5ec3651`](https://github.com/eyaltoledano/claude-task-master/commit/5ec3651e6459add7354910a86b3c4db4d12bc5d1) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix workflows


## Links discovered
- [#1523](https://github.com/eyaltoledano/claude-task-master/pull/1523)
- [`fc1a79f`](https://github.com/eyaltoledano/claude-task-master/commit/fc1a79f2565b0d8c24f009aec2c473a335262ae2)
- [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)
- [#1549](https://github.com/eyaltoledano/claude-task-master/pull/1549)
- [`98087ac`](https://github.com/eyaltoledano/claude-task-master/commit/98087acae91fad7345bdb4c253d4dfd0d584f81e)
- [#1545](https://github.com/eyaltoledano/claude-task-master/pull/1545)
- [`a0007a3`](https://github.com/eyaltoledano/claude-task-master/commit/a0007a3575305c367c8561584aa0dbd181f5e1cc)
- [#1542](https://github.com/eyaltoledano/claude-task-master/pull/1542)
- [`b817d6f`](https://github.com/eyaltoledano/claude-task-master/commit/b817d6f9f278c84785ec468f9b305e70c47266f6)
- [@mdimitrovg](https://github.com/mdimitrovg)
- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538)
- [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97)
- [#1535](https://github.com/eyaltoledano/claude-task-master/pull/1535)
- [`4d1ed20`](https://github.com/eyaltoledano/claude-task-master/commit/4d1ed20345083ab2ec1c7fc268c69379281a68ea)
- [#1526](https://github.com/eyaltoledano/claude-task-master/pull/1526)
- [`38c2c08`](https://github.com/eyaltoledano/claude-task-master/commit/38c2c08af1f8de729d5d2dab586ec4622445f2db)
- [@eyaltoledano](https://github.com/eyaltoledano)
- [#1521](https://github.com/eyaltoledano/claude-task-master/pull/1521)
- [`353e3bf`](https://github.com/eyaltoledano/claude-task-master/commit/353e3bffd6df528dc19f7c5790564d0dead14c6d)
- [#1525](https://github.com/eyaltoledano/claude-task-master/pull/1525)
- [`1c2228d`](https://github.com/eyaltoledano/claude-task-master/commit/1c2228dbb618e522798c4484b74c1508f13d61d6)
- [#1310](https://github.com/eyaltoledano/claude-task-master/pull/1310)
- [`4b6570e`](https://github.com/eyaltoledano/claude-task-master/commit/4b6570e300eedb265af215c0ca6baeb772d42e4a)
- [#1461](https://github.com/eyaltoledano/claude-task-master/pull/1461)
- [`9ee63e0`](https://github.com/eyaltoledano/claude-task-master/commit/9ee63e01db4308cf248be3855949c7cd86272b9b)
- [#1508](https://github.com/eyaltoledano/claude-task-master/pull/1508)
- [`69ac463`](https://github.com/eyaltoledano/claude-task-master/commit/69ac46351eac8e1c3f58b203b2a618bf6114c000)
- [@ben-vargas](https://github.com/ben-vargas)
- [#1492](https://github.com/eyaltoledano/claude-task-master/pull/1492)
- [`071dfc6`](https://github.com/eyaltoledano/claude-task-master/commit/071dfc6be9abe30909157ea72e026036721cea1d)
- [#1491](https://github.com/eyaltoledano/claude-task-master/pull/1491)
- [`0e908be`](https://github.com/eyaltoledano/claude-task-master/commit/0e908be43af1075bae1fd7f6b7a6fad8a131dd56)
- [#1477](https://github.com/eyaltoledano/claude-task-master/pull/1477)
- [`b0199f1`](https://github.com/eyaltoledano/claude-task-master/commit/b0199f1cfa643051f90406d69e90ea916d434e6a)
- [#1478](https://github.com/eyaltoledano/claude-task-master/pull/1478)
- [`6ff330f`](https://github.com/eyaltoledano/claude-task-master/commit/6ff330f8c2bc6e534e0a883c770e8394d7ad5fa8)
- [#1452](https://github.com/eyaltoledano/claude-task-master/pull/1452)
- [`4046b3c`](https://github.com/eyaltoledano/claude-task-master/commit/4046b3ca4479adf0239679eb5ba18b7b4aec0749)
- [#1463](https://github.com/eyaltoledano/claude-task-master/pull/1463)
- [`55595f6`](https://github.com/eyaltoledano/claude-task-master/commit/55595f680c8b52b5421d3e0c7640bf2050efe44f)
- [#1446](https://github.com/eyaltoledano/claude-task-master/pull/1446)
- [`2316e94`](https://github.com/eyaltoledano/claude-task-master/commit/2316e94b288915bb906e1a61a87f59e291594fef)
- [#1454](https://github.com/eyaltoledano/claude-task-master/pull/1454)
- [`38ff7eb`](https://github.com/eyaltoledano/claude-task-master/commit/38ff7ebbc029919ea4cd5257573efbf1ea2f0eeb)
- [#1437](https://github.com/eyaltoledano/claude-task-master/pull/1437)
- [`783398e`](https://github.com/eyaltoledano/claude-task-master/commit/783398ecdf71432bd2b97f400756acbcfd60fbef)
- [#1440](https://github.com/eyaltoledano/claude-task-master/pull/1440)
- [`9f6f3af`](https://github.com/eyaltoledano/claude-task-master/commit/9f6f3affe322512a8708624850c144b4b890e782)
- [#1436](https://github.com/eyaltoledano/claude-task-master/pull/1436)
- [`c1df63d`](https://github.com/eyaltoledano/claude-task-master/commit/c1df63d7229f05b57abba4af11e74a8d2bc6dcd9)
- [#1425](https://github.com/eyaltoledano/claude-task-master/pull/1425)
- [`99d9179`](https://github.com/eyaltoledano/claude-task-master/commit/99d9179522dc66797ec7e3f428d72b46a9557f09)
- [#1427](https://github.com/eyaltoledano/claude-task-master/pull/1427)
- [`122c23a`](https://github.com/eyaltoledano/claude-task-master/commit/122c23abb36634c1e68c476d681f41b4b4991671)
- [#1421](https://github.com/eyaltoledano/claude-task-master/pull/1421)
- [`e75946b`](https://github.com/eyaltoledano/claude-task-master/commit/e75946b1a998269e6a751d2b5baf5c3b7e9b9f46)
- [#1413](https://github.com/eyaltoledano/claude-task-master/issues/1413)
- [#1411](https://github.com/eyaltoledano/claude-task-master/issues/1411)
- [#1396](https://github.com/eyaltoledano/claude-task-master/pull/1396)
- [`9883e83`](https://github.com/eyaltoledano/claude-task-master/commit/9883e83b78306e55003e960ea072a11048d89ec9)
- [@bjcoombs](https://github.com/bjcoombs)
- [#1382](https://github.com/eyaltoledano/claude-task-master/pull/1382)
- [`ac4328a`](https://github.com/eyaltoledano/claude-task-master/commit/ac4328ae86380c50bb84fff0e98e2370f4ea666f)
- [@JJVvV](https://github.com/JJVvV)
- [#1408](https://github.com/eyaltoledano/claude-task-master/pull/1408)
- [`10ec025`](https://github.com/eyaltoledano/claude-task-master/commit/10ec0255812dad00aaa72f1b31f41ca978e4451c)
- [#1398](https://github.com/eyaltoledano/claude-task-master/pull/1398)
- [`e59c16c`](https://github.com/eyaltoledano/claude-task-master/commit/e59c16c707d3ade479a422d8c617004eac1a857f)
- [#1400](https://github.com/eyaltoledano/claude-task-master/pull/1400)
- [`c62cf84`](https://github.com/eyaltoledano/claude-task-master/commit/c62cf845dad1960ec183df217293d4edbeea71b9)
- [#1393](https://github.com/eyaltoledano/claude-task-master/pull/1393)
- [`da8ed6a`](https://github.com/eyaltoledano/claude-task-master/commit/da8ed6aa116b9ade3ef4502dd8b8c44727057b5f)
- [#1407](https://github.com/eyaltoledano/claude-task-master/pull/1407)
- [`0003b6f`](https://github.com/eyaltoledano/claude-task-master/commit/0003b6fca6b8c9320ee959fb0081eed4ba086b98)
- [#1351](https://github.com/eyaltoledano/claude-task-master/pull/1351)
- [`37aee78`](https://github.com/eyaltoledano/claude-task-master/commit/37aee7809ce753104692b2024eb8b2bb0d376c14)
- [#1406](https://github.com/eyaltoledano/claude-task-master/pull/1406)
- [`9079d04`](https://github.com/eyaltoledano/claude-task-master/commit/9079d0417907f468360e8db8dd461abb619609e7)
- [#1377](https://github.com/eyaltoledano/claude-task-master/pull/1377)
- [`3c22875`](https://github.com/eyaltoledano/claude-task-master/commit/3c22875efeb5d21754d447a9559817bc5327a234)
- [#1370](https://github.com/eyaltoledano/claude-task-master/pull/1370)
- [`9c3b273`](https://github.com/eyaltoledano/claude-task-master/commit/9c3b2737dd224e788b197f41df644ea0a6f4cfe2)
- [#1371](https://github.com/eyaltoledano/claude-task-master/pull/1371)
- [`abf46b8`](https://github.com/eyaltoledano/claude-task-master/commit/abf46b8087c2f32466a71d057415bab315e35567)
- [#1360](https://github.com/eyaltoledano/claude-task-master/pull/1360)
- [`819d5e1`](https://github.com/eyaltoledano/claude-task-master/commit/819d5e1bc5fb81be4b25f1823988a8e20abe8440)
- [LM Studio](https://lmstudio.ai/)
- [#1362](https://github.com/eyaltoledano/claude-task-master/pull/1362)
- [`3e70edf`](https://github.com/eyaltoledano/claude-task-master/commit/3e70edfa3a1f47bd8a6d2d2a30c20c72f5758b9b)
- [#1358](https://github.com/eyaltoledano/claude-task-master/pull/1358)
- [`0c639bd`](https://github.com/eyaltoledano/claude-task-master/commit/0c639bd1db9d2d9b4c2c22ac60b0d875ba75f80e)
- [#1339](https://github.com/eyaltoledano/claude-task-master/pull/1339)
- [`3b09b5d`](https://github.com/eyaltoledano/claude-task-master/commit/3b09b5da2a929f260d275f056d35bb6ded54ca6d)
- [#1326](https://github.com/eyaltoledano/claude-task-master/pull/1326)
- [`9d5812b`](https://github.com/eyaltoledano/claude-task-master/commit/9d5812ba6725cfadebb8db8f4aa732cf3cdb3a36)
- [@SharifMrCreed](https://github.com/SharifMrCreed)
- [#1340](https://github.com/eyaltoledano/claude-task-master/pull/1340)
- [`d63a40c`](https://github.com/eyaltoledano/claude-task-master/commit/d63a40c6ddc1ed2fe418206a19acd3e9dc27fd99)
- [#1305](https://github.com/eyaltoledano/claude-task-master/pull/1305)
- [`a98d96e`](https://github.com/eyaltoledano/claude-task-master/commit/a98d96ef0414833b948672f86da4acc11f700ebb)

--- CONTRIBUTING.md ---
# Contributing to Task Master

Thank you for your interest in contributing to Task Master! We're excited to work with you and appreciate your help in making this project better. 🚀

## 🤝 Our Collaborative Approach

We're a **PR-friendly team** that values collaboration:

- ✅ **We review PRs quickly** - Usually within hours, not days
- ✅ **We're super reactive** - Expect fast feedback and engagement
- ✅ **We sometimes take over PRs** - If your contribution is valuable but needs cleanup, we might jump in to help finish it
- ✅ **We're open to all contributions** - From bug fixes to major features

**We don't mind AI-generated code**, but we do expect you to:

- ✅ **Review and understand** what the AI generated
- ✅ **Test the code thoroughly** before submitting
- ✅ **Ensure it's well-written** and follows our patterns
- ❌ **Don't submit "AI slop"** - untested, unreviewed AI output

> **Why this matters**: We spend significant time reviewing PRs. Help us help you by submitting quality contributions that save everyone time!

## 🚀 Quick Start for Contributors

### 1. Fork and Clone

```bash
git clone https://github.com/YOUR_USERNAME/claude-task-master.git
cd claude-task-master
npm install
```

### 2. Create a Feature Branch

**Important**: Always target the `next` branch, not `main`:

```bash
git checkout next
git pull origin next
git checkout -b feature/your-feature-name
```

### 3. Make Your Changes

Follow our development guidelines below.

### 4. Test Everything Yourself

**Before submitting your PR**, ensure:

```bash
# Run all tests
npm test

# Check formatting
npm run format-check

# Fix formatting if needed
npm run format
```

### 5. Create a Changeset

**Required for most changes**:

```bash
npm run changeset
```

See the [Changeset Guidelines](#changeset-guidelines) below for details.

### 6. Submit Your PR

- Target the `next` branch
- Write a clear description
- Reference any related issues

## 📋 Development Guidelines

### Branch Strategy

- **`main`**: Production-ready code
- **`next`**: Development branch - **target this for PRs**
- **Feature branches**: `feature/description` or `fix/description`

### Code Quality Standards

1. **Write tests** for new functionality
2. **Follow existing patterns** in the codebase
3. **Add JSDoc comments** for functions
4. **Keep functions focused** and single-purpose

### Testing Requirements

Your PR **must pass all CI checks**:

- ✅ **Unit tests**: `npm test`
- ✅ **Format check**: `npm run format-check`

**Test your changes locally first** - this saves review time and shows you care about quality.

## 📦 Changeset Guidelines

We use [Changesets](https://github.com/changesets/changesets) to manage versioning and generate changelogs.

### When to Create a Changeset

**Always create a changeset for**:

- ✅ New features
- ✅ Bug fixes
- ✅ Breaking changes
- ✅ Performance improvements
- ✅ User-facing documentation updates
- ✅ Dependency updates that affect functionality

**Skip changesets for**:

- ❌ Internal documentation only
- ❌ Test-only changes
- ❌ Code formatting/linting
- ❌ Development tooling that doesn't affect users

### How to Create a Changeset

1. **After making your changes**:

   ```bash
   npm run changeset
   ```

2. **Choose the bump type**:

   - **Major**: Breaking changes
   - **Minor**: New features
   - **Patch**: Bug fixes, docs, performance improvements

3. **Write a clear summary**:

   ```
   Add support for custom AI models in MCP configuration
   ```

4. **Commit the changeset file** with your changes:
   ```bash
   git add .changeset/*.md
   git commit -m "feat: add custom AI model support"
   ```

### Changeset vs Git Commit Messages

- **Changeset summary**: User-facing, goes in CHANGELOG.md
- **Git commit**: Developer-facing, explains the technical change

Example:

```bash
# Changeset summary (user-facing)
"Add support for custom Ollama models"

# Git commit message (developer-facing)
"feat(models): implement custom Ollama model validation

- Add model validation for custom Ollama endpoints
- Update configuration schema to support custom models
- Add tests for new validation logic"
```

## 🔧 Development Setup

### Prerequisites

- Node.js 20+
- npm or yarn

### Environment Setup

1. **Copy environment template**:

   ```bash
   cp .env.example .env
   ```

2. **Add your API keys** (for testing AI features):
   ```bash
   ANTHROPIC_API_KEY=your_key_here
   OPENAI_API_KEY=your_key_here
   # Add others as needed
   ```

### Running Tests

```bash
# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run with coverage
npm run test:coverage

# Run E2E tests
npm run test:e2e
```

### Code Formatting

We use Prettier for consistent formatting:

```bash
# Check formatting
npm run format-check

# Fix formatting
npm run format
```

## 📝 PR Guidelines

### Before Submitting

- [ ] **Target the `next` branch**
- [ ] **Test everything locally**
- [ ] **Run the full test suite**
- [ ] **Check code formatting**
- [ ] **Create a changeset** (if needed)
- [ ] **Re-read your changes** - ensure they're clean and well-thought-out

### PR Description Template

```markdown
## Description

Brief description of what this PR does.

## Type of Change

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing

- [ ] I have tested this locally
- [ ] All existing tests pass
- [ ] I have added tests for new functionality

## Changeset

- [ ] I have created a changeset (or this change doesn't need one)

## Additional Notes

Any additional context or notes for reviewers.
```

### What We Look For

✅ **Good PRs**:

- Clear, focused changes
- Comprehensive testing
- Good commit messages
- Proper changeset (when needed)
- Self-reviewed code

❌ **Avoid**:

- Massive PRs that change everything
- Untested code
- Formatting issues
- Missing changesets for user-facing changes
- AI-generated code that wasn't reviewed

## 🏗️ Project Structure

```
claude-task-master/
├── bin/                    # CLI executables
├── mcp-server/            # MCP server implementation
├── scripts/               # Core task management logic
├── src/                   # Shared utilities and providers and well refactored code (we are slowly moving everything here)
├── tests/                 # Test files
├── docs/                  # Documentation
└── .cursor/               # Cursor IDE rules and configuration
└── assets/							   # Assets like rules and configuration for all IDEs
```

### Key Areas for Contribution

- **CLI Commands**: `scripts/modules/commands.js`
- **MCP Tools**: `mcp-server/src/tools/`
- **Core Logic**: `scripts/modules/task-manager/`
- **AI Providers**: `src/ai-providers/`
- **Tests**: `tests/`

## 🐛 Reporting Issues

### Bug Reports

Include:

- Task Master version
- Node.js version
- Operating system
- Steps to reproduce
- Expected vs actual behavior
- Error messages/logs

### Feature Requests

Include:

- Clear description of the feature
- Use case/motivation
- Proposed implementation (if you have ideas)
- Willingness to contribute

## 💬 Getting Help

- **Discord**: [Join our community](https://discord.gg/taskmasterai)
- **Issues**: [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- **Discussions**: [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

## 📄 License

By contributing, you agree that your contributions will be licensed under the same license as the project (MIT with Commons Clause).

---

**Thank you for contributing to Task Master!** 🎉

Your contributions help make AI-driven development more accessible and efficient for everyone.


## Links discovered
- [Changesets](https://github.com/changesets/changesets)
- [Join our community](https://discord.gg/taskmasterai)
- [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)

--- apps/cli/CHANGELOG.md ---
# @tm/cli

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- [#1396](https://github.com/eyaltoledano/claude-task-master/pull/1396) [`9883e83`](https://github.com/eyaltoledano/claude-task-master/commit/9883e83b78306e55003e960ea072a11048d89ec9) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix box title alignment by adding emoji variant selector to warning sign

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- [#1305](https://github.com/eyaltoledano/claude-task-master/pull/1305) [`a98d96e`](https://github.com/eyaltoledano/claude-task-master/commit/a98d96ef0414833b948672f86da4acc11f700ebb) Thanks [@bjcoombs](https://github.com/bjcoombs)! - Fix warning message box width to match dashboard box width for consistent UI alignment

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## 0.27.0

### Patch Changes

- Updated dependencies []:
  - @tm/core@0.26.1

## 0.27.0-rc.0

### Minor Changes

- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213) [`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - testing this stuff out to see how the release candidate works with monorepo

## 1.1.0-rc.0

### Minor Changes

- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213) [`cd90b4d`](https://github.com/eyaltoledano/claude-task-master/commit/cd90b4d65fc2f04bdad9fb73aba320b58a124240) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - testing this stuff out to see how the release candidate works with monorepo


## Links discovered
- [#1396](https://github.com/eyaltoledano/claude-task-master/pull/1396)
- [`9883e83`](https://github.com/eyaltoledano/claude-task-master/commit/9883e83b78306e55003e960ea072a11048d89ec9)
- [@bjcoombs](https://github.com/bjcoombs)
- [#1305](https://github.com/eyaltoledano/claude-task-master/pull/1305)
- [`a98d96e`](https://github.com/eyaltoledano/claude-task-master/commit/a98d96ef0414833b948672f86da4acc11f700ebb)
- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213)
- [`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)
- [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)
- [`cd90b4d`](https://github.com/eyaltoledano/claude-task-master/commit/cd90b4d65fc2f04bdad9fb73aba320b58a124240)

--- apps/extension/CHANGELOG.md ---
# Change Log

## 0.26.0

### Minor Changes

- [#1403](https://github.com/eyaltoledano/claude-task-master/pull/1403) [`a381376`](https://github.com/eyaltoledano/claude-task-master/commit/a381376ba4925593bfb49d934693a83c804cd2a5) Thanks [@EDKarlsson](https://github.com/EDKarlsson)! - Updated readme mcp configuration example to not include package=task-master-ai.

## 0.26.0-rc.0

### Minor Changes

- [#1403](https://github.com/eyaltoledano/claude-task-master/pull/1403) [`a381376`](https://github.com/eyaltoledano/claude-task-master/commit/a381376ba4925593bfb49d934693a83c804cd2a5) Thanks [@EDKarlsson](https://github.com/EDKarlsson)! - Updated readme mcp configuration example to not include package=task-master-ai.

## 0.25.6

## 0.25.6-rc.0

### Patch Changes

- Updated dependencies [[`f12a16d`](https://github.com/eyaltoledano/claude-task-master/commit/f12a16d09649f62148515f11f616157c7d0bd2d5), [`3010b90`](https://github.com/eyaltoledano/claude-task-master/commit/3010b90d98f3a7d8636caa92fc33d6ee69d4bed0), [`2a910a4`](https://github.com/eyaltoledano/claude-task-master/commit/2a910a40bac375f9f61d797bf55597303d556b48), [`aaf903f`](https://github.com/eyaltoledano/claude-task-master/commit/aaf903ff2f606c779a22e9a4b240ab57b3683815), [`90e6bdc`](https://github.com/eyaltoledano/claude-task-master/commit/90e6bdcf1c59f65ad27fcdfe3b13b9dca7e77654)]:
  - task-master-ai@0.29.0-rc.0

## 0.25.5

### Patch Changes

- Updated dependencies [[`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21), [`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3), [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d), [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0), [`4f984f8`](https://github.com/eyaltoledano/claude-task-master/commit/4f984f8a6965da9f9c7edd60ddfd6560ac022917), [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5), [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede), [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541), [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d), [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a), [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca), [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055)]:
  - task-master-ai@0.28.0

## 0.25.5-rc.0

### Patch Changes

- Updated dependencies [[`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3), [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d), [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede), [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541), [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d), [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a), [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca), [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055)]:
  - task-master-ai@0.28.0-rc.0

## 0.25.4

### Patch Changes

- Updated dependencies [[`af53525`](https://github.com/eyaltoledano/claude-task-master/commit/af53525cbc660a595b67d4bb90d906911c71f45d)]:
  - task-master-ai@0.27.3

## 0.25.3

### Patch Changes

- Updated dependencies [[`044a7bf`](https://github.com/eyaltoledano/claude-task-master/commit/044a7bfc98049298177bc655cf341d7a8b6a0011)]:
  - task-master-ai@0.27.2

## 0.25.2

### Patch Changes

- Updated dependencies [[`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e), [`c911608`](https://github.com/eyaltoledano/claude-task-master/commit/c911608f60454253f4e024b57ca84e5a5a53f65c), [`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)]:
  - task-master-ai@0.27.1

## 0.25.2-rc.1

### Patch Changes

- Updated dependencies [[`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)]:
  - task-master-ai@0.27.1-rc.1

## 0.25.2-rc.0

### Patch Changes

- Updated dependencies [[`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e)]:
  - task-master-ai@0.27.1-rc.0

## 0.25.0

### Minor Changes

- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add "Start Task" button to VS Code extension for seamless Claude Code integration

  You can now click a "Start Task" button directly in the Task Master extension which will open a new terminal and automatically execute the task using Claude Code. This provides a seamless workflow from viewing tasks in the extension to implementing them without leaving VS Code.

- [#1201](https://github.com/eyaltoledano/claude-task-master/pull/1201) [`83af314`](https://github.com/eyaltoledano/claude-task-master/commit/83af314879fc0e563581161c60d2bd089899313e) Thanks [@losolosol](https://github.com/losolosol)! - Added a Start Build button to the VSCODE Task Properties Right Panel

### Patch Changes

- [#1229](https://github.com/eyaltoledano/claude-task-master/pull/1229) [`674d1f6`](https://github.com/eyaltoledano/claude-task-master/commit/674d1f6de7ea98116b61bdae6198bafe6c4e7c1a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP not connecting to new Taskmaster version

- Updated dependencies [[`4e12643`](https://github.com/eyaltoledano/claude-task-master/commit/4e126430a092fb54afb035514fb3d46115714f97), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`a621ff0`](https://github.com/eyaltoledano/claude-task-master/commit/a621ff05eafb51a147a9aabd7b37ddc0e45b0869), [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142)]:
  - task-master-ai@0.27.0

## 0.25.0-rc.0

### Minor Changes

- [#1201](https://github.com/eyaltoledano/claude-task-master/pull/1201) [`83af314`](https://github.com/eyaltoledano/claude-task-master/commit/83af314879fc0e563581161c60d2bd089899313e) Thanks [@losolosol](https://github.com/losolosol)! - Added a Start Build button to the VSCODE Task Properties Right Panel

### Patch Changes

- Updated dependencies [[`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)]:
  - task-master-ai@0.27.0-rc.0

## 0.24.2

### Patch Changes

- Updated dependencies [[`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`df26c65`](https://github.com/eyaltoledano/claude-task-master/commit/df26c65632000874a73504963b08f18c46283144), [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66), [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e), [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9)]:
  - task-master-ai@0.26.0

## 0.24.2-rc.1

### Patch Changes

- Updated dependencies [[`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e)]:
  - task-master-ai@0.26.0-rc.1

## 0.24.2-rc.0

### Patch Changes

- Updated dependencies [[`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66), [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f), [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9)]:
  - task-master-ai@0.26.0-rc.0

## 0.24.1

### Patch Changes

- Updated dependencies [[`8933557`](https://github.com/eyaltoledano/claude-task-master/commit/89335578ffffc65504b2055c0c85aa7521e5e79b), [`db720a9`](https://github.com/eyaltoledano/claude-task-master/commit/db720a954d390bb44838cd021b8813dde8f3d8de)]:
  - task-master-ai@0.25.1

## 0.24.0

### Minor Changes

- [#1100](https://github.com/eyaltoledano/claude-task-master/pull/1100) [`30ca144`](https://github.com/eyaltoledano/claude-task-master/commit/30ca144231c36a6c63911f20adc225d38fb15a2f) Thanks [@vedovelli](https://github.com/vedovelli)! - Display current task ID on task details page

### Patch Changes

- Updated dependencies [[`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8), [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1), [`782728f`](https://github.com/eyaltoledano/claude-task-master/commit/782728ff95aa2e3b766d48273b57f6c6753e8573), [`3dee60d`](https://github.com/eyaltoledano/claude-task-master/commit/3dee60dc3d566e3cff650accb30f994b8bb3a15e), [`e3ed4d7`](https://github.com/eyaltoledano/claude-task-master/commit/e3ed4d7c14b56894d7da675eb2b757423bea8f9d), [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8), [`95640dc`](https://github.com/eyaltoledano/claude-task-master/commit/95640dcde87ce7879858c0a951399fb49f3b6397), [`311b243`](https://github.com/eyaltoledano/claude-task-master/commit/311b2433e23c771c8d3a4d3f5ac577302b8321e5)]:
  - task-master-ai@0.25.0

## 0.24.0-rc.0

### Minor Changes

- [#1040](https://github.com/eyaltoledano/claude-task-master/pull/1040) [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1) Thanks [@DomVidja](https://github.com/DomVidja)! - "Add Kilo Code profile integration with custom modes and MCP configuration"

- [#1100](https://github.com/eyaltoledano/claude-task-master/pull/1100) [`30ca144`](https://github.com/eyaltoledano/claude-task-master/commit/30ca144231c36a6c63911f20adc225d38fb15a2f) Thanks [@vedovelli](https://github.com/vedovelli)! - Display current task ID on task details page

### Patch Changes

- Updated dependencies [[`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8), [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1), [`782728f`](https://github.com/eyaltoledano/claude-task-master/commit/782728ff95aa2e3b766d48273b57f6c6753e8573), [`3dee60d`](https://github.com/eyaltoledano/claude-task-master/commit/3dee60dc3d566e3cff650accb30f994b8bb3a15e), [`e3ed4d7`](https://github.com/eyaltoledano/claude-task-master/commit/e3ed4d7c14b56894d7da675eb2b757423bea8f9d), [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8), [`95640dc`](https://github.com/eyaltoledano/claude-task-master/commit/95640dcde87ce7879858c0a951399fb49f3b6397), [`311b243`](https://github.com/eyaltoledano/claude-task-master/commit/311b2433e23c771c8d3a4d3f5ac577302b8321e5)]:
  - task-master-ai@0.25.0-rc.0

## 0.23.1

### Patch Changes

- [#1090](https://github.com/eyaltoledano/claude-task-master/pull/1090) [`a464e55`](https://github.com/eyaltoledano/claude-task-master/commit/a464e550b886ef81b09df80588fe5881bce83d93) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix issues with some users not being able to connect to Taskmaster MCP server while using the extension

- Updated dependencies [[`4357af3`](https://github.com/eyaltoledano/claude-task-master/commit/4357af3f13859d90bca8795215e5d5f1d94abde5), [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05), [`36468f3`](https://github.com/eyaltoledano/claude-task-master/commit/36468f3c93faf4035a5c442ccbc501077f3440f1), [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05), [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05), [`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b), [`4bb6370`](https://github.com/eyaltoledano/claude-task-master/commit/4bb63706b80c28d1b2d782ba868a725326f916c7)]:
  - task-master-ai@0.24.0

## 0.23.1-rc.1

### Patch Changes

- Updated dependencies [[`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b)]:
  - task-master-ai@0.24.0-rc.2

## 0.23.1-rc.0

### Patch Changes

- [#1090](https://github.com/eyaltoledano/claude-task-master/pull/1090) [`a464e55`](https://github.com/eyaltoledano/claude-task-master/commit/a464e550b886ef81b09df80588fe5881bce83d93) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix issues with some users not being able to connect to Taskmaster MCP server while using the extension

- Updated dependencies [[`4357af3`](https://github.com/eyaltoledano/claude-task-master/commit/4357af3f13859d90bca8795215e5d5f1d94abde5), [`36468f3`](https://github.com/eyaltoledano/claude-task-master/commit/36468f3c93faf4035a5c442ccbc501077f3440f1), [`4bb6370`](https://github.com/eyaltoledano/claude-task-master/commit/4bb63706b80c28d1b2d782ba868a725326f916c7)]:
  - task-master-ai@0.24.0-rc.1

## 0.23.0

### Minor Changes

- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`b82d858`](https://github.com/eyaltoledano/claude-task-master/commit/b82d858f81a1e702ad59d84d5ae8a2ca84359a83) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - 🎉 **Introducing TaskMaster Extension!**

  We're thrilled to launch the first version of our Code extension, bringing the power of TaskMaster directly into your favorite code editor. While this is our initial release and we've kept things focused, it already packs powerful features to supercharge your development workflow.

  ## ✨ Key Features

  ### 📋 Visual Task Management
  - **Kanban Board View**: Visualize all your tasks in an intuitive board layout directly in VS Code
  - **Drag & Drop**: Easily change task status by dragging cards between columns
  - **Real-time Updates**: See changes instantly as you work through your project

  ### 🏷️ Multi-Context Support
  - **Tag Switching**: Seamlessly switch between different project contexts/tags
  - **Isolated Workflows**: Keep different features or experiments organized separately

  ### 🤖 AI-Powered Task Updates
  - **Smart Updates**: Use TaskMaster's AI capabilities to update tasks and subtasks
  - **Context-Aware**: Leverages your existing TaskMaster configuration and models

  ### 📊 Rich Task Information
  - **Complexity Scores**: See task complexity ratings at a glance
  - **Subtask Visualization**: Expand tasks to view and manage subtasks
  - **Dependency Graphs**: Understand task relationships and dependencies visually

  ### ⚙️ Configuration Management
  - **Visual Config Editor**: View and understand your `.taskmaster/config.json` settings
  - **Easy Access**: No more manual JSON editing for common configuration tasks

  ### 🚀 Quick Actions
  - **Status Updates**: Change task status with a single click
  - **Task Details**: Access full task information without leaving VS Code
  - **Integrated Commands**: All TaskMaster commands available through the command palette

  ## 🎯 What's Next?

  This is just the beginning! We wanted to get a solid foundation into your hands quickly. The extension will evolve rapidly with your feedback, adding more advanced features, better visualizations, and deeper integration with your development workflow.

  Thank you for being part of the TaskMaster journey. Your workflow has never looked better! 🚀

## 0.23.0-rc.1

### Minor Changes

- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`b82d858`](https://github.com/eyaltoledano/claude-task-master/commit/b82d858f81a1e702ad59d84d5ae8a2ca84359a83) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - 🎉 **Introducing TaskMaster Extension!**

  We're thrilled to launch the first version of our Code extension, bringing the power of TaskMaster directly into your favorite code editor. While this is our initial release and we've kept things focused, it already packs powerful features to supercharge your development workflow.

  ## ✨ Key Features

  ### 📋 Visual Task Management
  - **Kanban Board View**: Visualize all your tasks in an intuitive board layout directly in VS Code
  - **Drag & Drop**: Easily change task status by dragging cards between columns
  - **Real-time Updates**: See changes instantly as you work through your project

  ### 🏷️ Multi-Context Support
  - **Tag Switching**: Seamlessly switch between different project contexts/tags
  - **Isolated Workflows**: Keep different features or experiments organized separately

  ### 🤖 AI-Powered Task Updates
  - **Smart Updates**: Use TaskMaster's AI capabilities to update tasks and subtasks
  - **Context-Aware**: Leverages your existing TaskMaster configuration and models

  ### 📊 Rich Task Information
  - **Complexity Scores**: See task complexity ratings at a glance
  - **Subtask Visualization**: Expand tasks to view and manage subtasks
  - **Dependency Graphs**: Understand task relationships and dependencies visually

  ### ⚙️ Configuration Management
  - **Visual Config Editor**: View and understand your `.taskmaster/config.json` settings
  - **Easy Access**: No more manual JSON editing for common configuration tasks

  ### 🚀 Quick Actions
  - **Status Updates**: Change task status with a single click
  - **Task Details**: Access full task information without leaving VS Code
  - **Integrated Commands**: All TaskMaster commands available through the command palette

  ## 🎯 What's Next?

  This is just the beginning! We wanted to get a solid foundation into your hands quickly. The extension will evolve rapidly with your feedback, adding more advanced features, better visualizations, and deeper integration with your development workflow.

  Thank you for being part of the TaskMaster journey. Your workflow has never looked better! 🚀

## 0.23.0-rc.0

### Minor Changes

- [#997](https://github.com/eyaltoledano/claude-task-master/pull/997) [`64302dc`](https://github.com/eyaltoledano/claude-task-master/commit/64302dc1918f673fcdac05b29411bf76ffe93505) Thanks [@DavidMaliglowka](https://github.com/DavidMaliglowka)! - 🎉 **Introducing TaskMaster Extension!**

  We're thrilled to launch the first version of our Code extension, bringing the power of TaskMaster directly into your favorite code editor. While this is our initial release and we've kept things focused, it already packs powerful features to supercharge your development workflow.

  ## ✨ Key Features

  ### 📋 Visual Task Management
  - **Kanban Board View**: Visualize all your tasks in an intuitive board layout directly in VS Code
  - **Drag & Drop**: Easily change task status by dragging cards between columns
  - **Real-time Updates**: See changes instantly as you work through your project

  ### 🏷️ Multi-Context Support
  - **Tag Switching**: Seamlessly switch between different project contexts/tags
  - **Isolated Workflows**: Keep different features or experiments organized separately

  ### 🤖 AI-Powered Task Updates
  - **Smart Updates**: Use TaskMaster's AI capabilities to update tasks and subtasks
  - **Context-Aware**: Leverages your existing TaskMaster configuration and models

  ### 📊 Rich Task Information
  - **Complexity Scores**: See task complexity ratings at a glance
  - **Subtask Visualization**: Expand tasks to view and manage subtasks
  - **Dependency Graphs**: Understand task relationships and dependencies visually

  ### ⚙️ Configuration Management
  - **Visual Config Editor**: View and understand your `.taskmaster/config.json` settings
  - **Easy Access**: No more manual JSON editing for common configuration tasks

  ### 🚀 Quick Actions
  - **Status Updates**: Change task status with a single click
  - **Task Details**: Access full task information without leaving VS Code
  - **Integrated Commands**: All TaskMaster commands available through the command palette

  ## 🎯 What's Next?

  This is just the beginning! We wanted to get a solid foundation into your hands quickly. The extension will evolve rapidly with your feedback, adding more advanced features, better visualizations, and deeper integration with your development workflow.

  Thank you for being part of the TaskMaster journey. Your workflow has never looked better! 🚀


## Links discovered
- [#1403](https://github.com/eyaltoledano/claude-task-master/pull/1403)
- [`a381376`](https://github.com/eyaltoledano/claude-task-master/commit/a381376ba4925593bfb49d934693a83c804cd2a5)
- [@EDKarlsson](https://github.com/EDKarlsson)
- [[`f12a16d`](https://github.com/eyaltoledano/claude-task-master/commit/f12a16d09649f62148515f11f616157c7d0bd2d5)
- [`3010b90`](https://github.com/eyaltoledano/claude-task-master/commit/3010b90d98f3a7d8636caa92fc33d6ee69d4bed0)
- [`2a910a4`](https://github.com/eyaltoledano/claude-task-master/commit/2a910a40bac375f9f61d797bf55597303d556b48)
- [`aaf903f`](https://github.com/eyaltoledano/claude-task-master/commit/aaf903ff2f606c779a22e9a4b240ab57b3683815)
- [`90e6bdc`](https://github.com/eyaltoledano/claude-task-master/commit/90e6bdcf1c59f65ad27fcdfe3b13b9dca7e77654)
- [[`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21)
- [`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3)
- [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d)
- [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0)
- [`4f984f8`](https://github.com/eyaltoledano/claude-task-master/commit/4f984f8a6965da9f9c7edd60ddfd6560ac022917)
- [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5)
- [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e)
- [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042)
- [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede)
- [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541)
- [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d)
- [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a)
- [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca)
- [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055)
- [[`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3)
- [[`af53525`](https://github.com/eyaltoledano/claude-task-master/commit/af53525cbc660a595b67d4bb90d906911c71f45d)
- [[`044a7bf`](https://github.com/eyaltoledano/claude-task-master/commit/044a7bfc98049298177bc655cf341d7a8b6a0011)
- [[`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e)
- [`c911608`](https://github.com/eyaltoledano/claude-task-master/commit/c911608f60454253f4e024b57ca84e5a5a53f65c)
- [`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)
- [[`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200)
- [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142)
- [@eyaltoledano](https://github.com/eyaltoledano)
- [#1201](https://github.com/eyaltoledano/claude-task-master/pull/1201)
- [`83af314`](https://github.com/eyaltoledano/claude-task-master/commit/83af314879fc0e563581161c60d2bd089899313e)
- [@losolosol](https://github.com/losolosol)
- [#1229](https://github.com/eyaltoledano/claude-task-master/pull/1229)
- [`674d1f6`](https://github.com/eyaltoledano/claude-task-master/commit/674d1f6de7ea98116b61bdae6198bafe6c4e7c1a)
- [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)
- [[`4e12643`](https://github.com/eyaltoledano/claude-task-master/commit/4e126430a092fb54afb035514fb3d46115714f97)
- [`a621ff0`](https://github.com/eyaltoledano/claude-task-master/commit/a621ff05eafb51a147a9aabd7b37ddc0e45b0869)
- [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515)
- [[`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)
- [[`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f)
- [`df26c65`](https://github.com/eyaltoledano/claude-task-master/commit/df26c65632000874a73504963b08f18c46283144)
- [`37af0f1`](https://github.com/eyaltoledano/claude-task-master/commit/37af0f191227a68d119b7f89a377bf932ee3ac66)
- [`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e)
- [`8783708`](https://github.com/eyaltoledano/claude-task-master/commit/8783708e5e3389890a78fcf685d3da0580e73b3f)
- [`4dad2fd`](https://github.com/eyaltoledano/claude-task-master/commit/4dad2fd613ceac56a65ae9d3c1c03092b8860ac9)
- [[`c4f92f6`](https://github.com/eyaltoledano/claude-task-master/commit/c4f92f6a0aee3435c56eb8d27d9aa9204284833e)
- [[`8933557`](https://github.com/eyaltoledano/claude-task-master/commit/89335578ffffc65504b2055c0c85aa7521e5e79b)
- [`db720a9`](https://github.com/eyaltoledano/claude-task-master/commit/db720a954d390bb44838cd021b8813dde8f3d8de)
- [#1100](https://github.com/eyaltoledano/claude-task-master/pull/1100)
- [`30ca144`](https://github.com/eyaltoledano/claude-task-master/commit/30ca144231c36a6c63911f20adc225d38fb15a2f)
- [@vedovelli](https://github.com/vedovelli)
- [[`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8)
- [`fc47714`](https://github.com/eyaltoledano/claude-task-master/commit/fc477143400fd11d953727bf1b4277af5ad308d1)
- [`782728f`](https://github.com/eyaltoledano/claude-task-master/commit/782728ff95aa2e3b766d48273b57f6c6753e8573)
- [`3dee60d`](https://github.com/eyaltoledano/claude-task-master/commit/3dee60dc3d566e3cff650accb30f994b8bb3a15e)
- [`e3ed4d7`](https://github.com/eyaltoledano/claude-task-master/commit/e3ed4d7c14b56894d7da675eb2b757423bea8f9d)
- [`04e11b5`](https://github.com/eyaltoledano/claude-task-master/commit/04e11b5e828597c0ba5b82ca7d5fb6f933e4f1e8)
- [`95640dc`](https://github.com/eyaltoledano/claude-task-master/commit/95640dcde87ce7879858c0a951399fb49f3b6397)
- [`311b243`](https://github.com/eyaltoledano/claude-task-master/commit/311b2433e23c771c8d3a4d3f5ac577302b8321e5)
- [#1040](https://github.com/eyaltoledano/claude-task-master/pull/1040)
- [@DomVidja](https://github.com/DomVidja)
- [#1090](https://github.com/eyaltoledano/claude-task-master/pull/1090)
- [`a464e55`](https://github.com/eyaltoledano/claude-task-master/commit/a464e550b886ef81b09df80588fe5881bce83d93)
- [[`4357af3`](https://github.com/eyaltoledano/claude-task-master/commit/4357af3f13859d90bca8795215e5d5f1d94abde5)
- [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05)
- [`36468f3`](https://github.com/eyaltoledano/claude-task-master/commit/36468f3c93faf4035a5c442ccbc501077f3440f1)
- [`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b)
- [`4bb6370`](https://github.com/eyaltoledano/claude-task-master/commit/4bb63706b80c28d1b2d782ba868a725326f916c7)
- [[`75c514c`](https://github.com/eyaltoledano/claude-task-master/commit/75c514cf5b2ca47f95c0ad7fa92654a4f2a6be4b)
- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064)
- [`b82d858`](https://github.com/eyaltoledano/claude-task-master/commit/b82d858f81a1e702ad59d84d5ae8a2ca84359a83)
- [#997](https://github.com/eyaltoledano/claude-task-master/pull/997)
- [`64302dc`](https://github.com/eyaltoledano/claude-task-master/commit/64302dc1918f673fcdac05b29411bf76ffe93505)
- [@DavidMaliglowka](https://github.com/DavidMaliglowka)

--- apps/mcp/CHANGELOG.md ---
# @tm/mcp

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null


--- packages/build-config/CHANGELOG.md ---
# @tm/build-config

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## 1.0.1


--- packages/claude-code-plugin/CHANGELOG.md ---
# @tm/claude-code-plugin

## 0.0.10

## 0.0.9

## 0.0.8

## 0.0.7

## 0.0.6

## 0.0.5

## 0.0.4

## 0.0.3

## 0.0.3

## 0.0.2


--- packages/tm-bridge/CHANGELOG.md ---
# @tm/bridge

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
  - @tm/core@null


--- packages/tm-core/CHANGELOG.md ---
# Changelog

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## null

## 0.26.1

All notable changes to the @task-master/tm-core package will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Initial package structure and configuration
- TypeScript support with strict mode
- Dual ESM/CJS build system with tsup
- Jest testing framework with TypeScript support
- ESLint and Prettier for code quality
- Modular architecture with barrel exports
- Placeholder implementations for all modules
- Comprehensive documentation and README

### Development Infrastructure

- tsup configuration for dual format builds
- Jest configuration with ESM support
- ESLint configuration with TypeScript rules
- Prettier configuration for consistent formatting
- Complete package.json with all required fields
- TypeScript configuration with strict settings
- .gitignore for development files

### Package Structure

- `src/types/` - TypeScript type definitions (placeholder)
- `src/providers/` - AI provider implementations (placeholder)
- `src/storage/` - Storage layer abstractions (placeholder)
- `src/parser/` - Task parsing utilities (placeholder)
- `src/utils/` - Common utility functions (placeholder)
- `src/errors/` - Custom error classes (placeholder)
- `tests/` - Test directories and setup

## [1.0.0] - TBD

### Planned Features

- Complete TypeScript type system
- AI provider implementations
- Storage adapters
- Task parsing capabilities
- Comprehensive utility functions
- Custom error handling
- Full test coverage
- Complete documentation

---

## Release Notes

### Version 1.0.0 (Coming Soon)

This will be the first stable release of tm-core with complete implementations of all modules. Currently, all modules contain placeholder implementations to establish the package structure and enable development of dependent packages.

### Development Status

- ✅ Package structure and configuration
- ✅ Build and test infrastructure
- ✅ Development tooling setup
- 🚧 TypeScript types implementation (Task 116)
- 🚧 AI provider system (Task 117)
- 🚧 Storage layer (Task 118)
- 🚧 Task parser (Task 119)
- 🚧 Utility functions (Task 120)
- 🚧 Error handling (Task 121)
- 🚧 Configuration system (Task 122)
- 🚧 Testing infrastructure (Task 123)
- 🚧 Documentation (Task 124)
- 🚧 Package finalization (Task 125)


## Links discovered
- [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

--- packages/tm-profiles/CHANGELOG.md ---
# @tm/profiles

## null

## null

## null


--- .changeset/README.md ---
# Changesets

This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos or single-package repos to help version and publish code. Full documentation is available in the [Changesets repository](https://github.com/changesets/changesets).

## What are Changesets?

Changesets are a way to track changes to packages in your repository. Each changeset:

- Describes the changes you've made
- Specifies the type of version bump needed (patch, minor, or major)
- Connects these changes with release notes
- Automates the versioning and publishing process

## How to Use Changesets in Task Master

### 2. Making Changes

1. Create a new branch for your changes
2. Make your code changes
3. Write tests and ensure all tests pass

### 3. Creating a Changeset

After making changes, create a changeset by running:

```bash
npx changeset
```

This will:

- Walk you through a CLI to describe your changes
- Ask you to select impact level (patch, minor, major)
- Create a markdown file in the `.changeset` directory

### 4. Impact Level Guidelines

When choosing the impact level for your changes:

- **Patch**: Bug fixes and minor changes that don't affect how users interact with the system
  - Example: Fixing a typo in output text, optimizing code without changing behavior
- **Minor**: New features or enhancements that don't break existing functionality
  - Example: Adding a new flag to an existing command, adding new task metadata fields
- **Major**: Breaking changes that require users to update their usage
  - Example: Renaming a command, changing the format of the tasks.json file

### 5. Writing Good Changeset Descriptions

Your changeset description should:

- Be written for end-users, not developers
- Clearly explain what changed and why
- Include any migration steps or backward compatibility notes
- Reference related issues or pull requests with `#issue-number`

Examples:

```md
# Good

Added new `--research` flag to the `expand` command that uses Perplexity AI
to provide research-backed task expansions. Requires PERPLEXITY_API_KEY
environment variable.

# Not Good

Fixed stuff and added new flag
```

### 6. Committing Your Changes

Commit both your code changes and the generated changeset file:

```bash
git add .
git commit -m "Add feature X with changeset"
git push
```

### 7. Pull Request Process

1. Open a pull request
2. Ensure CI passes
3. Await code review
4. Once approved and merged, your changeset will be used during the next release

## Release Process (for Maintainers)

When it's time to make a release:

1. Ensure all desired changesets are merged
2. Run `npx changeset version` to update package versions and changelog
3. Review and commit the changes
4. Run `npm publish` to publish to npm

This can be automated through Github Actions

## Common Issues and Solutions

- **Merge Conflicts in Changeset Files**: Resolve just like any other merge conflict
- **Multiple Changes in One PR**: Create multiple changesets if changes affect different areas
- **Accidentally Committed Without Changeset**: Create the changeset after the fact and commit it separately

## Additional Resources

- [Changesets Documentation](https://github.com/changesets/changesets)
- [Common Questions](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)


## Links discovered
- [Changesets repository](https://github.com/changesets/changesets)
- [Changesets Documentation](https://github.com/changesets/changesets)
- [Common Questions](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

--- .cursor/commands/goham.md ---
# Start Working with Hamster Brief

End-to-end workflow for working on tasks from a connected Hamster brief. All tasks from the brief are worked on in a single branch, with one PR created at the end.

## Step 1: Verify Connection & Authentication

```bash
# Check current context and authentication status
tm context
```

If not connected or authentication fails:
- Get brief URL from user if not available
- Connect: `tm context <brief url>`
- Refresh token if needed: `tm auth refresh`

## Step 2: List Available Tasks

```bash
# View all tasks from the brief
tm list
```

Review the task list to understand what needs to be done. Note the total number of tasks.

## Step 3: Initialize Git Branch for Brief

```bash
# Ensure you're on dev branch and pull latest
git checkout dev
git pull origin dev

# Create a single branch for the entire brief (e.g., hamster-brief-YYYY-MM-DD or brief-specific name)
git checkout -b hamster-brief

# Verify branch creation
git branch
```

**Note**: This branch will be used for ALL tasks in the brief. Do not create separate branches per task.

## Step 4: Task Loop (Repeat for Each Task)

Work through all tasks sequentially in the same branch:

### 4.1: Read Task Details

```bash
# Get detailed information about the task
tm show 1

# If task has subtasks, examine them all
tm show 1,1.1,1.2,1.3  # Adjust IDs as needed
```

### 4.2: Log Initial Context

```bash
# Document task understanding and initial findings
tm update-task -i 1 --append --prompt="Starting task implementation.

Initial context:
- Task requirements: [summarize key requirements]
- Dependencies identified: [list any dependencies]
- Files that may need modification: [list relevant files]
- Approach planned: [brief implementation approach]"
```

### 4.3: Mark Task as In-Progress

```bash
# Mark task and first subtask (if exists) as in-progress
tm set-status -i 1,1.1 -s in-progress
```

### 4.4: Subtask Implementation Loop

For each subtask (1.1, 1.2, 1.3, etc.):

#### 4.4.1: Read Subtask Details
```bash
tm show 1.1  # Replace with current subtask ID
```

#### 4.4.2: Log Research & Context Gathering
```bash
# Document findings during implementation
tm update-task -i 1 --append --prompt="Subtask 1.1 - Context gathered:

- Code exploration findings: [what you discovered]
- Implementation approach: [how you plan to implement]
- Key decisions made: [important choices]
- Challenges encountered: [any blockers or issues]"
```

#### 4.4.3: Implement Subtask
- Write code following the subtask requirements
- Make necessary changes to files

#### 4.4.4: Quality Verification
```bash
# Run linting
pnpm lint

# Run type checking
pnpm typecheck

# If either fails, fix issues and re-run until both pass
```

#### 4.4.5: CodeRabbit Review
```bash
# Generate code review (wait for plain text results)
coderabbit --prompt-only

# Review the output and address any critical issues if needed
```

#### 4.4.6: Log Implementation Completion
```bash
# Document what was completed
tm update-task -i 1 --append --prompt="Subtask 1.1 - Implementation complete:

- Files modified: [list files changed]
- Key changes: [summary of implementation]
- CodeRabbit feedback addressed: [if any issues were fixed]
- Ready for commit"
```

#### 4.4.7: Commit Subtask Work
```bash
# Stage changes
git add .

# Commit with detailed message following git_workflow.mdc format
git commit -m "feat(task-1): Complete subtask 1.1 - [Subtask Title]

- Implementation details
- Key changes made
- Files modified: [list files]
- CodeRabbit review completed

Subtask 1.1: [Brief description of what was accomplished]
Relates to Task 1: [Main task title]"
```

#### 4.4.8: Mark Subtask as Done
```bash
tm set-status -i 1.1 -s done
```

#### 4.4.9: Move to Next Subtask
Repeat steps 4.4.1 through 4.4.8 for the next subtask (1.2, 1.3, etc.)

### 4.5: Complete Parent Task

After all subtasks are complete:

#### 4.5.1: Final Quality Checks
```bash
# Final linting
pnpm lint

# Final type checking
pnpm typecheck

# Final CodeRabbit review
coderabbit --prompt-only

# Address any remaining issues if critical
```

#### 4.5.2: Log Task Completion
```bash
# Document final task completion
tm update-task -i 1 --append --prompt="Task 1 - Complete:

- All subtasks completed: [list all subtasks]
- Final verification passed: lint, typecheck, CodeRabbit review
- Files changed: [comprehensive list]
- Committed to brief branch"
```

#### 4.5.3: Mark Parent Task as Done
```bash
tm set-status -i 1 -s done
```

**Note**: Do NOT push or create PR yet. Continue to next task in the same branch.

### 4.6: Move to Next Task

```bash
# Verify remaining tasks
tm list

# Continue with next task (e.g., Task 2)
# Repeat steps 4.1 through 4.5 for Task 2, then Task 3, etc.
```

## Step 5: Complete All Tasks

Continue working through all tasks (Steps 4.1-4.6) until all tasks in the brief are complete. All work is committed to the same `hamster-brief` branch.

## Step 6: Final Verification & PR Creation

After ALL tasks are complete:

### 6.1: Verify All Tasks Complete
```bash
# Verify all tasks are done
tm list

# Should show all tasks with status 'done'
```

### 6.2: Final Quality Checks
```bash
# Final comprehensive checks
pnpm lint
pnpm typecheck
coderabbit --prompt-only

# Address any remaining issues if critical
```

### 6.3: Push Branch
```bash
# Push the brief branch to remote
git push origin hamster-brief
```

### 6.4: Create Pull Request to Dev
```bash
# Get all task titles (adjust task IDs as needed)
# Create comprehensive PR description

gh pr create \
  --base dev \
  --title "Hamster Brief: Complete Implementation" \
  --body "## Brief Overview
Completed all tasks from Hamster brief.

## Tasks Completed
- [x] Task 1: [Task 1 title]
  - Subtasks: 1.1, 1.2, 1.3
- [x] Task 2: [Task 2 title]
  - Subtasks: 2.1, 2.2
- [x] Task 3: [Task 3 title]
  - [Continue listing all tasks]

## Implementation Summary
- Total tasks: [number]
- Total subtasks: [number]
- Files modified: [comprehensive list]
- All quality checks passed

## Quality Checks
- ✅ Linting passed (pnpm lint)
- ✅ Type checking passed (pnpm typecheck)
- ✅ CodeRabbit review completed for all changes

## Testing
- [ ] Manual testing completed
- [ ] All checks passing

Complete implementation of Hamster brief tasks"
```

## Step 7: Cleanup

```bash
# After PR is merged, switch back to dev
git checkout dev
git pull origin dev

# Delete local branch (optional)
git branch -d hamster-brief
```

## Important Notes

- **Use ONLY**: `tm list`, `tm show <id>`, `tm set-status`, `tm update-task`, `tm auth refresh`, `tm context <brief url>`
- **DON'T use MCP tools** - not compatible with Hamster integration
- **Single branch per brief**: All tasks work in the same branch (`hamster-brief`)
- **Single PR per brief**: One PR created after all tasks are complete
- **Always target dev branch** - never main branch
- **Regular logging**: Use `tm update-task -i <id> --append` frequently to document:
  - Context gathered during exploration
  - Implementation decisions made
  - Challenges encountered
  - Completion status
- **Quality gates**: Never skip lint, typecheck, or CodeRabbit review
- **Commit format**: Follow git_workflow.mdc commit message standards
- **PR format**: Always use `--base dev` when creating PRs

## Workflow Summary

```
1. Verify connection → tm context
2. List tasks → tm list
3. Create single branch → git checkout -b hamster-brief
4. For each task (in same branch):
   a. Read task → tm show X
   b. Log context → tm update-task -i X --append
   c. Mark in-progress → tm set-status -i X,X.Y -s in-progress
   d. For each subtask:
      - Read → tm show X.Y
      - Log context → tm update-task -i X --append
      - Implement code
      - Verify → pnpm lint && pnpm typecheck
      - Review → coderabbit --prompt-only
      - Log completion → tm update-task -i X --append
      - Commit → git commit (following git_workflow.mdc format)
      - Mark done → tm set-status -i X.Y -s done
   e. Final checks → pnpm lint && pnpm typecheck && coderabbit --prompt-only
   f. Log completion → tm update-task -i X --append
   g. Mark task done → tm set-status -i X -s done
   h. Continue to next task (same branch)
5. After ALL tasks complete:
   a. Final verification → pnpm lint && pnpm typecheck && coderabbit --prompt-only
   b. Push branch → git push origin hamster-brief
   c. Create PR → gh pr create --base dev
```

## References

- Full guidelines: [hamster.mdc](mdc:.cursor/rules/hamster.mdc)
- Git workflow: [git_workflow.mdc](mdc:.cursor/rules/git_workflow.mdc)


## Links discovered
- [hamster.mdc](https://github.com/eyaltoledano/claude-task-master/blob/main/.cursor/commands/mdc:.cursor/rules/hamster.mdc)
- [git_workflow.mdc](https://github.com/eyaltoledano/claude-task-master/blob/main/.cursor/commands/mdc:.cursor/rules/git_workflow.mdc)

--- CLAUDE.md ---
# Claude Code Instructions

## Task Master AI Instructions

**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**
@./.taskmaster/CLAUDE.md

## Test Guidelines

### Test File Placement

- **Package & tests**: Place in `packages/<package-name>/src/<module>/<file>.spec.ts` or `apps/<app-name>/src/<module>/<file.spec.ts>` alongside source
- **Package integration tests**: Place in `packages/<package-name>/tests/integration/<module>/<file>.test.ts` or `apps/<app-name>/tests/integration/<module>/<file>.test.ts` alongside source
- **Isolated unit tests**: Use `tests/unit/packages/<package-name>/` only when parallel placement isn't possible
- **Test extension**: Always use `.ts` for TypeScript tests, never `.js`

### Synchronous Tests

- **NEVER use async/await in test functions** unless testing actual asynchronous operations
- Use synchronous top-level imports instead of dynamic `await import()`
- Test bodies should be synchronous whenever possible
- Example:

  ```typescript
  // ✅ CORRECT - Synchronous imports with .ts extension
  import { MyClass } from '../src/my-class.js';

  it('should verify behavior', () => {
    expect(new MyClass().property).toBe(value);
  });

  // ❌ INCORRECT - Async imports
  it('should verify behavior', async () => {
    const { MyClass } = await import('../src/my-class.js');
    expect(new MyClass().property).toBe(value);
  });
  ```

### When to Write Tests

**ALWAYS write tests for:**

- **Bug fixes**: Add a regression test that would have caught the bug
- **Business logic**: Complex calculations, validations, transformations
- **Edge cases**: Boundary conditions, error handling, null/undefined cases
- **Public APIs**: Methods other code depends on
- **Integration points**: Database, file system, external APIs

**SKIP tests for:**

- Simple getters/setters: `getX() { return this.x; }`
- Trivial pass-through functions with no logic
- Pure configuration objects
- Code that just delegates to another tested function

**Examples:**

```javascript
// ✅ WRITE A TEST - Bug fix with regression prevention
it('should use correct baseURL from defaultBaseURL config', () => {
  const provider = new ZAIProvider();
  expect(provider.defaultBaseURL).toBe('https://api.z.ai/api/paas/v4/');
});

// ✅ WRITE A TEST - Business logic with edge cases
it('should parse subtask IDs correctly', () => {
  expect(parseTaskId('1.2.3')).toEqual({ taskId: 1, subtaskId: 2, subSubtaskId: 3 });
  expect(parseTaskId('invalid')).toBeNull();
});

// ❌ SKIP TEST - Trivial getter
class Task {
  get id() { return this._id; } // No test needed
}

// ❌ SKIP TEST - Pure delegation
function getTasks() {
  return taskManager.getTasks(); // Already tested in taskManager
}
```

**Bug Fix Workflow:**

1. Encounter a bug
2. Write a failing test that reproduces it
3. Fix the bug
4. Verify test now passes
5. Commit both fix and test together

### Testing Guidelines

**Principles**: FIRST (Fast, Independent, Repeatable, Self-validating, Timely)
**Structure**: AAA (Arrange, Act, Assert)
**Coverage**: Right-BICEP (Right results, Boundary, Inverse, Cross-check, Error conditions, Performance)

#### What to Mock

**Unit tests** (`.spec.ts` - test single unit in isolation):
- **@tm/core**: Mock only external I/O (Supabase, APIs, filesystem). Use real internal services.
- **apps/cli**: Mock tm-core responses. Use real Commander/chalk/inquirer/other npm packages (test display logic).
- **apps/mcp**: Mock tm-core responses. Use real MCP framework (test response formatting).

**Integration tests** (`tests/integration/` - test multiple units together):
- **All packages**: Use real tm-core, mock only external boundaries (APIs, DB, filesystem).

**Never mock**:
- Internal utilities/helpers in the same package
- Standard frameworks (Commander, Express) - let them run
- Standard library

**Rule of thumb**: Mock what you're NOT testing. CLI unit tests test display → mock tm-core. Core unit tests test logic → mock I/O. Integration tests test full flow → mock only external APIs.

**Red flag**: Mocking 3+ dependencies in a unit test means code is doing too much or is in the wrong layer.

**Anti-pattern**: Heavily mocked tests don't verify real behavior—they verify that you wired up mocks correctly. You end up writing orchestration code to satisfy tests, rather than tests that validate your actual implementation. If testing is hard, move the logic to where it's naturally testable.

## Architecture Guidelines

### Business Logic Separation

**CRITICAL RULE**: ALL business logic must live in `@tm/core`, NOT in presentation layers.

- **`@tm/core`** (packages/tm-core/):
  - Contains ALL business logic, domain models, services, and utilities
  - Provides clean facade APIs through domain objects (tasks, auth, workflow, git, config)
  - Houses all complexity - parsing, validation, transformations, calculations, etc.
  - Example: Task ID parsing, subtask extraction, status validation, dependency resolution

- **`@tm/cli`** (apps/cli/):
  - Thin presentation layer ONLY
  - Calls tm-core methods and displays results
  - Handles CLI-specific concerns: argument parsing, output formatting, user prompts
  - NO business logic, NO data transformations, NO calculations

- **`@tm/mcp`** (apps/mcp/):
  - Thin presentation layer ONLY
  - Calls tm-core methods and returns MCP-formatted responses
  - Handles MCP-specific concerns: tool schemas, parameter validation, response formatting
  - NO business logic, NO data transformations, NO calculations

- **`apps/extension`** (future):
  - Thin presentation layer ONLY
  - Calls tm-core methods and displays in VS Code UI
  - NO business logic

**Examples of violations to avoid:**

- ❌ Creating helper functions in CLI/MCP to parse task IDs → Move to tm-core
- ❌ Data transformation logic in CLI/MCP → Move to tm-core
- ❌ Validation logic in CLI/MCP → Move to tm-core
- ❌ Duplicating logic across CLI and MCP → Implement once in tm-core

**Correct approach:**

- ✅ Add method to TasksDomain: `tasks.get(taskId)` (automatically handles task and subtask IDs)
- ✅ CLI calls: `await tmCore.tasks.get(taskId)` (supports "1", "1.2", "HAM-123", "HAM-123.2")
- ✅ MCP calls: `await tmCore.tasks.get(taskId)` (same intelligent ID parsing)
- ✅ Single source of truth in tm-core

## Code Quality & Reusability Guidelines

Apply standard software engineering principles:

- **DRY (Don't Repeat Yourself)**: Extract patterns that appear 2+ times into reusable components or utilities
- **YAGNI (You Aren't Gonna Need It)**: Don't over-engineer. Create abstractions when duplication appears, not before
- **Maintainable**: Single source of truth. Change once, update everywhere
- **Readable**: Clear naming, proper structure, export from index files
- **Flexible**: Accept configuration options with sensible defaults

## Documentation Guidelines

- **Documentation location**: Write docs in `apps/docs/` (Mintlify site source), not `docs/`
- **Documentation URL**: Reference docs at <https://docs.task-master.dev>, not local file paths

## Changeset Guidelines

- **Add a changeset for code changes** - Run `npx changeset` after making code changes (not needed for docs-only PRs)
- When creating changesets, remember that it's user-facing, meaning we don't have to get into the specifics of the code, but rather mention what the end-user is getting or fixing from this changeset
- Run `npm run turbo:typecheck` before pushing to ensure TypeScript type checks pass
- Run `npm run test -w <package-name>` to test a package


--- CLAUDE_CODE_PLUGIN.md ---
# Taskmaster AI - Claude Code Marketplace

This repository includes a Claude Code plugin marketplace in `.claude-plugin/marketplace.json`.

## Installation

### From GitHub (Public Repository)

Once this repository is pushed to GitHub, users can install with:

```bash
# Add the marketplace
/plugin marketplace add eyaltoledano/claude-task-master

# Install the plugin
/plugin install taskmaster@taskmaster
```

### Local Development/Testing

```bash
# From the project root directory
cd /path/to/claude-task-master

# Build the plugin first
cd packages/claude-code-plugin
npm run build
cd ../..

# In Claude Code
/plugin marketplace add .
/plugin install taskmaster@taskmaster
```

## Marketplace Structure

```
claude-task-master/
├── .claude-plugin/
│   └── marketplace.json        # Marketplace manifest (at repo root)
│
├── packages/claude-code-plugin/
│   ├── src/build.ts           # Build tooling
│   └── [generated plugin files]
│
└── assets/claude/              # Plugin source files
    ├── commands/
    └── agents/
```

## Available Plugins

### taskmaster

AI-powered task management system for ambitious development workflows.

**Features:**

- 49 slash commands for comprehensive task management
- 3 specialized AI agents (orchestrator, executor, checker)
- MCP server integration
- Complexity analysis and auto-expansion
- Dependency management and validation
- Automated workflow capabilities

**Quick Start:**

```bash
/tm:init
/tm:parse-prd
/tm:next
```

## For Contributors

### Adding New Plugins

To add more plugins to this marketplace:

1. **Update marketplace.json**:

   ```json
   {
     "plugins": [
       {
         "name": "new-plugin",
         "source": "./path/to/plugin",
         "description": "Plugin description",
         "version": "1.0.0"
       }
     ]
   }
   ```

2. **Commit and push** the changes

3. **Users update** with: `/plugin marketplace update taskmaster`

### Marketplace Versioning

The marketplace version is tracked in `.claude-plugin/marketplace.json`:

```json
{
  "metadata": {
    "version": "1.0.0"
  }
}
```

Increment the version when adding or updating plugins.

## Team Configuration

Organizations can auto-install this marketplace for all team members by adding to `.claude/settings.json`:

```json
{
  "extraKnownMarketplaces": {
    "task-master": {
      "source": {
        "source": "github",
        "repo": "eyaltoledano/claude-task-master"
      }
    }
  },
  "enabledPlugins": {
    "taskmaster": {
      "marketplace": "taskmaster"
    }
  }
}
```

Team members who trust the repository folder will automatically get the marketplace and plugins installed.

## Documentation

- [Claude Code Plugin Docs](https://docs.claude.com/en/docs/claude-code/plugins)
- [Marketplace Documentation](https://docs.claude.com/en/docs/claude-code/plugin-marketplaces)


## Links discovered
- [Claude Code Plugin Docs](https://docs.claude.com/en/docs/claude-code/plugins)
- [Marketplace Documentation](https://docs.claude.com/en/docs/claude-code/plugin-marketplaces)

--- README-task-master.md ---
# Task Master

### by [@eyaltoledano](https://x.com/eyaltoledano)

A task management system for AI-driven development with Claude, designed to work seamlessly with Cursor AI.

## Requirements

- Node.js 14.0.0 or higher
- Anthropic API key (Claude API)
- Anthropic SDK version 0.39.0 or higher
- OpenAI SDK (for Perplexity API integration, optional)

## Configuration

Taskmaster uses two primary configuration methods:

1.  **`.taskmasterconfig` File (Project Root)**

    - Stores most settings: AI model selections (main, research, fallback), parameters (max tokens, temperature), logging level, default priority/subtasks, project name.
    - **Created and managed using `task-master models --setup` CLI command or the `models` MCP tool.**
    - Do not edit manually unless you know what you are doing.

2.  **Environment Variables (`.env` file or MCP `env` block)**
    - Used **only** for sensitive **API Keys** (e.g., `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY`, etc.) and specific endpoints (like `OLLAMA_BASE_URL`).
    - **For CLI:** Place keys in a `.env` file in your project root.
    - **For MCP/Cursor:** Place keys in the `env` section of your `.cursor/mcp.json` (or other MCP config according to the AI IDE or client you use) file under the `taskmaster-ai` server definition.

**Important:** Settings like model choices, max tokens, temperature, and log level are **no longer configured via environment variables.** Use the `task-master models` command or tool.

See the [Configuration Guide](docs/configuration.md) for full details.

## Installation

```bash
# Install globally
npm install -g task-master-ai

# OR install locally within your project
npm install task-master-ai
```

### Initialize a new project

```bash
# If installed globally
task-master init

# If installed locally
npx task-master init
```

This will prompt you for project details and set up a new project with the necessary files and structure.

### Important Notes

1. **ES Modules Configuration:**

   - This project uses ES Modules (ESM) instead of CommonJS.
   - This is set via `"type": "module"` in your package.json.
   - Use `import/export` syntax instead of `require()`.
   - Files should use `.js` or `.mjs` extensions.
   - To use a CommonJS module, either:
     - Rename it with `.cjs` extension
     - Use `await import()` for dynamic imports
   - If you need CommonJS throughout your project, remove `"type": "module"` from package.json, but Task Master scripts expect ESM.

2. The Anthropic SDK version should be 0.39.0 or higher.

## Quick Start with Global Commands

After installing the package globally, you can use these CLI commands from any directory:

```bash
# Initialize a new project
task-master init

# Parse a PRD and generate tasks
task-master parse-prd your-prd.txt

# List all tasks
task-master list

# Show the next task to work on
task-master next

# Generate task files
task-master generate
```

## Troubleshooting

### If `task-master init` doesn't respond:

Try running it with Node directly:

```bash
node node_modules/claude-task-master/scripts/init.js
```

Or clone the repository and run:

```bash
git clone https://github.com/eyaltoledano/claude-task-master.git
cd claude-task-master
node scripts/init.js
```

## Task Structure

Tasks in tasks.json have the following structure:

- `id`: Unique identifier for the task (Example: `1`)
- `title`: Brief, descriptive title of the task (Example: `"Initialize Repo"`)
- `description`: Concise description of what the task involves (Example: `"Create a new repository, set up initial structure."`)
- `status`: Current state of the task (Example: `"pending"`, `"done"`, `"deferred"`)
- `dependencies`: IDs of tasks that must be completed before this task (Example: `[1, 2]`)
  - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending)
  - This helps quickly identify which prerequisite tasks are blocking work
- `priority`: Importance level of the task (Example: `"high"`, `"medium"`, `"low"`)
- `details`: In-depth implementation instructions (Example: `"Use GitHub client ID/secret, handle callback, set session token."`)
- `testStrategy`: Verification approach (Example: `"Deploy and call endpoint to confirm 'Hello World' response."`)
- `subtasks`: List of smaller, more specific tasks that make up the main task (Example: `[{"id": 1, "title": "Configure OAuth", ...}]`)

## Integrating with Cursor AI

Claude Task Master is designed to work seamlessly with [Cursor AI](https://www.cursor.so/), providing a structured workflow for AI-driven development.

### Setup with Cursor

1. After initializing your project, open it in Cursor
2. The `.cursor/rules/dev_workflow.mdc` file is automatically loaded by Cursor, providing the AI with knowledge about the task management system
3. Place your PRD document in the `scripts/` directory (e.g., `scripts/prd.txt`)
4. Open Cursor's AI chat and switch to Agent mode

### Setting up MCP in Cursor

To enable enhanced task management capabilities directly within Cursor using the Model Control Protocol (MCP):

1. Go to Cursor settings
2. Navigate to the MCP section
3. Click on "Add New MCP Server"
4. Configure with the following details:
   - Name: "Task Master"
   - Type: "Command"
   - Command: "npx -y task-master-ai"
5. Save the settings

Once configured, you can interact with Task Master's task management commands directly through Cursor's interface, providing a more integrated experience.

### Initial Task Generation

In Cursor's AI chat, instruct the agent to generate tasks from your PRD:

```
Please use the task-master parse-prd command to generate tasks from my PRD. The PRD is located at scripts/prd.txt.
```

The agent will execute:

```bash
task-master parse-prd scripts/prd.txt
```

This will:

- Parse your PRD document
- Generate a structured `tasks.json` file with tasks, dependencies, priorities, and test strategies
- The agent will understand this process due to the Cursor rules

### Generate Individual Task Files

Next, ask the agent to generate individual task files:

```
Please generate individual task files from tasks.json
```

The agent will execute:

```bash
task-master generate
```

This creates individual task files in the `tasks/` directory (e.g., `task_001.txt`, `task_002.txt`), making it easier to reference specific tasks.

## AI-Driven Development Workflow

The Cursor agent is pre-configured (via the rules file) to follow this workflow:

### 1. Task Discovery and Selection

Ask the agent to list available tasks:

```
What tasks are available to work on next?
```

The agent will:

- Run `task-master list` to see all tasks
- Run `task-master next` to determine the next task to work on
- Analyze dependencies to determine which tasks are ready to be worked on
- Prioritize tasks based on priority level and ID order
- Suggest the next task(s) to implement

### 2. Task Implementation

When implementing a task, the agent will:

- Reference the task's details section for implementation specifics
- Consider dependencies on previous tasks
- Follow the project's coding standards
- Create appropriate tests based on the task's testStrategy

You can ask:

```
Let's implement task 3. What does it involve?
```

### 3. Task Verification

Before marking a task as complete, verify it according to:

- The task's specified testStrategy
- Any automated tests in the codebase
- Manual verification if required

### 4. Task Completion

When a task is completed, tell the agent:

```
Task 3 is now complete. Please update its status.
```

The agent will execute:

```bash
task-master set-status --id=3 --status=done
```

### 5. Handling Implementation Drift

If during implementation, you discover that:

- The current approach differs significantly from what was planned
- Future tasks need to be modified due to current implementation choices
- New dependencies or requirements have emerged

Tell the agent:

```
We've changed our approach. We're now using Express instead of Fastify. Please update all future tasks to reflect this change.
```

The agent will execute:

```bash
task-master update --from=4 --prompt="Now we are using Express instead of Fastify."
```

This will rewrite or re-scope subsequent tasks in tasks.json while preserving completed work.

### 6. Breaking Down Complex Tasks

For complex tasks that need more granularity:

```
Task 5 seems complex. Can you break it down into subtasks?
```

The agent will execute:

```bash
task-master expand --id=5 --num=3
```

You can provide additional context:

```
Please break down task 5 with a focus on security considerations.
```

The agent will execute:

```bash
task-master expand --id=5 --prompt="Focus on security aspects"
```

You can also expand all pending tasks:

```
Please break down all pending tasks into subtasks.
```

The agent will execute:

```bash
task-master expand --all
```

For research-backed subtask generation using Perplexity AI:

```
Please break down task 5 using research-backed generation.
```

The agent will execute:

```bash
task-master expand --id=5 --research
```

## Command Reference

Here's a comprehensive reference of all available commands:

### Parse PRD

```bash
# Parse a PRD file and generate tasks
task-master parse-prd <prd-file.txt>

# Limit the number of tasks generated (default is 10)
task-master parse-prd <prd-file.txt> --num-tasks=5

# Allow task master to determine the number of tasks based on complexity
task-master parse-prd <prd-file.txt> --num-tasks=0
```

### List Tasks

```bash
# List all tasks
task-master list

# List tasks with a specific status
task-master list --status=<status>

# List tasks with subtasks
task-master list --with-subtasks

# List tasks with a specific status and include subtasks
task-master list --status=<status> --with-subtasks
```

### Show Next Task

```bash
# Show the next task to work on based on dependencies and status
task-master next
```

### Show Specific Task

```bash
# Show details of a specific task
task-master show <id>
# or
task-master show --id=<id>

# View a specific subtask (e.g., subtask 2 of task 1)
task-master show 1.2
```

### Update Tasks

```bash
# Update tasks from a specific ID and provide context
task-master update --from=<id> --prompt="<prompt>"
```

### Generate Task Files

```bash
# Generate individual task files from tasks.json
task-master generate
```

### Set Task Status

```bash
# Set status of a single task
task-master set-status --id=<id> --status=<status>

# Set status for multiple tasks
task-master set-status --id=1,2,3 --status=<status>

# Set status for subtasks
task-master set-status --id=1.1,1.2 --status=<status>
```

When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.

### Expand Tasks

```bash
# Expand a specific task with subtasks
task-master expand --id=<id> --num=<number>

# Expand a task with a dynamic number of subtasks (ignoring complexity report)
task-master expand --id=<id> --num=0

# Expand with additional context
task-master expand --id=<id> --prompt="<context>"

# Expand all pending tasks
task-master expand --all

# Force regeneration of subtasks for tasks that already have them
task-master expand --all --force

# Research-backed subtask generation for a specific task
task-master expand --id=<id> --research

# Research-backed generation for all tasks
task-master expand --all --research
```

### Clear Subtasks

```bash
# Clear subtasks from a specific task
task-master clear-subtasks --id=<id>

# Clear subtasks from multiple tasks
task-master clear-subtasks --id=1,2,3

# Clear subtasks from all tasks
task-master clear-subtasks --all
```

### Analyze Task Complexity

```bash
# Analyze complexity of all tasks
task-master analyze-complexity

# Save report to a custom location
task-master analyze-complexity --output=my-report.json

# Use a specific LLM model
task-master analyze-complexity --model=claude-3-opus-20240229

# Set a custom complexity threshold (1-10)
task-master analyze-complexity --threshold=6

# Use an alternative tasks file
task-master analyze-complexity --file=custom-tasks.json

# Use Perplexity AI for research-backed complexity analysis
task-master analyze-complexity --research
```

### View Complexity Report

```bash
# Display the task complexity analysis report
task-master complexity-report

# View a report at a custom location
task-master complexity-report --file=my-report.json
```

### Managing Task Dependencies

```bash
# Add a dependency to a task
task-master add-dependency --id=<id> --depends-on=<id>

# Remove a dependency from a task
task-master remove-dependency --id=<id> --depends-on=<id>

# Validate dependencies without fixing them
task-master validate-dependencies

# Find and fix invalid dependencies automatically
task-master fix-dependencies
```

### Add a New Task

```bash
# Add a new task using AI
task-master add-task --prompt="Description of the new task"

# Add a task with dependencies
task-master add-task --prompt="Description" --dependencies=1,2,3

# Add a task with priority
task-master add-task --prompt="Description" --priority=high
```

## Feature Details

### Analyzing Task Complexity

The `analyze-complexity` command:

- Analyzes each task using AI to assess its complexity on a scale of 1-10
- Recommends optimal number of subtasks based on configured DEFAULT_SUBTASKS
- Generates tailored prompts for expanding each task
- Creates a comprehensive JSON report with ready-to-use commands
- Saves the report to scripts/task-complexity-report.json by default

The generated report contains:

- Complexity analysis for each task (scored 1-10)
- Recommended number of subtasks based on complexity
- AI-generated expansion prompts customized for each task
- Ready-to-run expansion commands directly within each task analysis

### Viewing Complexity Report

The `complexity-report` command:

- Displays a formatted, easy-to-read version of the complexity analysis report
- Shows tasks organized by complexity score (highest to lowest)
- Provides complexity distribution statistics (low, medium, high)
- Highlights tasks recommended for expansion based on threshold score
- Includes ready-to-use expansion commands for each complex task
- If no report exists, offers to generate one on the spot

### Smart Task Expansion

The `expand` command automatically checks for and uses the complexity report:

When a complexity report exists:

- Tasks are automatically expanded using the recommended subtask count and prompts
- When expanding all tasks, they're processed in order of complexity (highest first)
- Research-backed generation is preserved from the complexity analysis
- You can still override recommendations with explicit command-line options

Example workflow:

```bash
# Generate the complexity analysis report with research capabilities
task-master analyze-complexity --research

# Review the report in a readable format
task-master complexity-report

# Expand tasks using the optimized recommendations
task-master expand --id=8
# or expand all tasks
task-master expand --all
```

### Finding the Next Task

The `next` command:

- Identifies tasks that are pending/in-progress and have all dependencies satisfied
- Prioritizes tasks by priority level, dependency count, and task ID
- Displays comprehensive information about the selected task:
  - Basic task details (ID, title, priority, dependencies)
  - Implementation details
  - Subtasks (if they exist)
- Provides contextual suggested actions:
  - Command to mark the task as in-progress
  - Command to mark the task as done
  - Commands for working with subtasks

### Viewing Specific Task Details

The `show` command:

- Displays comprehensive details about a specific task or subtask
- Shows task status, priority, dependencies, and detailed implementation notes
- For parent tasks, displays all subtasks and their status
- For subtasks, shows parent task relationship
- Provides contextual action suggestions based on the task's state
- Works with both regular tasks and subtasks (using the format taskId.subtaskId)

## Best Practices for AI-Driven Development

1. **Start with a detailed PRD**: The more detailed your PRD, the better the generated tasks will be.

2. **Review generated tasks**: After parsing the PRD, review the tasks to ensure they make sense and have appropriate dependencies.

3. **Analyze task complexity**: Use the complexity analysis feature to identify which tasks should be broken down further.

4. **Follow the dependency chain**: Always respect task dependencies - the Cursor agent will help with this.

5. **Update as you go**: If your implementation diverges from the plan, use the update command to keep future tasks aligned with your current approach.

6. **Break down complex tasks**: Use the expand command to break down complex tasks into manageable subtasks.

7. **Regenerate task files**: After any updates to tasks.json, regenerate the task files to keep them in sync.

8. **Communicate context to the agent**: When asking the Cursor agent to help with a task, provide context about what you're trying to achieve.

9. **Validate dependencies**: Periodically run the validate-dependencies command to check for invalid or circular dependencies.

## Example Cursor AI Interactions

### Starting a new project

```
I've just initialized a new project with Claude Task Master. I have a PRD at scripts/prd.txt.
Can you help me parse it and set up the initial tasks?
```

### Working on tasks

```
What's the next task I should work on? Please consider dependencies and priorities.
```

### Implementing a specific task

```
I'd like to implement task 4. Can you help me understand what needs to be done and how to approach it?
```

### Managing subtasks

```
I need to regenerate the subtasks for task 3 with a different approach. Can you help me clear and regenerate them?
```

### Handling changes

```
We've decided to use MongoDB instead of PostgreSQL. Can you update all future tasks to reflect this change?
```

### Completing work

```
I've finished implementing the authentication system described in task 2. All tests are passing.
Please mark it as complete and tell me what I should work on next.
```

### Analyzing complexity

```
Can you analyze the complexity of our tasks to help me understand which ones need to be broken down further?
```

### Viewing complexity report

```
Can you show me the complexity report in a more readable format?
```


## Links discovered
- [@eyaltoledano](https://x.com/eyaltoledano)
- [Configuration Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/configuration.md)
- [Cursor AI](https://www.cursor.so/)

--- README.md ---
<a name="readme-top"></a>

<div align='center'>
<a href="https://trendshift.io/repositories/13971" target="_blank"><img src="https://trendshift.io/api/badge/repositories/13971" alt="eyaltoledano%2Fclaude-task-master | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</div>

<p align="center">
  <a href="https://task-master.dev"><img src="./images/logo.png?raw=true" alt="Taskmaster logo"></a>
</p>

<p align="center">
<b>Taskmaster</b>: A task management system for AI-driven development, designed to work seamlessly with any AI chat.
</p>

<p align="center">
  <a href="https://discord.gg/taskmasterai" target="_blank"><img src="https://dcbadge.limes.pink/api/server/https://discord.gg/taskmasterai?style=flat" alt="Discord"></a> |
  <a href="https://docs.task-master.dev" target="_blank">Docs</a>
</p>

<p align="center">
  <a href="https://github.com/eyaltoledano/claude-task-master/actions/workflows/ci.yml"><img src="https://github.com/eyaltoledano/claude-task-master/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
  <a href="https://github.com/eyaltoledano/claude-task-master/stargazers"><img src="https://img.shields.io/github/stars/eyaltoledano/claude-task-master?style=social" alt="GitHub stars"></a>
  <a href="https://badge.fury.io/js/task-master-ai"><img src="https://badge.fury.io/js/task-master-ai.svg" alt="npm version"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT%20with%20Commons%20Clause-blue.svg" alt="License"></a>
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/task-master-ai"><img src="https://img.shields.io/npm/d18m/task-master-ai?style=flat" alt="NPM Downloads"></a>
  <a href="https://www.npmjs.com/package/task-master-ai"><img src="https://img.shields.io/npm/dm/task-master-ai?style=flat" alt="NPM Downloads"></a>
  <a href="https://www.npmjs.com/package/task-master-ai"><img src="https://img.shields.io/npm/dw/task-master-ai?style=flat" alt="NPM Downloads"></a>
</p>

## By [@eyaltoledano](https://x.com/eyaltoledano) & [@RalphEcom](https://x.com/RalphEcom)

[![Twitter Follow](https://img.shields.io/twitter/follow/eyaltoledano)](https://x.com/eyaltoledano)
[![Twitter Follow](https://img.shields.io/twitter/follow/RalphEcom)](https://x.com/RalphEcom)

A task management system for AI-driven development with Claude, designed to work seamlessly with Cursor AI.

## Documentation

📚 **[View Full Documentation](https://docs.task-master.dev)**

For detailed guides, API references, and comprehensive examples, visit our documentation site.

### Quick Reference

The following documentation is also available in the `docs` directory:

- [Configuration Guide](docs/configuration.md) - Set up environment variables and customize Task Master
- [Tutorial](docs/tutorial.md) - Step-by-step guide to getting started with Task Master
- [Command Reference](docs/command-reference.md) - Complete list of all available commands
- [Task Structure](docs/task-structure.md) - Understanding the task format and features
- [Example Interactions](docs/examples.md) - Common Cursor AI interaction examples
- [Migration Guide](docs/migration-guide.md) - Guide to migrating to the new project structure

#### Quick Install for Cursor 1.0+ (One-Click)

[![Add task-master-ai MCP server to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=task-master-ai&config=eyJjb21tYW5kIjoibnB4IC15IC0tcGFja2FnZT10YXNrLW1hc3Rlci1haSB0YXNrLW1hc3Rlci1haSIsImVudiI6eyJBTlRIUk9QSUNfQVBJX0tFWSI6IllPVVJfQU5USFJPUElDX0FQSV9LRVlfSEVSRSIsIlBFUlBMRVhJVFlfQVBJX0tFWSI6IllPVVJfUEVSUExFWElUWV9BUElfS0VZX0hFUkUiLCJPUEVOQUlfQVBJX0tFWSI6IllPVVJfT1BFTkFJX0tFWV9IRVJFIiwiR09PR0xFX0FQSV9LRVkiOiJZT1VSX0dPT0dMRV9LRVlfSEVSRSIsIk1JU1RSQUxfQVBJX0tFWSI6IllPVVJfTUlTVFJBTF9LRVlfSEVSRSIsIkdST1FfQVBJX0tFWSI6IllPVVJfR1JPUV9LRVlfSEVSRSIsIk9QRU5ST1VURVJfQVBJX0tFWSI6IllPVVJfT1BFTlJPVVRFUl9LRVlfSEVSRSIsIlhBSV9BUElfS0VZIjoiWU9VUl9YQUlfS0VZX0hFUkUiLCJBWlVSRV9PUEVOQUlfQVBJX0tFWSI6IllPVVJfQVpVUkVfS0VZX0hFUkUiLCJPTExBTUFfQVBJX0tFWSI6IllPVVJfT0xMQU1BX0FQSV9LRVlfSEVSRSJ9fQ%3D%3D)

> **Note:** After clicking the link, you'll still need to add your API keys to the configuration. The link installs the MCP server with placeholder keys that you'll need to replace with your actual API keys.

#### Claude Code Quick Install

For Claude Code users:

```bash
claude mcp add taskmaster-ai -- npx -y task-master-ai
```

Don't forget to add your API keys to the configuration:
- in the root .env of your Project
- in the "env" section of your mcp config for taskmaster-ai


## Requirements

Taskmaster utilizes AI across several commands, and those require a separate API key. You can use a variety of models from different AI providers provided you add your API keys. For example, if you want to use Claude 3.7, you'll need an Anthropic API key.

You can define 3 types of models to be used: the main model, the research model, and the fallback model (in case either the main or research fail). Whatever model you use, its provider API key must be present in either mcp.json or .env.

At least one (1) of the following is required:

- Anthropic API key (Claude API)
- OpenAI API key
- Google Gemini API key
- Perplexity API key (for research model)
- xAI API Key (for research or main model)
- OpenRouter API Key (for research or main model)
- Claude Code (no API key required - requires Claude Code CLI)
- Codex CLI (OAuth via ChatGPT subscription - requires Codex CLI)

Using the research model is optional but highly recommended. You will need at least ONE API key (unless using Claude Code or Codex CLI with OAuth). Adding all API keys enables you to seamlessly switch between model providers at will.

## Quick Start

### Option 1: MCP (Recommended)

MCP (Model Control Protocol) lets you run Task Master directly from your editor.

#### 1. Add your MCP config at the following path depending on your editor

| Editor       | Scope   | Linux/macOS Path                      | Windows Path                                      | Key          |
| ------------ | ------- | ------------------------------------- | ------------------------------------------------- | ------------ |
| **Cursor**   | Global  | `~/.cursor/mcp.json`                  | `%USERPROFILE%\.cursor\mcp.json`                  | `mcpServers` |
|              | Project | `<project_folder>/.cursor/mcp.json`   | `<project_folder>\.cursor\mcp.json`               | `mcpServers` |
| **Windsurf** | Global  | `~/.codeium/windsurf/mcp_config.json` | `%USERPROFILE%\.codeium\windsurf\mcp_config.json` | `mcpServers` |
| **VS Code**  | Project | `<project_folder>/.vscode/mcp.json`   | `<project_folder>\.vscode\mcp.json`               | `servers`    |
| **Q CLI**    | Global  | `~/.aws/amazonq/mcp.json`             |                                                   | `mcpServers` |

##### Manual Configuration

###### Cursor & Windsurf & Q Developer CLI (`mcpServers`)

```json
{
  "mcpServers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        // "TASK_MASTER_TOOLS": "all", // Options: "all", "standard", "core", or comma-separated list of tools
        "ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
        "PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
        "OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
        "GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
        "MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
        "GROQ_API_KEY": "YOUR_GROQ_KEY_HERE",
        "OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
        "XAI_API_KEY": "YOUR_XAI_KEY_HERE",
        "AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE",
        "OLLAMA_API_KEY": "YOUR_OLLAMA_API_KEY_HERE"
      }
    }
  }
}
```

> 🔑 Replace `YOUR_…_KEY_HERE` with your real API keys. You can remove keys you don't use.

> **Note**: If you see `0 tools enabled` in the MCP settings, restart your editor and check that your API keys are correctly configured.

###### VS Code (`servers` + `type`)

```json
{
  "servers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        // "TASK_MASTER_TOOLS": "all", // Options: "all", "standard", "core", or comma-separated list of tools
        "ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
        "PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
        "OPENAI_API_KEY": "YOUR_OPENAI_KEY_HERE",
        "GOOGLE_API_KEY": "YOUR_GOOGLE_KEY_HERE",
        "MISTRAL_API_KEY": "YOUR_MISTRAL_KEY_HERE",
        "GROQ_API_KEY": "YOUR_GROQ_KEY_HERE",
        "OPENROUTER_API_KEY": "YOUR_OPENROUTER_KEY_HERE",
        "XAI_API_KEY": "YOUR_XAI_KEY_HERE",
        "AZURE_OPENAI_API_KEY": "YOUR_AZURE_KEY_HERE",
        "OLLAMA_API_KEY": "YOUR_OLLAMA_API_KEY_HERE"
      },
      "type": "stdio"
    }
  }
}
```

> 🔑 Replace `YOUR_…_KEY_HERE` with your real API keys. You can remove keys you don't use.

#### 2. (Cursor-only) Enable Taskmaster MCP

Open Cursor Settings (Ctrl+Shift+J) ➡ Click on MCP tab on the left ➡ Enable task-master-ai with the toggle

#### 3. (Optional) Configure the models you want to use

In your editor's AI chat pane, say:

```txt
Change the main, research and fallback models to <model_name>, <model_name> and <model_name> respectively.
```

For example, to use Claude Code (no API key required):
```txt
Change the main model to claude-code/sonnet
```

[Table of available models](docs/models.md) | [Claude Code setup](docs/examples/claude-code-usage.md)

#### 4. Initialize Task Master

In your editor's AI chat pane, say:

```txt
Initialize taskmaster-ai in my project
```

#### 5. Make sure you have a PRD (Recommended)

For **new projects**: Create your PRD at `.taskmaster/docs/prd.txt`.
For **existing projects**: You can use `scripts/prd.txt` or migrate with `task-master migrate`

An example PRD template is available after initialization in `.taskmaster/templates/example_prd.txt`.

> [!NOTE]
> While a PRD is recommended for complex projects, you can always create individual tasks by asking "Can you help me implement [description of what you want to do]?" in chat.

**Always start with a detailed PRD.**

The more detailed your PRD, the better the generated tasks will be.

#### 6. Common Commands

Use your AI assistant to:

- Parse requirements: `Can you parse my PRD at scripts/prd.txt?`
- Plan next step: `What's the next task I should work on?`
- Implement a task: `Can you help me implement task 3?`
- View multiple tasks: `Can you show me tasks 1, 3, and 5?`
- Expand a task: `Can you help me expand task 4?`
- **Research fresh information**: `Research the latest best practices for implementing JWT authentication with Node.js`
- **Research with context**: `Research React Query v5 migration strategies for our current API implementation in src/api.js`

[More examples on how to use Task Master in chat](docs/examples.md)

### Option 2: Using Command Line

#### Installation

```bash
# Install globally
npm install -g task-master-ai

# OR install locally within your project
npm install task-master-ai
```

#### Initialize a new project

```bash
# If installed globally
task-master init

# If installed locally
npx task-master init

# Initialize project with specific rules
task-master init --rules cursor,windsurf,vscode
```

This will prompt you for project details and set up a new project with the necessary files and structure.

#### Common Commands

```bash
# Initialize a new project
task-master init

# Parse a PRD and generate tasks
task-master parse-prd your-prd.txt

# List all tasks
task-master list

# Show the next task to work on
task-master next

# Show specific task(s) - supports comma-separated IDs
task-master show 1,3,5

# Research fresh information with project context
task-master research "What are the latest best practices for JWT authentication?"

# Move tasks between tags (cross-tag movement)
task-master move --from=5 --from-tag=backlog --to-tag=in-progress
task-master move --from=5,6,7 --from-tag=backlog --to-tag=done --with-dependencies
task-master move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies

# Add rules after initialization
task-master rules add windsurf,roo,vscode
```

## Tool Loading Configuration

### Optimizing MCP Tool Loading

Task Master's MCP server supports selective tool loading to reduce context window usage. By default, all 36 tools are loaded (~21,000 tokens) to maintain backward compatibility with existing installations.

You can optimize performance by configuring the `TASK_MASTER_TOOLS` environment variable:

### Available Modes

| Mode | Tools | Context Usage | Use Case |
|------|-------|--------------|----------|
| `all` (default) | 36 | ~21,000 tokens | Complete feature set - all tools available |
| `standard` | 15 | ~10,000 tokens | Common task management operations |
| `core` (or `lean`) | 7 | ~5,000 tokens | Essential daily development workflow |
| `custom` | Variable | Variable | Comma-separated list of specific tools |

### Configuration Methods

#### Method 1: Environment Variable in MCP Configuration

Add `TASK_MASTER_TOOLS` to your MCP configuration file's `env` section:

```jsonc
{
  "mcpServers": {  // or "servers" for VS Code
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        "TASK_MASTER_TOOLS": "standard",  // Options: "all", "standard", "core", "lean", or comma-separated list
        "ANTHROPIC_API_KEY": "your-key-here",
        // ... other API keys
      }
    }
  }
}
```

#### Method 2: Claude Code CLI (One-Time Setup)

For Claude Code users, you can set the mode during installation:

```bash
# Core mode example (~70% token reduction)
claude mcp add task-master-ai --scope user \
  --env TASK_MASTER_TOOLS="core" \
  -- npx -y task-master-ai@latest

# Custom tools example
claude mcp add task-master-ai --scope user \
  --env TASK_MASTER_TOOLS="get_tasks,next_task,set_task_status" \
  -- npx -y task-master-ai@latest
```

### Tool Sets Details

**Core Tools (7):** `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task`

**Standard Tools (15):** All core tools plus `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `generate`, `add_task`, `complexity_report`

**All Tools (36):** Complete set including project setup, task management, analysis, dependencies, tags, research, and more

### Recommendations

- **New users**: Start with `"standard"` mode for a good balance
- **Large projects**: Use `"core"` mode to minimize token usage
- **Complex workflows**: Use `"all"` mode or custom selection
- **Backward compatibility**: If not specified, defaults to `"all"` mode

## Claude Code Support

Task Master now supports Claude models through the Claude Code CLI, which requires no API key:

- **Models**: `claude-code/opus` and `claude-code/sonnet`
- **Requirements**: Claude Code CLI installed
- **Benefits**: No API key needed, uses your local Claude instance

[Learn more about Claude Code setup](docs/examples/claude-code-usage.md)

## Troubleshooting

### If `task-master init` doesn't respond

Try running it with Node directly:

```bash
node node_modules/claude-task-master/scripts/init.js
```

Or clone the repository and run:

```bash
git clone https://github.com/eyaltoledano/claude-task-master.git
cd claude-task-master
node scripts/init.js
```

## Join Our Team

<a href="https://tryhamster.com" target="_blank">
  <img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" />
</a>

## Contributors

<a href="https://github.com/eyaltoledano/claude-task-master/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=eyaltoledano/claude-task-master" alt="Task Master project contributors" />
</a>

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=eyaltoledano/claude-task-master&type=Timeline)](https://www.star-history.com/#eyaltoledano/claude-task-master&Timeline)

## Licensing

Task Master is licensed under the MIT License with Commons Clause. This means you can:

✅ **Allowed**:

- Use Task Master for any purpose (personal, commercial, academic)
- Modify the code
- Distribute copies
- Create and sell products built using Task Master

❌ **Not Allowed**:

- Sell Task Master itself
- Offer Task Master as a hosted service
- Create competing products based on Task Master

See the [LICENSE](LICENSE) file for the complete license text and [licensing details](docs/licensing.md) for more information.


## Links discovered
- [@eyaltoledano](https://x.com/eyaltoledano)
- [@RalphEcom](https://x.com/RalphEcom)
- [![Twitter Follow](https://img.shields.io/twitter/follow/eyaltoledano)
- [![Twitter Follow](https://img.shields.io/twitter/follow/RalphEcom)
- [View Full Documentation](https://docs.task-master.dev)
- [Configuration Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/configuration.md)
- [Tutorial](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/tutorial.md)
- [Command Reference](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/command-reference.md)
- [Task Structure](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/task-structure.md)
- [Example Interactions](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/examples.md)
- [Migration Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/migration-guide.md)
- [![Add task-master-ai MCP server to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)
- [Table of available models](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/models.md)
- [Claude Code setup](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/examples/claude-code-usage.md)
- [More examples on how to use Task Master in chat](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/examples.md)
- [Learn more about Claude Code setup](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/examples/claude-code-usage.md)
- [![Star History Chart](https://api.star-history.com/svg?repos=eyaltoledano/claude-task-master&type=Timeline)
- [LICENSE](https://github.com/eyaltoledano/claude-task-master/blob/main/LICENSE.md)
- [licensing details](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/licensing.md)
- [<img src="https://trendshift.io/api/badge/repositories/13971" alt="eyaltoledano%2Fclaude-task-master | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>](https://trendshift.io/repositories/13971)
- [<img src="./images/logo.png?raw=true" alt="Taskmaster logo">](https://task-master.dev)
- [<img src="https://dcbadge.limes.pink/api/server/https://discord.gg/taskmasterai?style=flat" alt="Discord">](https://discord.gg/taskmasterai)
- [Docs](https://docs.task-master.dev)
- [<img src="https://github.com/eyaltoledano/claude-task-master/actions/workflows/ci.yml/badge.svg" alt="CI">](https://github.com/eyaltoledano/claude-task-master/actions/workflows/ci.yml)
- [<img src="https://img.shields.io/github/stars/eyaltoledano/claude-task-master?style=social" alt="GitHub stars">](https://github.com/eyaltoledano/claude-task-master/stargazers)
- [<img src="https://badge.fury.io/js/task-master-ai.svg" alt="npm version">](https://badge.fury.io/js/task-master-ai)
- [<img src="https://img.shields.io/badge/license-MIT%20with%20Commons%20Clause-blue.svg" alt="License">](https://github.com/eyaltoledano/claude-task-master/blob/main/LICENSE.md)
- [<img src="https://img.shields.io/npm/d18m/task-master-ai?style=flat" alt="NPM Downloads">](https://www.npmjs.com/package/task-master-ai)
- [<img src="https://img.shields.io/npm/dm/task-master-ai?style=flat" alt="NPM Downloads">](https://www.npmjs.com/package/task-master-ai)
- [<img src="https://img.shields.io/npm/dw/task-master-ai?style=flat" alt="NPM Downloads">](https://www.npmjs.com/package/task-master-ai)
- [<img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" />](https://tryhamster.com)
- [<img src="https://contrib.rocks/image?repo=eyaltoledano/claude-task-master" alt="Task Master project contributors" />](https://github.com/eyaltoledano/claude-task-master/graphs/contributors)

--- bin/task-master.js ---
#!/usr/bin/env node

/**
 * Task Master
 * Copyright (c) 2025 Eyal Toledano, Ralph Khreish
 *
 * This software is licensed under the MIT License with Commons Clause.
 * You may use this software for any purpose, including commercial applications,
 * and modify and redistribute it freely, subject to the following restrictions:
 *
 * 1. You may not sell this software or offer it as a service.
 * 2. The origin of this software must not be misrepresented.
 * 3. Altered source versions must be plainly marked as such.
 *
 * For the full license text, see the LICENSE file in the root directory.
 */

/**
 * Claude Task Master CLI
 * Main entry point for globally installed package
 */

// Direct imports instead of spawning child processes
import { runCLI } from '../scripts/modules/commands.js';

// Simply run the CLI directly
runCLI();


--- index.js ---
#!/usr/bin/env node

/**
 * Task Master
 * Copyright (c) 2025 Eyal Toledano, Ralph Khreish
 *
 * This software is licensed under the MIT License with Commons Clause.
 * You may use this software for any purpose, including commercial applications,
 * and modify and redistribute it freely, subject to the following restrictions:
 *
 * 1. You may not sell this software or offer it as a service.
 * 2. The origin of this software must not be misrepresented.
 * 3. Altered source versions must be plainly marked as such.
 *
 * For the full license text, see the LICENSE file in the root directory.
 */

/**
 * Claude Task Master
 * A task management system for AI-driven development with Claude
 */

// This file serves as the main entry point for the package
// The primary functionality is provided through the CLI commands

import { spawn } from 'child_process';
import { createRequire } from 'module';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { Command } from 'commander';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const require = createRequire(import.meta.url);

// Get package information
const packageJson = require('./package.json');

// Export the path to the dev.js script for programmatic usage
export const devScriptPath = resolve(__dirname, './scripts/dev.js');

// Export a function to initialize a new project programmatically
export const initProject = async (options = {}) => {
	const init = await import('./scripts/init.js');
	return init.initializeProject(options);
};

// Export a function to run init as a CLI command
export const runInitCLI = async (options = {}) => {
	try {
		const init = await import('./scripts/init.js');
		const result = await init.initializeProject(options);
		return result;
	} catch (error) {
		console.error('Initialization failed:', error.message);
		if (process.env.DEBUG === 'true') {
			console.error('Debug stack trace:', error.stack);
		}
		throw error; // Re-throw to be handled by the command handler
	}
};

// Export version information
export const version = packageJson.version;

// CLI implementation
if (import.meta.url === `file://${process.argv[1]}`) {
	const program = new Command();

	program
		.name('task-master')
		.description('Claude Task Master CLI')
		.version(version);

	program
		.command('init')
		.description('Initialize a new project')
		.option('-y, --yes', 'Skip prompts and use default values')
		.option('-n, --name <n>', 'Project name')
		.option('-d, --description <description>', 'Project description')
		.option('-v, --version <version>', 'Project version', '0.1.0')
		.option('-a, --author <author>', 'Author name')
		.option('--skip-install', 'Skip installing dependencies')
		.option('--dry-run', 'Show what would be done without making changes')
		.option('--aliases', 'Add shell aliases (tm, taskmaster, hamster, ham)')
		.option('--no-aliases', 'Skip shell aliases (tm, taskmaster, hamster, ham)')
		.option('--git', 'Initialize Git repository')
		.option('--no-git', 'Skip Git repository initialization')
		.option('--git-tasks', 'Store tasks in Git')
		.option('--no-git-tasks', 'No Git storage of tasks')
		.action(async (cmdOptions) => {
			try {
				await runInitCLI(cmdOptions);
			} catch (err) {
				console.error('Init failed:', err.message);
				process.exit(1);
			}
		});

	program
		.command('dev')
		.description('Run the dev.js script')
		.allowUnknownOption(true)
		.action(() => {
			const args = process.argv.slice(process.argv.indexOf('dev') + 1);
			const child = spawn('node', [devScriptPath, ...args], {
				stdio: 'inherit',
				cwd: process.cwd()
			});

			child.on('close', (code) => {
				process.exit(code);
			});
		});

	// Add shortcuts for common dev.js commands
	program
		.command('list')
		.description('List all tasks')
		.action(() => {
			const child = spawn('node', [devScriptPath, 'list'], {
				stdio: 'inherit',
				cwd: process.cwd()
			});

			child.on('close', (code) => {
				process.exit(code);
			});
		});

	program
		.command('next')
		.description('Show the next task to work on')
		.action(() => {
			const child = spawn('node', [devScriptPath, 'next'], {
				stdio: 'inherit',
				cwd: process.cwd()
			});

			child.on('close', (code) => {
				process.exit(code);
			});
		});

	program
		.command('generate')
		.description('Generate task files')
		.action(() => {
			const child = spawn('node', [devScriptPath, 'generate'], {
				stdio: 'inherit',
				cwd: process.cwd()
			});

			child.on('close', (code) => {
				process.exit(code);
			});
		});

	program.parse(process.argv);
}


--- jest.config.js ---
export default {
	// Use Node.js environment for testing
	testEnvironment: 'node',

	// Automatically clear mock calls between every test
	clearMocks: true,

	// Indicates whether the coverage information should be collected while executing the test
	collectCoverage: false,

	// The directory where Jest should output its coverage files
	coverageDirectory: 'coverage',

	// A list of paths to directories that Jest should use to search for files in
	roots: ['<rootDir>/tests'],

	// The glob patterns Jest uses to detect test files
	testMatch: ['**/__tests__/**/*.js', '**/?(*.)+(spec|test).js'],

	// Transform files
	preset: 'ts-jest/presets/default-esm',
	extensionsToTreatAsEsm: ['.ts'],
	moduleFileExtensions: ['js', 'ts', 'json', 'node'],
	transform: {
		'^.+\\.ts$': [
			'ts-jest',
			{
				useESM: true
			}
		]
	},

	// Disable transformations for node_modules
	transformIgnorePatterns: ['/node_modules/'],

	// Set moduleNameMapper for absolute paths
	moduleNameMapper: {
		'^@/(.*)$': '<rootDir>/$1'
	},
	resolver: '<rootDir>/jest.resolver.cjs',

	// Setup module aliases
	moduleDirectories: ['node_modules', '<rootDir>'],

	// Configure test coverage thresholds
	// Note: ts-jest reports coverage against .ts files, not .js
	coverageThreshold: {
		global: {
			branches: 80,
			functions: 80,
			lines: 80,
			statements: 80
		},
		// Critical code requires higher coverage
		'./src/utils/**/*.ts': {
			branches: 70,
			functions: 90,
			lines: 90,
			statements: 90
		},
		'./src/middleware/**/*.ts': {
			branches: 70,
			functions: 85,
			lines: 85,
			statements: 85
		}
	},

	// Generate coverage report in these formats
	coverageReporters: ['text', 'lcov'],

	// Verbose output
	verbose: true,

	// Setup file
	setupFilesAfterEnv: ['<rootDir>/tests/setup.js']
};


--- mcp-test.js ---
#!/usr/bin/env node

import fs from 'fs';
import path from 'path';
import { Config } from 'fastmcp';

// Log the current directory
console.error(`Current working directory: ${process.cwd()}`);

try {
	console.error('Attempting to load FastMCP Config...');

	// Check if .cursor/mcp.json exists
	const mcpPath = path.join(process.cwd(), '.cursor', 'mcp.json');
	console.error(`Checking if mcp.json exists at: ${mcpPath}`);

	if (fs.existsSync(mcpPath)) {
		console.error('mcp.json file found');
		console.error(
			`File content: ${JSON.stringify(JSON.parse(fs.readFileSync(mcpPath, 'utf8')), null, 2)}`
		);
	} else {
		console.error('mcp.json file not found');
	}

	// Try to create Config
	const config = new Config();
	console.error('Config created successfully');

	// Check if env property exists
	if (config.env) {
		console.error(
			`Config.env exists with keys: ${Object.keys(config.env).join(', ')}`
		);

		// Print each env var value (careful with sensitive values)
		for (const [key, value] of Object.entries(config.env)) {
			if (key.includes('KEY')) {
				console.error(`${key}: [value hidden]`);
			} else {
				console.error(`${key}: ${value}`);
			}
		}
	} else {
		console.error('Config.env does not exist');
	}
} catch (error) {
	console.error(`Error loading Config: ${error.message}`);
	console.error(`Stack trace: ${error.stack}`);
}

// Log process.env to see if values from mcp.json were loaded automatically
console.error('\nChecking if process.env already has values from mcp.json:');
const envVars = [
	'ANTHROPIC_API_KEY',
	'PERPLEXITY_API_KEY',
	'MODEL',
	'PERPLEXITY_MODEL',
	'MAX_TOKENS',
	'TEMPERATURE',
	'DEFAULT_SUBTASKS',
	'DEFAULT_PRIORITY'
];

for (const varName of envVars) {
	if (process.env[varName]) {
		if (varName.includes('KEY')) {
			console.error(`${varName}: [value hidden]`);
		} else {
			console.error(`${varName}: ${process.env[varName]}`);
		}
	} else {
		console.error(`${varName}: not set`);
	}
}


--- test-clean-tags.js ---
import fs from 'fs';
import {
	createTag,
	listTags
} from './scripts/modules/task-manager/tag-management.js';

console.log('=== Testing Tag Management with Clean File ===');

// Create a clean test tasks.json file
const testTasksPath = './test-tasks.json';
const cleanData = {
	master: {
		tasks: [
			{ id: 1, title: 'Test Task 1', status: 'pending' },
			{ id: 2, title: 'Test Task 2', status: 'done' }
		],
		metadata: {
			created: new Date().toISOString(),
			description: 'Master tag'
		}
	}
};

// Write clean test file
fs.writeFileSync(testTasksPath, JSON.stringify(cleanData, null, 2));
console.log('Created clean test file');

try {
	// Test creating a new tag
	console.log('\n--- Testing createTag ---');
	await createTag(
		testTasksPath,
		'test-branch',
		{ copyFromCurrent: true, description: 'Test branch' },
		{ projectRoot: process.cwd() },
		'json'
	);

	// Read the file and check for corruption
	const resultData = JSON.parse(fs.readFileSync(testTasksPath, 'utf8'));
	console.log('Keys in result file:', Object.keys(resultData));
	console.log('Has _rawTaggedData in file:', !!resultData._rawTaggedData);

	if (resultData._rawTaggedData) {
		console.log('❌ CORRUPTION DETECTED: _rawTaggedData found in file!');
	} else {
		console.log('✅ SUCCESS: No _rawTaggedData corruption in file');
	}

	// Test listing tags
	console.log('\n--- Testing listTags ---');
	const tagList = await listTags(
		testTasksPath,
		{},
		{ projectRoot: process.cwd() },
		'json'
	);
	console.log(
		'Found tags:',
		tagList.tags.map((t) => t.name)
	);
} catch (error) {
	console.error('Error during test:', error.message);
} finally {
	// Clean up test file
	if (fs.existsSync(testTasksPath)) {
		fs.unlinkSync(testTasksPath);
		console.log('\nCleaned up test file');
	}
}


--- test-config-manager.js ---
// test-config-manager.js
console.log('=== ENVIRONMENT TEST ===');
console.log('Working directory:', process.cwd());
console.log('NODE_PATH:', process.env.NODE_PATH);

// Test basic imports
try {
	console.log('Importing config-manager');
	// Use dynamic import for ESM
	const configManagerModule = await import(
		'./scripts/modules/config-manager.js'
	);
	const configManager = configManagerModule.default || configManagerModule;
	console.log('Config manager loaded successfully');

	console.log('Loading supported models');
	// Add after line 14 (after "Config manager loaded successfully")
	console.log('Config manager exports:', Object.keys(configManager));
} catch (error) {
	console.error('Import error:', error.message);
	console.error(error.stack);
}

// Test file access
try {
	console.log('Checking for .taskmasterconfig');
	// Use dynamic import for ESM
	const { readFileSync, existsSync } = await import('fs');
	const { resolve } = await import('path');

	const configExists = existsSync('./.taskmasterconfig');
	console.log('.taskmasterconfig exists:', configExists);

	if (configExists) {
		const config = JSON.parse(readFileSync('./.taskmasterconfig', 'utf-8'));
		console.log('Config keys:', Object.keys(config));
	}

	console.log('Checking for supported-models.json');
	const modelsPath = resolve('./scripts/modules/supported-models.json');
	console.log('Models path:', modelsPath);
	const modelsExists = existsSync(modelsPath);
	console.log('supported-models.json exists:', modelsExists);
} catch (error) {
	console.error('File access error:', error.message);
}

console.log('=== TEST COMPLETE ===');


--- test-prd.txt ---
# Test PRD

## Project Overview
This is a simple test project to verify parse-prd functionality.

## Features
- Feature A: Basic setup
- Feature B: Core functionality  
- Feature C: Testing

## Requirements
- Use Node.js
- Include basic tests
- Simple CLI interface 

--- test-tag-functions.js ---


--- test-version-check-full.js ---
import fs from 'fs';
import path from 'path';
import {
	checkForUpdate,
	compareVersions,
	displayUpgradeNotification
} from './scripts/modules/commands.js';

// Force our current version for testing
process.env.FORCE_VERSION = '0.9.30';

// Create a mock package.json in memory for testing
const mockPackageJson = {
	name: 'task-master-ai',
	version: '0.9.30'
};

// Modified version of checkForUpdate that doesn't use HTTP for testing
async function testCheckForUpdate(simulatedLatestVersion) {
	// Get current version - use our forced version
	const currentVersion = process.env.FORCE_VERSION || '0.9.30';

	console.log(`Using simulated current version: ${currentVersion}`);
	console.log(`Using simulated latest version: ${simulatedLatestVersion}`);

	// Compare versions
	const needsUpdate =
		compareVersions(currentVersion, simulatedLatestVersion) < 0;

	return {
		currentVersion,
		latestVersion: simulatedLatestVersion,
		needsUpdate
	};
}

// Test with current version older than latest (should show update notice)
async function runTest() {
	console.log('=== Testing version check scenarios ===\n');

	// Scenario 1: Update available
	console.log(
		'\n--- Scenario 1: Update available (Current: 0.9.30, Latest: 1.0.0) ---'
	);
	const updateInfo1 = await testCheckForUpdate('1.0.0');
	console.log('Update check results:');
	console.log(`- Current version: ${updateInfo1.currentVersion}`);
	console.log(`- Latest version: ${updateInfo1.latestVersion}`);
	console.log(`- Update needed: ${updateInfo1.needsUpdate}`);

	if (updateInfo1.needsUpdate) {
		console.log('\nDisplaying upgrade notification:');
		displayUpgradeNotification(
			updateInfo1.currentVersion,
			updateInfo1.latestVersion
		);
	}

	// Scenario 2: No update needed (versions equal)
	console.log(
		'\n--- Scenario 2: No update needed (Current: 0.9.30, Latest: 0.9.30) ---'
	);
	const updateInfo2 = await testCheckForUpdate('0.9.30');
	console.log('Update check results:');
	console.log(`- Current version: ${updateInfo2.currentVersion}`);
	console.log(`- Latest version: ${updateInfo2.latestVersion}`);
	console.log(`- Update needed: ${updateInfo2.needsUpdate}`);

	// Scenario 3: Development version (current newer than latest)
	console.log(
		'\n--- Scenario 3: Development version (Current: 0.9.30, Latest: 0.9.0) ---'
	);
	const updateInfo3 = await testCheckForUpdate('0.9.0');
	console.log('Update check results:');
	console.log(`- Current version: ${updateInfo3.currentVersion}`);
	console.log(`- Latest version: ${updateInfo3.latestVersion}`);
	console.log(`- Update needed: ${updateInfo3.needsUpdate}`);

	console.log('\n=== Test complete ===');
}

// Run all tests
runTest();


--- test-version-check.js ---
import {
	compareVersions,
	displayUpgradeNotification
} from './scripts/modules/commands.js';

// Simulate different version scenarios
console.log('=== Simulating version check ===\n');

// 1. Current version is older than latest (should show update notice)
console.log('Scenario 1: Current version older than latest');
displayUpgradeNotification('0.9.30', '1.0.0');

// 2. Current version same as latest (no update needed)
console.log(
	'\nScenario 2: Current version same as latest (this would not normally show a notice)'
);
console.log('Current: 1.0.0, Latest: 1.0.0');
console.log('compareVersions result:', compareVersions('1.0.0', '1.0.0'));
console.log(
	'Update needed:',
	compareVersions('1.0.0', '1.0.0') < 0 ? 'Yes' : 'No'
);

// 3. Current version newer than latest (e.g., development version, would not show notice)
console.log(
	'\nScenario 3: Current version newer than latest (this would not normally show a notice)'
);
console.log('Current: 1.1.0, Latest: 1.0.0');
console.log('compareVersions result:', compareVersions('1.1.0', '1.0.0'));
console.log(
	'Update needed:',
	compareVersions('1.1.0', '1.0.0') < 0 ? 'Yes' : 'No'
);

console.log('\n=== Test complete ===');


--- tsdown.config.ts ---
import { resolve } from 'path';
import { baseConfig, mergeConfig } from '@tm/build-config';
import { config } from 'dotenv';
import { defineConfig } from 'tsdown';

// Load .env file explicitly with absolute path
config({ path: resolve(process.cwd(), '.env') });

// Get all TM_PUBLIC_* env variables for build-time injection
const getBuildTimeEnvs = () => {
	const envs: Record<string, string> = {};

	// Inject package.json version at build time
	try {
		const packageJson = JSON.parse(
			require('fs').readFileSync('package.json', 'utf8')
		);
		envs['TM_PUBLIC_VERSION'] = packageJson.version || 'unknown';
	} catch (error) {
		console.warn('Could not read package.json version during build:', error);
		envs['TM_PUBLIC_VERSION'] = 'unknown';
	}

	for (const [key, value] of Object.entries(process.env)) {
		if (key.startsWith('TM_PUBLIC_')) {
			envs[key] = value || '';
		}
	}

	return envs;
};

export default defineConfig(
	mergeConfig(baseConfig, {
		entry: {
			'task-master': 'scripts/dev.js',
			'mcp-server': 'mcp-server/server.js'
		},
		outDir: 'dist',
		copy: ['assets'],
		ignoreWatch: ['node_modules', 'dist', 'tests', 'apps/extension'],
		// Bundle only our workspace packages, keep npm dependencies external
		noExternal: [/^@tm\//],
		env: getBuildTimeEnvs()
	})
);


--- update-task-migration-plan.md ---
# Update Task Migration Plan

## Overview

Migrate and unify `update-tasks.js` and `update-subtask-by-id.js` into a single `update-task` command that handles both task and subtask updates. This migration will move from the legacy `scripts/modules/task-manager/` structure to the new `apps/cli` and `packages/tm-core` architecture.

## Current State Analysis

### `update-tasks.js` - Bulk Task Updates

**Purpose**: Update multiple tasks from a specified ID onwards
**Input Format**: `--from=<id> --prompt="context"`
**AI Service**: `generateObjectService` with structured schema

### `update-subtask-by-id.js` - Single Subtask Updates

**Purpose**: Append timestamped information to a specific subtask
**Input Format**: `--id=<parentId.subtaskId> --prompt="notes"`
**AI Service**: `generateTextService` for freeform content

## Unified Command Design

### New Command: `update-task`

```bash
# Update single task (replaces update-task)
task-master update-task --id=3 --prompt="changes"

# Update single subtask (replaces update-subtask)
task-master update-task --id=3.2 --prompt="implementation notes"

# Update multiple tasks from ID onwards (replaces update --from)
task-master update-task --from=3 --prompt="changes"
```

### Intelligent Behavior Detection

The command should automatically determine behavior based on:

1. **ID format**: Contains `.` → subtask mode
2. **--from flag**: Present → bulk update mode
3. **Default**: Single task update mode

---

## Functionality Checklist

### Core Functionality

#### Input Validation & Parsing

- [ ] Validate `tasksPath` exists
- [ ] Validate `id` parameter (task: integer, subtask: "parent.child" format)
- [ ] Validate `fromId` parameter (integer, positive)
- [ ] Validate `prompt` parameter (non-empty string)
- [ ] Parse subtask ID format: split "parentId.subtaskId" and validate both parts
- [ ] Determine project root (from context or `findProjectRoot()`)
- [ ] Support both MCP and CLI modes (detect via `mcpLog` presence)
- [ ] Handle `outputFormat` ('text' or 'json', auto-detect for MCP)

#### Task Loading & Filtering

- [ ] Load tasks from `tasks.json` using `readJSON(tasksPath, projectRoot, tag)`
- [ ] Validate tasks data structure exists
- [ ] **Bulk mode**: Filter tasks where `id >= fromId AND status !== 'done'`
- [ ] **Single task mode**: Find specific task by ID
- [ ] **Subtask mode**: Find parent task, validate subtasks array, find specific subtask
- [ ] Handle "no tasks to update" scenario gracefully

#### Context Gathering

- [ ] Initialize `ContextGatherer` with projectRoot and tag
- [ ] Flatten all tasks with subtasks using `flattenTasksWithSubtasks()`
- [ ] Initialize `FuzzyTaskSearch` with appropriate command type:
  - `'update'` for bulk/single task mode
  - `'update-subtask'` for subtask mode
- [ ] **Bulk/Single task**: Search with prompt, max 5 results, include self
- [ ] **Subtask mode**: Search with combined query: `${parentTask.title} ${subtask.title} ${prompt}`
- [ ] Merge task IDs to update with relevant context task IDs
- [ ] Gather context in 'research' format
- [ ] Handle context gathering errors gracefully (log warning, continue)

#### Prompt Building

- [ ] Initialize `PromptManager` via `getPromptManager()`
- [ ] **Bulk/Single task mode**: Load 'update-tasks' prompt template with params:
  - `tasks` (array of tasks to update)
  - `updatePrompt`
  - `useResearch`
  - `projectContext` (gathered context)
  - `hasCodebaseAnalysis` (from config)
  - `projectRoot`
- [ ] **Subtask mode**: Load 'update-subtask' prompt template with params:
  - `parentTask` (id, title)
  - `prevSubtask` (id, title, status) - if exists
  - `nextSubtask` (id, title, status) - if exists
  - `currentDetails` (existing subtask details or fallback)
  - `updatePrompt`
  - `useResearch`
  - `gatheredContext`
  - `hasCodebaseAnalysis`
  - `projectRoot`
- [ ] **Subtask mode**: Support variant key ('research' or 'default')
- [ ] Extract `systemPrompt` and `userPrompt` from prompt manager

#### AI Service Integration

- [ ] Determine service role: `useResearch ? 'research' : 'main'`
- [ ] **Bulk/Single task mode**: Call `generateObjectService` with:
  - `role`, `session`, `projectRoot`
  - `systemPrompt`, `prompt` (userPrompt)
  - `schema: COMMAND_SCHEMAS['update-tasks']`
  - `objectName: 'tasks'`
  - `commandName: 'update-tasks'`
  - `outputType: isMCP ? 'mcp' : 'cli'`
- [ ] **Subtask mode**: Call `generateTextService` with:
  - `prompt` (userPrompt), `systemPrompt`
  - `role`, `session`, `projectRoot`
  - `maxRetries: 2`
  - `commandName: 'update-subtask'`
  - `outputType: isMCP ? 'mcp' : 'cli'`
- [ ] Handle empty/invalid AI responses
- [ ] Capture `telemetryData` and `tagInfo` from response

#### Data Updates & Persistence

- [ ] **Bulk/Single task mode**:
  - Parse `aiServiceResponse.mainResult.tasks` array
  - Validate array structure
  - Create Map for efficient lookup
  - Merge updated tasks with existing, preserving subtasks field
  - Track actual update count
- [ ] **Subtask mode**:
  - Extract text string from `aiServiceResponse.mainResult`
  - Generate ISO timestamp
  - Format as: `<info added on ${timestamp}>\n${content}\n</info added on ${timestamp}>`
  - Append to `subtask.details` (create if doesn't exist)
  - Store newly added snippet separately for display
  - If prompt < 100 chars: append `[Updated: ${date}]` to subtask.description
- [ ] Write updated data using `writeJSON(tasksPath, data, projectRoot, tag)`
- [ ] Optionally call `generateTaskFiles()` (currently commented out in both)

#### CLI Display & UX

- [ ] **Pre-update display** (CLI only, text mode):
  - Create table with columns: ID, Title, Status
  - Truncate titles appropriately (57 chars for tasks, 52 for subtasks)
  - Apply status colors via `getStatusWithColor()`
  - Show boxed header with update count/target
  - **Bulk mode**: Show info box about completed subtasks handling
  - Display table
- [ ] **Loading indicators** (CLI only, text mode):
  - Start loading indicator before AI call
  - Message: "Updating tasks with AI..." (bulk/single) or "Updating subtask..." (subtask)
  - Support research variant message
  - Stop indicator when complete or on error
- [ ] **Post-update display** (CLI only, text mode):
  - **Bulk/Single task**: Success message with update count
  - **Subtask mode**: Boxed success message with:
    - Subtask ID
    - Title
    - "Newly Added Snippet" section showing timestamped content
  - Display AI usage summary via `displayAiUsageSummary(telemetryData, 'cli')`

#### Logging & Debugging

- [ ] Use appropriate logger: `mcpLog` (MCP) or `consoleLog` (CLI)
- [ ] Log info messages with proper format (MCP vs CLI differences)
- [ ] Log start of operation with key parameters
- [ ] Log task counts and AI response details
- [ ] Log successful completion
- [ ] **Debug mode** (when `getDebugFlag(session)` true):
  - Log subtask details before/after update
  - Log writeJSON calls
  - Log full error stack traces

#### Error Handling

- [ ] Catch and handle errors at multiple levels:
  - Context gathering errors (warn and continue)
  - AI service errors (stop and report)
  - General operation errors (report and exit/throw)
- [ ] **CLI mode**:
  - Print colored error messages
  - Show helpful troubleshooting for common errors:
    - API key missing/invalid
    - Model overloaded
    - Task/subtask not found
    - Invalid ID format
    - Empty prompt
    - Empty AI response
  - Exit with code 1
- [ ] **MCP mode**: Re-throw errors for caller handling
- [ ] Always stop loading indicators on error

#### Return Values

- [ ] **Success returns** (both modes):

  ```javascript
  {
    success: true,  // bulk/single task only
    updatedTasks: [...],  // bulk/single task only
    updatedSubtask: {...},  // subtask only
    telemetryData: {...},
    tagInfo: {...}
  }
  ```

- [ ] **Failure returns**:
  - CLI: exits with code 1
  - MCP: throws error
  - Subtask mode: returns `null` on error

### Special Features

#### Completed Subtasks Handling (Bulk Mode)

- [ ] Display informational box explaining:
  - Done/completed subtasks are preserved
  - New subtasks build upon completed work
  - Revisions create new subtasks instead of modifying done items
  - Maintains clear record of progress

#### Subtask Context Awareness

- [ ] Provide parent task context (id, title) to AI
- [ ] Provide previous subtask context (if exists) to AI
- [ ] Provide next subtask context (if exists) to AI
- [ ] Include current subtask details in prompt

#### Timestamp Tracking

- [ ] Use ISO format timestamps for subtask updates
- [ ] Wrap appended content in timestamped tags
- [ ] Update description field with simple date stamp (short prompts only)

---

## Migration Architecture

### Object-Oriented Design Philosophy

This migration will follow the established patterns in `tm-core` and `apps/cli`:
- **Domain separation** with clear bounded contexts
- **Dependency injection** for testability and flexibility
- **Abstract base classes** for shared behavior
- **Interfaces** for contracts and loose coupling
- **Service layer** for business logic orchestration
- **Factory pattern** for object creation
- **Single Responsibility Principle** throughout

### Package Structure

```
packages/tm-core/
  src/
    commands/
      update-task/
        # Core Interfaces & Types
        types.ts                              # Shared types, enums, interfaces
        interfaces/
          update-strategy.interface.ts        # IUpdateStrategy contract
          update-context.interface.ts         # IUpdateContext contract
          display.interface.ts                # IDisplayManager contract

        # Services (Business Logic)
        update-task.service.ts                # Main orchestrator service
        context-builder.service.ts            # Builds AI context (uses ContextGatherer, FuzzySearch)
        prompt-builder.service.ts             # Builds prompts (uses PromptManager)
        data-merger.service.ts                # Merges AI results with existing data

        # Strategies (Update Mode Logic)
        strategies/
          base-update.strategy.ts             # Abstract base class for all strategies
          bulk-update.strategy.ts             # Bulk task update implementation
          single-task-update.strategy.ts      # Single task update implementation
          subtask-update.strategy.ts          # Subtask update implementation

        # Utilities & Helpers
        validators/
          update-input.validator.ts           # Validates all input parameters
          task-id.validator.ts                # Parses and validates task/subtask IDs

        display/
          cli-display.manager.ts              # CLI output formatting
          json-display.manager.ts             # JSON output formatting
          update-display.factory.ts           # Creates appropriate display manager

        factories/
          update-strategy.factory.ts          # Creates appropriate strategy based on mode

        # Main Entry Point
        index.ts                              # Public API export

apps/cli/
  src/
    commands/
      update-task.command.ts                  # CLI command definition (uses UpdateTaskService)
```

### Core Classes & Their Responsibilities

#### 1. **UpdateTaskService** (Main Orchestrator)
```typescript
/**
 * Main service that coordinates the entire update process
 * Handles initialization, strategy selection, and result aggregation
 */
export class UpdateTaskService {
  constructor(
    private readonly configManager: ConfigManager,
    private readonly storage: IStorage,
    private readonly logger: Logger,
    private readonly strategyFactory: UpdateStrategyFactory,
    private readonly contextBuilder: ContextBuilderService,
    private readonly displayFactory: UpdateDisplayFactory
  ) {}

  async updateTask(options: UpdateTaskOptions): Promise<UpdateTaskResult> {
    // 1. Validate inputs
    // 2. Detect mode and create strategy
    // 3. Build context
    // 4. Execute strategy
    // 5. Display results
    // 6. Return result
  }
}
```

**Uses (existing classes):**
- `ConfigManager` - Project configuration
- `IStorage` - Task persistence
- `Logger` - Logging
- `ContextGatherer` - Gather related context
- `FuzzyTaskSearch` - Find relevant tasks
- `PromptManager` - Load prompt templates

**Uses (new classes):**
- `UpdateStrategyFactory` - Create update strategy
- `ContextBuilderService` - Build AI context
- `UpdateDisplayFactory` - Create display manager

---

#### 2. **IUpdateStrategy** (Strategy Interface)
```typescript
/**
 * Contract for all update strategies
 * Defines the common interface for bulk, single, and subtask updates
 */
export interface IUpdateStrategy {
  /**
   * Validate that the strategy can handle the given context
   */
  validate(context: IUpdateContext): Promise<void>;

  /**
   * Load and filter tasks that need updating
   */
  loadTasks(context: IUpdateContext): Promise<TaskLoadResult>;

  /**
   * Build prompts for AI service
   */
  buildPrompts(
    context: IUpdateContext,
    tasks: TaskLoadResult
  ): Promise<PromptResult>;

  /**
   * Call appropriate AI service
   */
  callAIService(
    context: IUpdateContext,
    prompts: PromptResult
  ): Promise<AIServiceResult>;

  /**
   * Merge AI results with existing data
   */
  mergeResults(
    context: IUpdateContext,
    aiResult: AIServiceResult,
    originalTasks: TaskLoadResult
  ): Promise<MergeResult>;

  /**
   * Get the mode this strategy handles
   */
  getMode(): UpdateMode;
}
```

---

#### 3. **BaseUpdateStrategy** (Abstract Base Class)
```typescript
/**
 * Provides common functionality for all update strategies
 * Implements template method pattern for the update workflow
 */
export abstract class BaseUpdateStrategy implements IUpdateStrategy {
  protected readonly logger: Logger;

  constructor(
    protected readonly contextBuilder: ContextBuilderService,
    protected readonly promptBuilder: PromptBuilderService,
    protected readonly dataMerger: DataMergerService,
    protected readonly aiService: AIService // wrapper around generate[Object|Text]Service
  ) {
    this.logger = getLogger(`UpdateStrategy:${this.getMode()}`);
  }

  // Template method - defines the workflow
  async execute(context: IUpdateContext): Promise<UpdateStrategyResult> {
    await this.validate(context);
    const tasks = await this.loadTasks(context);
    const prompts = await this.buildPrompts(context, tasks);
    const aiResult = await this.callAIService(context, prompts);
    const merged = await this.mergeResults(context, aiResult, tasks);
    return merged;
  }

  // Subclasses must implement these
  abstract validate(context: IUpdateContext): Promise<void>;
  abstract loadTasks(context: IUpdateContext): Promise<TaskLoadResult>;
  abstract getMode(): UpdateMode;

  // Shared implementations with extensibility
  async buildPrompts(
    context: IUpdateContext,
    tasks: TaskLoadResult
  ): Promise<PromptResult> {
    // Delegates to PromptBuilderService with mode-specific params
  }

  protected abstract getPromptParams(
    context: IUpdateContext,
    tasks: TaskLoadResult
  ): PromptParams;
}
```

---

#### 4. **BulkUpdateStrategy** (Concrete Strategy)
```typescript
/**
 * Handles bulk task updates (--from flag)
 * Uses generateObjectService for structured updates
 */
export class BulkUpdateStrategy extends BaseUpdateStrategy {
  getMode(): UpdateMode {
    return UpdateMode.BULK;
  }

  async validate(context: IUpdateContext): Promise<void> {
    if (!context.options.from) {
      throw new TaskMasterError('Bulk mode requires --from parameter');
    }
    // Additional validations...
  }

  async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
    // Filter tasks where id >= fromId AND status !== 'done'
  }

  async callAIService(
    context: IUpdateContext,
    prompts: PromptResult
  ): Promise<AIServiceResult> {
    // Call generateObjectService with update-tasks schema
  }

  protected getPromptParams(
    context: IUpdateContext,
    tasks: TaskLoadResult
  ): PromptParams {
    return {
      tasks: tasks.tasks,
      updatePrompt: context.options.prompt,
      useResearch: context.options.useResearch,
      projectContext: tasks.gatheredContext,
      // ...
    };
  }
}
```

---

#### 5. **SubtaskUpdateStrategy** (Concrete Strategy)
```typescript
/**
 * Handles single subtask updates (--id with dot notation)
 * Uses generateTextService for timestamped appends
 */
export class SubtaskUpdateStrategy extends BaseUpdateStrategy {
  getMode(): UpdateMode {
    return UpdateMode.SUBTASK;
  }

  async validate(context: IUpdateContext): Promise<void> {
    const parsed = TaskIdValidator.parseSubtaskId(context.options.id);
    if (!parsed) {
      throw new TaskMasterError('Invalid subtask ID format');
    }
  }

  async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
    // Find parent task, locate specific subtask
    // Build context with prev/next subtask info
  }

  async callAIService(
    context: IUpdateContext,
    prompts: PromptResult
  ): Promise<AIServiceResult> {
    // Call generateTextService for freeform content
  }

  async mergeResults(
    context: IUpdateContext,
    aiResult: AIServiceResult,
    originalTasks: TaskLoadResult
  ): Promise<MergeResult> {
    // Append timestamped content to subtask.details
    const timestamp = new Date().toISOString();
    const formatted = `<info added on ${timestamp}>\n${aiResult.text}\n</info>`;
    // ...
  }
}
```

---

#### 6. **SingleTaskUpdateStrategy** (Concrete Strategy)
```typescript
/**
 * Handles single task updates (--id without dot)
 * Uses generateObjectService for structured updates
 */
export class SingleTaskUpdateStrategy extends BaseUpdateStrategy {
  getMode(): UpdateMode {
    return UpdateMode.SINGLE;
  }

  async validate(context: IUpdateContext): Promise<void> {
    TaskIdValidator.validateTaskId(context.options.id);
  }

  async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
    // Find single task by ID
  }

  // Similar to BulkUpdateStrategy but operates on single task
}
```

---

#### 7. **ContextBuilderService** (Helper Service)
```typescript
/**
 * Builds context for AI prompts
 * Coordinates ContextGatherer and FuzzyTaskSearch
 */
export class ContextBuilderService {
  constructor(
    private readonly logger: Logger
  ) {}

  async buildContext(
    options: ContextBuildOptions
  ): Promise<BuiltContext> {
    try {
      const gatherer = new ContextGatherer(
        options.projectRoot,
        options.tag
      );

      const allTasksFlat = flattenTasksWithSubtasks(options.allTasks);
      const fuzzySearch = new FuzzyTaskSearch(
        allTasksFlat,
        options.searchMode // 'update' or 'update-subtask'
      );

      const searchResults = fuzzySearch.findRelevantTasks(
        options.searchQuery,
        { maxResults: 5, includeSelf: true }
      );

      const relevantTaskIds = fuzzySearch.getTaskIds(searchResults);
      const finalTaskIds = [
        ...new Set([...options.targetTaskIds, ...relevantTaskIds])
      ];

      const contextResult = await gatherer.gather({
        tasks: finalTaskIds,
        format: 'research'
      });

      return {
        context: contextResult.context || '',
        taskIds: finalTaskIds
      };
    } catch (error) {
      this.logger.warn(`Context gathering failed: ${error.message}`);
      return { context: '', taskIds: options.targetTaskIds };
    }
  }
}
```

**Uses (existing):**
- `ContextGatherer`
- `FuzzyTaskSearch`

---

#### 8. **PromptBuilderService** (Helper Service)
```typescript
/**
 * Builds system and user prompts for AI services
 * Wraps PromptManager with strategy-specific logic
 */
export class PromptBuilderService {
  constructor(
    private readonly promptManager: PromptManager,
    private readonly logger: Logger
  ) {}

  async buildPrompt(
    templateName: string,
    params: PromptParams,
    variant?: string
  ): Promise<PromptResult> {
    const { systemPrompt, userPrompt } = await this.promptManager.loadPrompt(
      templateName,
      params,
      variant
    );

    return {
      systemPrompt,
      userPrompt,
      templateName,
      params
    };
  }
}
```

**Uses (existing):**
- `PromptManager`

---

#### 9. **DataMergerService** (Helper Service)
```typescript
/**
 * Merges AI service results with existing task data
 * Handles different merge strategies for different modes
 */
export class DataMergerService {
  constructor(private readonly logger: Logger) {}

  /**
   * Merge for bulk/single task mode (structured updates)
   */
  mergeTasks(
    existingTasks: Task[],
    updatedTasks: Task[],
    options: MergeOptions
  ): MergeResult {
    const updatedTasksMap = new Map(
      updatedTasks.map(t => [t.id, t])
    );

    let updateCount = 0;
    const merged = existingTasks.map(task => {
      if (updatedTasksMap.has(task.id)) {
        const updated = updatedTasksMap.get(task.id)!;
        updateCount++;
        return {
          ...task,
          ...updated,
          // Preserve subtasks if not provided by AI
          subtasks: updated.subtasks !== undefined
            ? updated.subtasks
            : task.subtasks
        };
      }
      return task;
    });

    return {
      tasks: merged,
      updateCount,
      mode: 'structured'
    };
  }

  /**
   * Merge for subtask mode (timestamped append)
   */
  mergeSubtask(
    parentTask: Task,
    subtaskIndex: number,
    newContent: string,
    options: SubtaskMergeOptions
  ): SubtaskMergeResult {
    const subtask = parentTask.subtasks![subtaskIndex];
    const timestamp = new Date().toISOString();
    const formatted = `<info added on ${timestamp}>\n${newContent.trim()}\n</info added on ${timestamp}>`;

    subtask.details = (subtask.details ? subtask.details + '\n' : '') + formatted;

    // Short prompts get description timestamp
    if (options.prompt.length < 100 && subtask.description) {
      subtask.description += ` [Updated: ${new Date().toLocaleDateString()}]`;
    }

    return {
      updatedSubtask: subtask,
      newlyAddedSnippet: formatted,
      parentTask
    };
  }
}
```

---

#### 10. **IDisplayManager** (Display Interface)
```typescript
/**
 * Contract for display managers
 * Allows different output formats (CLI, JSON, etc.)
 */
export interface IDisplayManager {
  /**
   * Show tasks before update
   */
  showPreUpdate(tasks: Task[], mode: UpdateMode): void;

  /**
   * Show loading indicator
   */
  startLoading(message: string): void;
  stopLoading(success?: boolean): void;

  /**
   * Show post-update results
   */
  showPostUpdate(result: UpdateStrategyResult, mode: UpdateMode): void;

  /**
   * Show telemetry/usage data
   */
  showTelemetry(telemetry: TelemetryData): void;

  /**
   * Show errors
   */
  showError(error: Error): void;
}
```

---

#### 11. **CLIDisplayManager** (Concrete Display)
```typescript
/**
 * Formats output for CLI with colors, tables, and boxes
 */
export class CLIDisplayManager implements IDisplayManager {
  constructor(
    private readonly logger: Logger,
    private readonly isSilent: boolean
  ) {}

  showPreUpdate(tasks: Task[], mode: UpdateMode): void {
    // Create table with ID, Title, Status columns
    // Show boxed header
    // For bulk mode: show completed subtasks info box
  }

  startLoading(message: string): void {
    // startLoadingIndicator(message)
  }

  // ... implement other methods with chalk, boxen, cli-table3
}
```

---

#### 12. **UpdateStrategyFactory** (Factory)
```typescript
/**
 * Creates the appropriate update strategy based on mode
 */
export class UpdateStrategyFactory {
  constructor(
    private readonly contextBuilder: ContextBuilderService,
    private readonly promptBuilder: PromptBuilderService,
    private readonly dataMerger: DataMergerService,
    private readonly aiService: AIService
  ) {}

  createStrategy(mode: UpdateMode): IUpdateStrategy {
    switch (mode) {
      case UpdateMode.BULK:
        return new BulkUpdateStrategy(
          this.contextBuilder,
          this.promptBuilder,
          this.dataMerger,
          this.aiService
        );
      case UpdateMode.SINGLE:
        return new SingleTaskUpdateStrategy(
          this.contextBuilder,
          this.promptBuilder,
          this.dataMerger,
          this.aiService
        );
      case UpdateMode.SUBTASK:
        return new SubtaskUpdateStrategy(
          this.contextBuilder,
          this.promptBuilder,
          this.dataMerger,
          this.aiService
        );
      default:
        throw new TaskMasterError(`Unknown update mode: ${mode}`);
    }
  }

  detectMode(options: UpdateTaskOptions): UpdateMode {
    if (options.from !== undefined) {
      return UpdateMode.BULK;
    }
    if (options.id && typeof options.id === 'string' && options.id.includes('.')) {
      return UpdateMode.SUBTASK;
    }
    if (options.id !== undefined) {
      return UpdateMode.SINGLE;
    }
    throw new TaskMasterError('Must provide either --id or --from parameter');
  }
}
```

---

#### 13. **Validators** (Utility Classes)
```typescript
/**
 * Validates all update task inputs
 */
export class UpdateInputValidator {
  static validate(options: UpdateTaskOptions): void {
    // Validate tasksPath, prompt, etc.
  }
}

/**
 * Parses and validates task/subtask IDs
 */
export class TaskIdValidator {
  static validateTaskId(id: any): number {
    // Parse and validate task ID
  }

  static parseSubtaskId(id: string): SubtaskIdParts | null {
    // Parse "parentId.subtaskId" format
  }
}
```

---

### Class Diagram (Relationships)

```
┌─────────────────────────┐
│  UpdateTaskService      │ ◄─── Main Orchestrator
│  (Coordinates)          │
└───────┬─────────────────┘
        │ uses
        ├──► UpdateStrategyFactory ──creates──► IUpdateStrategy
        │                                           │
        ├──► ContextBuilderService                 │ implements
        │                                           ▼
        ├──► IDisplayManager ◄──creates── UpdateDisplayFactory
        │         │
        │         ├── CLIDisplayManager
        │         └── JSONDisplayManager
        │
        └──► ConfigManager (existing)
             IStorage (existing)
             Logger (existing)

┌────────────────────────────────────────────────────┐
│                 IUpdateStrategy                    │
└────────────────────────────────────────────────────┘
                        △
                        │ extends
            ┌───────────┴────────────┐
            │                        │
┌───────────────────────┐    ┌──────────────────────┐
│  BaseUpdateStrategy   │    │  Abstract base with  │
│  (Template Method)    │    │  common workflow     │
└───────────┬───────────┘    └──────────────────────┘
            │ extends
    ┌───────┼──────────┬─────────────┐
    │       │          │             │
┌───▼───┐ ┌─▼────┐  ┌─▼──────────┐  │
│ Bulk  │ │Single│  │  Subtask   │  │
│Update │ │Task  │  │  Update    │  │
│       │ │Update│  │            │  │
└───────┘ └──────┘  └────────────┘  │
                                     │
                                     ├──► ContextBuilderService
                                     │      ├─uses─► ContextGatherer (existing)
                                     │      └─uses─► FuzzyTaskSearch (existing)
                                     │
                                     ├──► PromptBuilderService
                                     │      └─uses─► PromptManager (existing)
                                     │
                                     └──► DataMergerService
```

---

### Dependency Injection & Initialization

```typescript
// In packages/tm-core/src/commands/update-task/index.ts

/**
 * Factory function to create a fully initialized UpdateTaskService
 */
export async function createUpdateTaskService(
  configManager: ConfigManager,
  storage: IStorage
): Promise<UpdateTaskService> {
  const logger = getLogger('UpdateTaskService');

  // Create helper services
  const contextBuilder = new ContextBuilderService(logger);
  const promptManager = getPromptManager(); // existing
  const promptBuilder = new PromptBuilderService(promptManager, logger);
  const dataMerger = new DataMergerService(logger);
  const aiService = new AIService(); // wrapper around generateObjectService/generateTextService

  // Create factory
  const strategyFactory = new UpdateStrategyFactory(
    contextBuilder,
    promptBuilder,
    dataMerger,
    aiService
  );

  // Create display factory
  const displayFactory = new UpdateDisplayFactory();

  // Create service
  return new UpdateTaskService(
    configManager,
    storage,
    logger,
    strategyFactory,
    contextBuilder,
    displayFactory
  );
}
```

---

### Types & Interfaces

```typescript
// packages/tm-core/src/commands/update-task/types.ts

export enum UpdateMode {
  BULK = 'bulk',
  SINGLE = 'single',
  SUBTASK = 'subtask'
}

export interface UpdateTaskOptions {
  tasksPath: string;
  id?: number | string;
  from?: number;
  prompt: string;
  useResearch?: boolean;
  context?: UpdateContext;
  outputFormat?: 'text' | 'json';
}

export interface UpdateContext {
  session?: any;
  mcpLog?: any;
  projectRoot?: string;
  tag?: string;
}

export interface UpdateTaskResult {
  success: boolean;
  mode: UpdateMode;
  updatedTasks?: Task[];
  updatedSubtask?: Subtask;
  updateCount?: number;
  telemetryData?: TelemetryData;
  tagInfo?: TagInfo;
}

export interface IUpdateContext {
  options: UpdateTaskOptions;
  projectRoot: string;
  tag?: string;
  mode: UpdateMode;
  isMCP: boolean;
  logger: Logger;
}

export interface TaskLoadResult {
  tasks: Task[];
  gatheredContext: string;
  originalData: TasksData;
}

export interface PromptResult {
  systemPrompt: string;
  userPrompt: string;
  templateName: string;
  params: PromptParams;
}

export interface AIServiceResult {
  mainResult: any; // structured object or text string
  telemetryData?: TelemetryData;
  tagInfo?: TagInfo;
}

export interface MergeResult {
  tasks?: Task[];
  updatedSubtask?: Subtask;
  newlyAddedSnippet?: string;
  updateCount: number;
  mode: 'structured' | 'timestamped';
}
```

---

## Implementation Phases

### Phase 1: Foundation & Core Types

**Goal**: Establish the type system and interfaces

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/types.ts`
   - Define `UpdateMode` enum
   - Define all shared interfaces (`UpdateTaskOptions`, `UpdateTaskResult`, etc.)
2. `packages/tm-core/src/commands/update-task/interfaces/update-strategy.interface.ts`
   - Define `IUpdateStrategy` interface
3. `packages/tm-core/src/commands/update-task/interfaces/update-context.interface.ts`
   - Define `IUpdateContext` interface
4. `packages/tm-core/src/commands/update-task/interfaces/display.interface.ts`
   - Define `IDisplayManager` interface

**Existing Classes to Study**:
- `BaseExecutor` - For abstract class patterns
- `TaskService` - For service patterns
- `IStorage` - For interface patterns

---

### Phase 2: Validator & Helper Utilities

**Goal**: Build validation and utility classes

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/validators/update-input.validator.ts`
   - Create `UpdateInputValidator` class
   - Port validation logic from both old files
2. `packages/tm-core/src/commands/update-task/validators/task-id.validator.ts`
   - Create `TaskIdValidator` class
   - Implement `validateTaskId()` and `parseSubtaskId()` methods

**Tests to Create**:
- `update-input.validator.spec.ts`
- `task-id.validator.spec.ts`

---

### Phase 3: Service Layer

**Goal**: Build the helper services that strategies will use

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/context-builder.service.ts`
   - Create `ContextBuilderService` class
   - **Uses existing**: `ContextGatherer`, `FuzzyTaskSearch`
   - Port context gathering logic from both old files

2. `packages/tm-core/src/commands/update-task/prompt-builder.service.ts`
   - Create `PromptBuilderService` class
   - **Uses existing**: `PromptManager` (via `getPromptManager()`)
   - Port prompt building logic

3. `packages/tm-core/src/commands/update-task/data-merger.service.ts`
   - Create `DataMergerService` class
   - Implement `mergeTasks()` method (from `update-tasks.js` lines 250-273)
   - Implement `mergeSubtask()` method (from `update-subtask-by-id.js` lines 291-332)

**Tests to Create**:
- `context-builder.service.spec.ts`
- `prompt-builder.service.spec.ts`
- `data-merger.service.spec.ts`

**Existing Classes Used**:
- `ContextGatherer` (from `scripts/modules/utils/contextGatherer.js`)
- `FuzzyTaskSearch` (from `scripts/modules/utils/fuzzyTaskSearch.js`)
- `PromptManager` (from `scripts/modules/prompt-manager.js`)

---

### Phase 4: Strategy Pattern Implementation

**Goal**: Implement the update strategies

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/strategies/base-update.strategy.ts`
   - Create `BaseUpdateStrategy` abstract class implementing `IUpdateStrategy`
   - Implement template method pattern
   - Define abstract methods for subclasses

2. `packages/tm-core/src/commands/update-task/strategies/bulk-update.strategy.ts`
   - Create `BulkUpdateStrategy` class extending `BaseUpdateStrategy`
   - Port logic from `update-tasks.js` lines 79-293
   - **Uses**: `generateObjectService` with `COMMAND_SCHEMAS['update-tasks']`

3. `packages/tm-core/src/commands/update-task/strategies/single-task-update.strategy.ts`
   - Create `SingleTaskUpdateStrategy` class extending `BaseUpdateStrategy`
   - Similar to bulk but for single task
   - **Uses**: `generateObjectService` with `COMMAND_SCHEMAS['update-tasks']`

4. `packages/tm-core/src/commands/update-task/strategies/subtask-update.strategy.ts`
   - Create `SubtaskUpdateStrategy` class extending `BaseUpdateStrategy`
   - Port logic from `update-subtask-by-id.js` lines 67-378
   - **Uses**: `generateTextService` for freeform content

**Tests to Create**:
- `bulk-update.strategy.spec.ts`
- `single-task-update.strategy.spec.ts`
- `subtask-update.strategy.spec.ts`

**Existing Classes/Functions Used**:
- `generateObjectService` (from `scripts/modules/ai-services-unified.js`)
- `generateTextService` (from `scripts/modules/ai-services-unified.js`)
- `COMMAND_SCHEMAS` (from `src/schemas/registry.js`)
- `readJSON`, `writeJSON`, `flattenTasksWithSubtasks` (from `scripts/modules/utils.js`)

---

### Phase 5: Display Layer

**Goal**: Implement display managers for different output formats

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/display/cli-display.manager.ts`
   - Create `CLIDisplayManager` class implementing `IDisplayManager`
   - Port CLI display logic from both old files
   - **Uses existing**: `chalk`, `boxen`, `cli-table3`, `getStatusWithColor`, `truncate`

2. `packages/tm-core/src/commands/update-task/display/json-display.manager.ts`
   - Create `JSONDisplayManager` class implementing `IDisplayManager`
   - Implement JSON output format (for MCP)

3. `packages/tm-core/src/commands/update-task/display/update-display.factory.ts`
   - Create `UpdateDisplayFactory` class
   - Factory method to create appropriate display manager

**Tests to Create**:
- `cli-display.manager.spec.ts`
- `json-display.manager.spec.ts`

**Existing Functions Used**:
- `getStatusWithColor`, `startLoadingIndicator`, `stopLoadingIndicator`, `displayAiUsageSummary` (from `scripts/modules/ui.js`)
- `truncate`, `isSilentMode` (from `scripts/modules/utils.js`)

---

### Phase 6: Factory Pattern

**Goal**: Implement factory for creating strategies

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/factories/update-strategy.factory.ts`
   - Create `UpdateStrategyFactory` class
   - Implement `createStrategy(mode)` method
   - Implement `detectMode(options)` method
   - Handles dependency injection for all strategies

**Tests to Create**:
- `update-strategy.factory.spec.ts` (test mode detection and strategy creation)

---

### Phase 7: Main Service Orchestrator

**Goal**: Create the main service that ties everything together

**New Files to Create**:
1. `packages/tm-core/src/commands/update-task/update-task.service.ts`
   - Create `UpdateTaskService` class
   - Main orchestrator that coordinates all components
   - Implements high-level workflow

2. `packages/tm-core/src/commands/update-task/index.ts`
   - Export all public types and interfaces
   - Export `createUpdateTaskService()` factory function
   - Export `UpdateTaskService` class

**Tests to Create**:
- `update-task.service.spec.ts` (integration tests)

**Existing Classes Used**:
- `ConfigManager` (from `packages/tm-core/src/config/config-manager.ts`)
- `IStorage` (from `packages/tm-core/src/interfaces/storage.interface.ts`)
- `Logger`, `getLogger` (from `packages/tm-core/src/logger/`)

---

### Phase 8: CLI Integration

**Goal**: Wire up the new service to the CLI

**New Files to Create**:
1. `apps/cli/src/commands/update-task.command.ts`
   - CLI command definition using `commander`
   - Calls `createUpdateTaskService()` and executes
   - Handles CLI-specific argument parsing

**Files to Modify**:
1. `apps/cli/src/index.ts` (or main CLI entry point)
   - Register new `update-task` command
   - Optionally add aliases for backward compatibility

**Existing Patterns to Follow**:
- Study existing CLI commands in `apps/cli/src/commands/`
- Follow same pattern for option parsing and service invocation

---

### Phase 9: Integration & Testing

**Goal**: Ensure everything works together

**Tasks**:
1. Run full integration tests
   - Test bulk update workflow end-to-end
   - Test single task update workflow
   - Test subtask update workflow
   - Test MCP mode vs CLI mode
   - Test all edge cases from checklist

2. Verify against original functionality
   - Use the functionality checklist
   - Ensure no regressions
   - Test with real task data

3. Performance testing
   - Compare execution time with old implementation
   - Ensure context gathering performs well

**Tests to Create**:
- `update-task.integration.spec.ts` - Full workflow tests
- End-to-end tests with real task files

---

### Phase 10: Documentation & Migration

**Goal**: Document the new system and deprecate old code

**Tasks**:
1. Update documentation
   - Update `apps/docs/command-reference.mdx`
   - Add JSDoc comments to all public APIs
   - Create migration guide for users

2. Add deprecation warnings
   - Mark old `update` and `update-subtask` commands as deprecated
   - Add console warnings directing users to new command

3. Create changeset
   - Document breaking changes (if any)
   - Document new features (unified command)
   - Note backward compatibility

**Files to Modify**:
1. `apps/docs/command-reference.mdx` - Update command documentation
2. Legacy files (add deprecation warnings):
   - `scripts/modules/task-manager/update-tasks.js`
   - `scripts/modules/task-manager/update-subtask-by-id.js`

---

### Phase 11: Cleanup

**Goal**: Remove deprecated code (future version)

**Tasks**:
1. Remove old files:
   - `scripts/modules/task-manager/update-tasks.js`
   - `scripts/modules/task-manager/update-subtask-by-id.js`
   - Any related old command handlers

2. Clean up any temporary compatibility shims

3. Update all references in codebase to use new command

---

## Testing Strategy

### Unit Tests

- [ ] Mode detection logic
- [ ] ID parsing and validation
- [ ] Context gathering integration
- [ ] Prompt building for each mode
- [ ] Data merging logic

### Integration Tests

- [ ] Bulk update workflow
- [ ] Single task update workflow
- [ ] Single subtask update workflow
- [ ] MCP mode operation
- [ ] CLI mode operation

### Edge Cases

- [ ] Empty tasks.json
- [ ] Invalid ID formats
- [ ] Non-existent IDs
- [ ] Tasks with no subtasks
- [ ] Empty AI responses
- [ ] Context gathering failures

---

## Backward Compatibility

### Deprecation Strategy

1. Keep old commands working initially
2. Add deprecation warnings
3. Update all documentation
4. Remove old commands in next major version

### Alias Support (Optional)

```bash
# Could maintain old command names as aliases
task-master update --from=3 --prompt="..."    # Still works, calls update-task
task-master update-subtask --id=3.2 --prompt="..."  # Still works, calls update-task
```

---

## Risk Mitigation

### High-Risk Areas

1. **Data integrity**: Ensure writeJSON doesn't corrupt existing data
2. **AI service compatibility**: Both generateObjectService and generateTextService must work
3. **Subtask detail format**: Maintain timestamp format consistency
4. **Context gathering**: Same behavior across all modes

### Rollback Plan

- Keep old files until new version is fully tested
- Version bump allows reverting if issues found
- Comprehensive test coverage before release

---

## Success Criteria

- [ ] All checklist items verified working
- [ ] Tests passing for all modes
- [ ] MCP integration functional
- [ ] CLI display matches existing behavior
- [ ] Documentation updated
- [ ] No regression in existing functionality
- [ ] Performance comparable or better than current implementation


--- vitest.config.ts ---
import { defineConfig } from 'vitest/config';

/**
 * Root Vitest configuration for Task Master monorepo
 * Provides shared defaults for all packages
 * Individual packages can extend this config with package-specific settings
 */
export default defineConfig({
	test: {
		// Enable global test APIs (describe, it, expect, etc.)
		globals: true,

		// Default environment for all packages (Node.js)
		environment: 'node',

		// Common test file patterns
		include: [
			'tests/**/*.test.ts',
			'tests/**/*.spec.ts',
			'src/**/*.test.ts',
			'src/**/*.spec.ts'
		],

		// Common exclusions
		exclude: ['node_modules', 'dist', '.git', '.cache', '**/node_modules/**'],

		// Coverage configuration
		coverage: {
			provider: 'v8',
			enabled: true,
			reporter: ['text', 'json', 'html'],
			include: ['src/**/*.ts'],
			exclude: [
				'node_modules/',
				'dist/',
				'tests/',
				'**/*.test.ts',
				'**/*.spec.ts',
				'**/*.d.ts',
				'**/mocks/**',
				'**/fixtures/**',
				'**/types/**',
				'vitest.config.ts',
				'src/index.ts'
			],
			// Default thresholds (can be overridden per package)
			thresholds: {
				branches: 70,
				functions: 70,
				lines: 70,
				statements: 70
			}
		},

		// Test execution settings
		testTimeout: 10000,
		clearMocks: true,
		restoreMocks: true,
		mockReset: true
	}
});


--- .claude/hamster.md ---
# Hamster Integration Workflow

This guide outlines the process for working with tasks imported from Hamster briefs using Task Master. When connected to a Hamster brief, follow these specific guidelines to ensure proper task management and workflow execution.

## Command Restrictions

### Supported Commands
Use only these Task Master CLI commands when working with Hamster briefs:
```bash
tm list                      # List all tasks
tm show <sub/task id> --json # Show task details (--json saves tokens)
tm set-status                # Update task status
tm auth refresh              # Refresh authentication token
tm context <brief url>       # Reconnect to Hamster brief context
```

### Unsupported Commands
- Do not use MCP tools when connected with Hamster briefs - they are not yet up to date with Hamster integration
- Do not use other Task Master CLI commands that haven't been verified to work with Hamster integration

## Task Workflow Process

### Starting a Task
```bash
# Mark task and subtasks as in-progress when starting
tm set-status -i 1,1.1 -s in-progress

# Multiple tasks/subtasks can be marked at once using comma separation
tm set-status -i 1,1.1,1.2,2 -s in-progress
```

### Task Implementation Flow
1. **Read the Task**: Use `tm show <id> --json` to understand the task requirements
2. **Check for Subtasks**: If the task has subtasks, implement them one at a time
3. **Implement Subtask**: Complete the subtask implementation
4. **Verify Quality**: Run lint and typecheck before marking as done
   ```bash
   npm run lint
   npm run typecheck
   ```
5. **Mark Complete**: If verification passes, mark the subtask as done
   ```bash
   tm set-status -i 1.1 -s done
   ```
6. **Commit Changes**: Commit the completed subtask work
7. **Repeat**: Continue until all subtasks are complete

### Parent Task Completion
- After all subtasks are done, run final verification:
  ```bash
  npm run lint
  npm run typecheck
  ```
- Mark the parent task as done:
  ```bash
  tm set-status -i 1 -s done
  ```
- Move to the next task and repeat the process

## Multiple Task Context

### Viewing Multiple Tasks
```bash
# Use comma-separated IDs to get context from multiple tasks
tm show 1,1.1,2,2.1 --json

# This is more efficient than calling tm show multiple times
```

### Parallel Subtask Execution
- **When to Parallelize**: If a task has subtasks that can be completed in parallel
- **Requirements**:
  - Ensure work/files to adjust are **not the same** across subtasks
  - Spawn sub-agents for each parallel subtask
  - Verify clear separation of work before parallelizing
- **Example**: If subtask 1.1 modifies `src/api.js` and subtask 1.2 modifies `src/utils.js`, these can run in parallel

## Pull Request Management

### PR Creation Strategy
- **Preferred Approach**: Keep everything in one PR if scope remains manageable
- **When to Split**: Create separate PRs if the work becomes too large
- **Multi-PR Strategy**: If splitting is necessary:
  - Create PRs that build on top of previous ones
  - **Always confirm with the human** before creating multiple PRs
- **PR Creation**: Use GitHub CLI after completing a task:
  ```bash
  gh pr create --title "Task X: [Task Title]" --body "Description"
  ```

### Committing to PRs
- Keep committing to the same PR as long as the scope is maintained
- An entire task list (brief) might fit into a single PR
- If scope grows too large, discuss with human before creating new PRs

## Authentication & Context Management

### Token Refresh
```bash
# Refresh token if JWT seems expired or commands don't work
tm auth refresh

# If refresh doesn't work, reconnect context
tm context <brief url>
```

### Context Reconnection
- **When Needed**: If commands stop working or authentication fails
- **Required Information**: Brief URL (ask user if not available)
- **Best Practice**: Store brief URL at the beginning of the session
- **Command**: `tm context <brief url>`

## Integration with Git Workflow

When working with Hamster briefs, follow standard Git workflow patterns:
- Create task-specific branches: `task-XXX`
- Commit subtask work incrementally
- Create PRs after task completion
- Follow commit message standards

## Key Principles

- **Incremental Progress**: Work through subtasks one at a time
- **Quality Gates**: Always run lint and typecheck before marking tasks as done
- **Clear Communication**: Confirm with human before splitting work across multiple PRs
- **Efficient Context Gathering**: Use comma-separated IDs when viewing multiple tasks
- **Authentication Management**: Proactively refresh tokens and reconnect context when needed


--- .claude/commands/dedupe.md ---
---
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh api:*), Bash(gh issue comment:*)
description: Find duplicate GitHub issues
---

Find up to 3 likely duplicate issues for a given GitHub issue.

To do this, follow these steps precisely:

1. Use an agent to check if the Github issue (a) is closed, (b) does not need to be deduped (eg. because it is broad product feedback without a specific solution, or positive feedback), or (c) already has a duplicates comment that you made earlier. If so, do not proceed.
2. Use an agent to view a Github issue, and ask the agent to return a summary of the issue
3. Then, launch 5 parallel agents to search Github for duplicates of this issue, using diverse keywords and search approaches, using the summary from #1
4. Next, feed the results from #1 and #2 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed.
5. Finally, comment back on the issue with a list of up to three duplicate issues (or zero, if there are no likely duplicates)

Notes (be sure to tell this to your agents, too):

- Use `gh` to interact with Github, rather than web fetch
- Do not use other tools, beyond `gh` (eg. don't use other MCP servers, file edit, etc.)
- Make a todo list first
- For your comment, follow the following format precisely (assuming for this example that you found 3 suspected duplicates):

---

Found 3 possible duplicate issues:

1. <link to issue>
2. <link to issue>
3. <link to issue>

This issue will be automatically closed as a duplicate in 3 days.

- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with \[Task Master Bot\]

---

--- .claude/commands/go/ham.md ---
# Hamster (Go ham!) Run Task Workflow

This command initiates the HAM (Hamster Automated Management) workflow for task execution.

## Usage

```
/go:ham [task-id]
```

- `task-id` (optional): Specific task identifier to work on (e.g., "1", "1.2", "2.3.1")
  - If provided, start working on that specific task immediately
  - If omitted, automatically identify the next available task

## Process

When the user invokes this command, follow these steps:

### 1. Task Selection

#### If task-id is provided ($ARGUMENTS is not empty):
```bash
tm show $ARGUMENTS
```
Start working on the specified task immediately, skipping to step 3.

#### If no task-id is provided ($ARGUMENTS is empty):
```bash
tm list
```
Display all tasks with their current status to provide context.

### 2. Identify Next Task (only if no task-id provided)
Determine which task should be worked on next based on:
- Dependencies
- Priority
- Current status (pending tasks only)

### 3. Show Task Details (only if task wasn't specified in step 1)
```bash
tm show <task-id>
```
Display the full details of the identified task including:
- Title and description
- Dependencies
- Test strategy
- Subtasks (if any)

### 4. Kickoff Workflow

Based on the task type, follow the appropriate workflow:

#### For Main Tasks (e.g., "1", "2", "3")
- Review the task's subtasks
- If no subtasks exist, suggest expanding the task first
- Identify the first pending subtask
- Begin implementation following the subtask's requirements

#### For Subtasks (e.g., "1.1", "2.3")
- Mark the subtask as in-progress:
  ```bash
  tm set-status --id=<subtask-id> --status=in-progress
  ```
- Review the task details and requirements
- Check for related code files or dependencies
- Create an implementation plan
- Begin implementation following project conventions

### 5. Implementation Guidelines

Follow these principles during implementation:

1. **Understand First**: Read related files and understand the current architecture
2. **Plan**: Create a mental model or brief plan before coding
3. **Follow Conventions**: Adhere to project structure and coding standards
4. **Test As You Go**: Validate changes incrementally
5. **Stay Focused**: Complete the current subtask before moving to the next

### 6. Task Completion

When the subtask is complete:
```bash
tm set-status --id=<subtask-id> --status=done
```

Then automatically check for the next available task by repeating from step 2.

## Example Flows

### With Specific Task ID
```
User: "/go:ham 1.2"

1. Claude runs: tm show 1.2
   → Displays full task details
2. Claude analyzes the task and creates an implementation plan
3. Claude marks task in-progress: tm set-status --id=1.2 --status=in-progress
4. Claude begins implementation following the task requirements
5. Upon completion, Claude runs: tm set-status --id=1.2 --status=done
6. Claude automatically identifies next task with tm list
```

### Without Specific Task ID (Auto-discovery)
```
User: "/go:ham"

1. Claude runs: tm list
2. Claude identifies next available task (e.g., 1.2)
3. Claude runs: tm show 1.2
   → Displays full task details
4. Claude analyzes the task and creates an implementation plan
5. Claude marks task in-progress: tm set-status --id=1.2 --status=in-progress
6. Claude begins implementation following the task requirements
7. Upon completion, Claude runs: tm set-status --id=1.2 --status=done
8. Claude automatically identifies next task with tm list
```

## Notes

- Always verify task dependencies are complete before starting
- If a task is blocked, mark it as such and move to the next available task
- Keep the user informed of progress at each major step
- Ask for clarification if task requirements are unclear
- Follow the project's CLAUDE.md and .cursor/rules/* guidelines at all times
- Unlike the usual Taskmaster process, do not bother using update-task nor update-subtask as they do not work with Hamster tasks yet.

- Use only `tm list`, `tm show <sub/task id>` and `tm set status` - other commands don't yet work with it.
- Do not use the MCP tools when connected with Hamster briefs - that is not yet up to date.
- Use `.cursor/rules/git_workflow.mdc` as a guide for the workflow
- When starting a task, mark it as in-progress. You can mark multiple task statuses at once with comma separation (i.e. `tm set-status -i 1,1.1 -s in-progress`)
- Read the task, then if it has subtasks, begin implementing the subtasks one at a time.
- When the subtask is done, run lint and typecheck, mark the task as done if it passes, and commit.
- Continue until all subtasks are done, then run a final lint and typecheck (`npm lint` and `npm typecheck`) and create a PR using `gh` cli for that Task.
- Keep committing to the same PR as long as the scope is maintained. An entire task list (brief) might fit into a single PR but not if it ends up being huge. It is preferred for everything to land in one PR if it is possible, otherwise commit to different PRs that build on top of the previous ones. Confirm with the human when doing this.
- When the parent task is completed, ensure you mark is as done.
- When the first task is done, repeat this process for all tasks until all tasks are done.
- If you run into an issue where the JWT seems expired or commands don't work, ensure you use `tm auth refresh` to refresh the token and if that does not work, use `tm context <brief url>` to reconnect the context. If you do not have the brief url, ask the user for it (perhaps use it at the beginning)

You're a fast hamster. Go go go.

--- .claude/commands/go/pr-comments.md ---
Fix PR review comments: PR # $ARGUMENTS

This command collects all review comments from a GitHub PR (including CodeRabbit, human reviewers, and other bots), consolidates them by author and severity, shows them to you for approval, then implements the approved fixes.

Steps:

1. **Collect PR comments**
   - Run: `gh pr view $ARGUMENTS --comments` to get ALL comments (no truncation)
   - Parse and extract all review comments from:
     - PR review comments (file-level)
     - General comments
     - Review threads
   - Include author information for each comment
   - IMPORTANT: Do NOT use `head`, `tail`, or any truncation - we need complete comment history

2. **Consolidate comments**
   - Group comments by:
     - Author (CodeRabbit, human reviewers, other bots)
     - Severity (🚨 Critical, ⚠️ Important, 💡 Suggestion, ℹ️ Info)
     - Category (Security, Performance, Best Practices, Style, etc.)
   - Remove duplicates and group similar issues
   - Present in a clear, numbered list format showing author for each

3. **Show consolidated issues for approval**
   - Display the organized list with:
     - Issue number for reference
     - Severity indicator
     - File location
     - Description
     - Suggested fix
   - Ask: "Which issues would you like me to fix? (Enter numbers separated by commas, or 'all' for everything)"
   - Wait for user confirmation

4. **Implement approved fixes**
   - For each approved issue:
     - Read the relevant file(s)
     - Implement the suggested fix
     - Log what was changed

5. **Validate changes**
   - Run: `pnpm typecheck`
   - If fails: review errors, fix them, retry
   - Run: `pnpm lint`
   - If fails: review errors, fix them, retry
   - Continue until both pass

6. **Commit and push**
   - Stage changes: `git add .`
   - Create commit: `git commit -m "fix: address review comments from PR #$ARGUMENTS"`
   - Push: `git push`
   - Confirm completion with summary of fixes applied

Notes:
- If no review comments found, inform user and exit
- If typecheck/lint fails after fixes, show errors and ask for guidance
- Keep fixes focused on reviewers' specific suggestions
- Preserve existing code style and patterns
- Group related fixes in the commit message if many changes
- Treat all reviewers equally - human and bot feedback both matter

You previously got all the PR comments in a temporary JSON file and then ran something like this;

cat > /tmp/parse_comments.js << 'EOF'
const fs = require('fs');
const comments = JSON.parse(fs.readFileSync('/tmp/all-pr-comments.json', 'utf8'));

const byFile = {};
const bySeverity = {
  critical: [],
  important: [],
  suggestion: [],
  info: []
};

comments.forEach((c, idx) => {
  const file = c.path;
  const author = c.user.login;
  const line = c.line || c.original_line || 'N/A';
  const body = c.body;
  
  if (!byFile[file]) byFile[file] = [];
  
  const comment = {
    num: idx + 1,
    author,
    line,
    body: body.substring(0, 200) + (body.length > 200 ? '...' : ''),
    fullBody: body
  };
  
  byFile[file].push(comment);
  
  // Categorize by severity
  const lower = body.toLowerCase();
  if (lower.includes('critical') || lower.includes('security') || lower.includes('bug:')) {
    bySeverity.critical.push({...comment, file});
  } else if (lower.includes('important') || lower.includes('error') || lower.includes('fail')) {
    bySeverity.important.push({...comment, file});
  } else if (lower.includes('suggestion') || lower.includes('consider') || lower.includes('recommend')) {
    bySeverity.suggestion.push({...comment, file});
  } else {
    bySeverity.info.push({...comment, file});
  }
});

console.log('\n=== SUMMARY BY SEVERITY ===\n');
console.log(`🚨 Critical: ${bySeverity.critical.length}`);
console.log(`⚠️  Important: ${bySeverity.important.length}`);
console.log(`💡 Suggestion: ${bySeverity.suggestion.length}`);
console.log(`ℹ️  Info: ${bySeverity.info.length}`);

console.log('\n=== SUMMARY BY FILE ===\n');
Object.entries(byFile)
  .sort((a, b) => b[1].length - a[1].length)
  .forEach(([file, comments]) => {
    console.log(`${file}: ${comments.length} comments`);
  });

console.log('\n=== CRITICAL ISSUES ===\n');
bySeverity.critical.forEach(c => {
  console.log(`\n#${c.num} [${c.author}] ${c.file}:${c.line}`);
  console.log(c.body);
});

console.log('\n=== IMPORTANT ISSUES ===\n');
bySeverity.important.slice(0, 10).forEach(c => {
  console.log(`\n#${c.num} [${c.author}] ${c.file}:${c.line}`);
  console.log(c.body);
});
EOF
node /tmp/parse_comments.js

And got a nice report you could act on.

--- .github/PULL_REQUEST_TEMPLATE.md ---
# What type of PR is this?
<!-- Check one -->

 - [ ] 🐛 Bug fix
 - [ ] ✨ Feature
 - [ ] 🔌 Integration
 - [ ] 📝 Docs
 - [ ] 🧹 Refactor
 - [ ] Other:
## Description
<!-- What does this PR do? -->

## Related Issues
<!-- Link issues: Fixes #123 -->

## How to Test This
<!-- Quick steps to verify the changes work -->
```bash
# Example commands or steps
```

**Expected result:**
<!-- What should happen? -->

## Contributor Checklist

- [ ] Created changeset: `npm run changeset`
- [ ] Tests pass: `npm test`
- [ ] Format check passes: `npm run format-check` (or `npm run format` to fix)
- [ ] Addressed CodeRabbit comments (if any)
- [ ] Linked related issues (if any)
- [ ] Manually tested the changes

## Changelog Entry
<!-- One line describing the change for users -->
<!-- Example: "Added Kiro IDE integration with automatic task status updates" -->

---

### For Maintainers

- [ ] PR title follows conventional commits
- [ ] Target branch correct
- [ ] Labels added
- [ ] Milestone assigned (if applicable)


--- .github/ISSUE_TEMPLATE/bug_report.md ---
---
name: Bug report
about: Create a report to help us improve
title: 'bug: '
labels: bug
assignees: ''
---

### Description

Detailed description of the problem, including steps to reproduce the issue.

### Steps to Reproduce

1. Step-by-step instructions to reproduce the issue
2. Include command examples or UI interactions

### Expected Behavior

Describe clearly what the expected outcome or behavior should be.

### Actual Behavior

Describe clearly what the actual outcome or behavior is.

### Screenshots or Logs

Provide screenshots, logs, or error messages if applicable.

### Environment

- Task Master version:
- Node.js version:
- Operating system:
- IDE (if applicable):

### Additional Context

Any additional information or context that might help diagnose the issue.


--- .github/PULL_REQUEST_TEMPLATE/bugfix.md ---
## 🐛 Bug Fix

### 🔍 Bug Description
<!-- Describe the bug -->

### 🔗 Related Issues
<!-- Fixes #123 -->

### ✨ Solution
<!-- How does this PR fix the bug? -->

## How to Test

### Steps that caused the bug:
1. 
2. 

**Before fix:** 
**After fix:** 

### Quick verification:
```bash
# Commands to verify the fix
```

## Contributor Checklist
- [ ] Created changeset: `npm run changeset`
- [ ] Tests pass: `npm test`
- [ ] Format check passes: `npm run format-check`
- [ ] Addressed CodeRabbit comments
- [ ] Added unit tests (if applicable)
- [ ] Manually verified the fix works

---

### For Maintainers
- [ ] Root cause identified
- [ ] Fix doesn't introduce new issues
- [ ] CI passes

--- .github/ISSUE_TEMPLATE/enhancements---feature-requests.md ---
---
name: Enhancements & feature requests
about: Suggest an idea for this project
title: 'feat: '
labels: enhancement
assignees: ''
---

> "Direct quote or clear summary of user request or need or user story."

### Motivation

Detailed explanation of why this feature is important. Describe the problem it solves or the benefit it provides.

### Proposed Solution

Clearly describe the proposed feature, including:

- High-level overview of the feature
- Relevant technologies or integrations
- How it fits into the existing workflow or architecture

### High-Level Workflow

1. Step-by-step description of how the feature will be implemented
2. Include necessary intermediate milestones

### Key Elements

- Bullet-point list of technical or UX/UI enhancements
- Mention specific integrations or APIs
- Highlight changes needed in existing data models or commands

### Example Workflow

Provide a clear, concrete example demonstrating the feature:

```shell
$ task-master [action]
→ Expected response/output
```

### Implementation Considerations

- Dependencies on external components or APIs
- Backward compatibility requirements
- Potential performance impacts or resource usage

### Out of Scope (Future Considerations)

Clearly list any features or improvements not included but relevant for future iterations.


--- .github/PULL_REQUEST_TEMPLATE/feature.md ---
## ✨ New Feature

### 📋 Feature Description
<!-- Brief description -->

### 🎯 Problem Statement
<!-- What problem does this feature solve? Why is it needed? -->

### 💡 Solution
<!-- How does this feature solve the problem? What's the approach? -->

### 🔗 Related Issues
<!-- Link related issues: Fixes #123, Part of #456 -->

## How to Use It

### Quick Start
```bash
# Basic usage example
```

### Example
<!-- Show a real use case -->
```bash
# Practical example
```

**What you should see:**
<!-- Expected behavior -->

## Contributor Checklist
- [ ] Created changeset: `npm run changeset`
- [ ] Tests pass: `npm test`
- [ ] Format check passes: `npm run format-check`
- [ ] Addressed CodeRabbit comments
- [ ] Added tests for new functionality
- [ ] Manually tested in CLI mode
- [ ] Manually tested in MCP mode (if applicable)

## Changelog Entry
<!-- One-liner for release notes -->

---

### For Maintainers

- [ ] Feature aligns with project vision
- [ ] CIs pass
- [ ] Changeset file exists


--- .github/ISSUE_TEMPLATE/feedback.md ---
---
name: Feedback
about: Give us specific feedback on the product/approach/tech
title: 'feedback: '
labels: feedback
assignees: ''
---

### Feedback Summary

Provide a clear summary or direct quote from user feedback.

### User Context

Explain the user's context or scenario in which this feedback was provided.

### User Impact

Describe how this feedback affects the user experience or workflow.

### Suggestions

Provide any initial thoughts, potential solutions, or improvements based on the feedback.

### Relevant Screenshots or Examples

Attach screenshots, logs, or examples that illustrate the feedback.

### Additional Notes

Any additional context or related information.


--- .github/PULL_REQUEST_TEMPLATE/integration.md ---
# 🔌 New Integration

## What tool/IDE is being integrated?

<!-- Name and brief description -->

## What can users do with it?

<!-- Key benefits -->

## How to Enable

### Setup

```bash
task-master rules add [name]
# Any other setup steps
```

### Example Usage

<!-- Show it in action -->

```bash
# Real example
```

### Natural Language Hooks (if applicable)

```
"When tests pass, mark task as done"
# Other examples
```

## Contributor Checklist

- [ ] Created changeset: `npm run changeset`
- [ ] Tests pass: `npm test`
- [ ] Format check passes: `npm run format-check`
- [ ] Addressed CodeRabbit comments
- [ ] Integration fully tested with target tool/IDE
- [ ] Error scenarios tested
- [ ] Added integration tests
- [ ] Documentation includes setup guide
- [ ] Examples are working and clear

---

## For Maintainers

- [ ] Integration stability verified
- [ ] Documentation comprehensive
- [ ] Examples working


--- .kiro/steering/dev_workflow.md ---
---
inclusion: always
---

# Taskmaster Development Workflow

This guide outlines the standard process for using Taskmaster to manage software development projects. It is written as a set of instructions for you, the AI agent.

- **Your Default Stance**: For most projects, the user can work directly within the `master` task context. Your initial actions should operate on this default context unless a clear pattern for multi-context work emerges.
- **Your Goal**: Your role is to elevate the user's workflow by intelligently introducing advanced features like **Tagged Task Lists** when you detect the appropriate context. Do not force tags on the user; suggest them as a helpful solution to a specific need.

## The Basic Loop
The fundamental development cycle you will facilitate is:
1.  **`list`**: Show the user what needs to be done.
2.  **`next`**: Help the user decide what to work on.
3.  **`show <id>`**: Provide details for a specific task.
4.  **`expand <id>`**: Break down a complex task into smaller, manageable subtasks.
5.  **Implement**: The user writes the code and tests.
6.  **`update-subtask`**: Log progress and findings on behalf of the user.
7.  **`set-status`**: Mark tasks and subtasks as `done` as work is completed.
8.  **Repeat**.

All your standard command executions should operate on the user's current task context, which defaults to `master`.

---

## Standard Development Workflow Process

### Simple Workflow (Default Starting Point)

For new projects or when users are getting started, operate within the `master` tag context:

-   Start new projects by running `initialize_project` tool / `task-master init` or `parse_prd` / `task-master parse-prd --input='<prd-file.txt>'` (see @`taskmaster.md`) to generate initial tasks.json with tagged structure
-   Configure rule sets during initialization with `--rules` flag (e.g., `task-master init --rules kiro,windsurf`) or manage them later with `task-master rules add/remove` commands  
-   Begin coding sessions with `get_tasks` / `task-master list` (see @`taskmaster.md`) to see current tasks, status, and IDs
-   Determine the next task to work on using `next_task` / `task-master next` (see @`taskmaster.md`)
-   Analyze task complexity with `analyze_project_complexity` / `task-master analyze-complexity --research` (see @`taskmaster.md`) before breaking down tasks
-   Review complexity report using `complexity_report` / `task-master complexity-report` (see @`taskmaster.md`)
-   Select tasks based on dependencies (all marked 'done'), priority level, and ID order
-   View specific task details using `get_task` / `task-master show <id>` (see @`taskmaster.md`) to understand implementation requirements
-   Break down complex tasks using `expand_task` / `task-master expand --id=<id> --force --research` (see @`taskmaster.md`) with appropriate flags like `--force` (to replace existing subtasks) and `--research`
-   Implement code following task details, dependencies, and project standards
-   Mark completed tasks with `set_task_status` / `task-master set-status --id=<id> --status=done` (see @`taskmaster.md`)
-   Update dependent tasks when implementation differs from original plan using `update` / `task-master update --from=<id> --prompt="..."` or `update_task` / `task-master update-task --id=<id> --prompt="..."` (see @`taskmaster.md`)

---

## Leveling Up: Agent-Led Multi-Context Workflows

While the basic workflow is powerful, your primary opportunity to add value is by identifying when to introduce **Tagged Task Lists**. These patterns are your tools for creating a more organized and efficient development environment for the user, especially if you detect agentic or parallel development happening across the same session.

**Critical Principle**: Most users should never see a difference in their experience. Only introduce advanced workflows when you detect clear indicators that the project has evolved beyond simple task management.

### When to Introduce Tags: Your Decision Patterns

Here are the patterns to look for. When you detect one, you should propose the corresponding workflow to the user.

#### Pattern 1: Simple Git Feature Branching
This is the most common and direct use case for tags.

- **Trigger**: The user creates a new git branch (e.g., `git checkout -b feature/user-auth`).
- **Your Action**: Propose creating a new tag that mirrors the branch name to isolate the feature's tasks from `master`.
- **Your Suggested Prompt**: *"I see you've created a new branch named 'feature/user-auth'. To keep all related tasks neatly organized and separate from your main list, I can create a corresponding task tag for you. This helps prevent merge conflicts in your `tasks.json` file later. Shall I create the 'feature-user-auth' tag?"*
- **Tool to Use**: `task-master add-tag --from-branch`

#### Pattern 2: Team Collaboration
- **Trigger**: The user mentions working with teammates (e.g., "My teammate Alice is handling the database schema," or "I need to review Bob's work on the API.").
- **Your Action**: Suggest creating a separate tag for the user's work to prevent conflicts with shared master context.
- **Your Suggested Prompt**: *"Since you're working with Alice, I can create a separate task context for your work to avoid conflicts. This way, Alice can continue working with the master list while you have your own isolated context. When you're ready to merge your work, we can coordinate the tasks back to master. Shall I create a tag for your current work?"*
- **Tool to Use**: `task-master add-tag my-work --copy-from-current --description="My tasks while collaborating with Alice"`

#### Pattern 3: Experiments or Risky Refactors
- **Trigger**: The user wants to try something that might not be kept (e.g., "I want to experiment with switching our state management library," or "Let's refactor the old API module, but I want to keep the current tasks as a reference.").
- **Your Action**: Propose creating a sandboxed tag for the experimental work.
- **Your Suggested Prompt**: *"This sounds like a great experiment. To keep these new tasks separate from our main plan, I can create a temporary 'experiment-zustand' tag for this work. If we decide not to proceed, we can simply delete the tag without affecting the main task list. Sound good?"*
- **Tool to Use**: `task-master add-tag experiment-zustand --description="Exploring Zustand migration"`

#### Pattern 4: Large Feature Initiatives (PRD-Driven)
This is a more structured approach for significant new features or epics.

- **Trigger**: The user describes a large, multi-step feature that would benefit from a formal plan.
- **Your Action**: Propose a comprehensive, PRD-driven workflow.
- **Your Suggested Prompt**: *"This sounds like a significant new feature. To manage this effectively, I suggest we create a dedicated task context for it. Here's the plan: I'll create a new tag called 'feature-xyz', then we can draft a Product Requirements Document (PRD) together to scope the work. Once the PRD is ready, I'll automatically generate all the necessary tasks within that new tag. How does that sound?"*
- **Your Implementation Flow**:
    1.  **Create an empty tag**: `task-master add-tag feature-xyz --description "Tasks for the new XYZ feature"`. You can also start by creating a git branch if applicable, and then create the tag from that branch.
    2.  **Collaborate & Create PRD**: Work with the user to create a detailed PRD file (e.g., `.taskmaster/docs/feature-xyz-prd.txt`).
    3.  **Parse PRD into the new tag**: `task-master parse-prd .taskmaster/docs/feature-xyz-prd.txt --tag feature-xyz`
    4.  **Prepare the new task list**: Follow up by suggesting `analyze-complexity` and `expand-all` for the newly created tasks within the `feature-xyz` tag.

#### Pattern 5: Version-Based Development
Tailor your approach based on the project maturity indicated by tag names.

- **Prototype/MVP Tags** (`prototype`, `mvp`, `poc`, `v0.x`):
  - **Your Approach**: Focus on speed and functionality over perfection
  - **Task Generation**: Create tasks that emphasize "get it working" over "get it perfect"
  - **Complexity Level**: Lower complexity, fewer subtasks, more direct implementation paths
  - **Research Prompts**: Include context like "This is a prototype - prioritize speed and basic functionality over optimization"
  - **Example Prompt Addition**: *"Since this is for the MVP, I'll focus on tasks that get core functionality working quickly rather than over-engineering."*

- **Production/Mature Tags** (`v1.0+`, `production`, `stable`):
  - **Your Approach**: Emphasize robustness, testing, and maintainability
  - **Task Generation**: Include comprehensive error handling, testing, documentation, and optimization
  - **Complexity Level**: Higher complexity, more detailed subtasks, thorough implementation paths
  - **Research Prompts**: Include context like "This is for production - prioritize reliability, performance, and maintainability"
  - **Example Prompt Addition**: *"Since this is for production, I'll ensure tasks include proper error handling, testing, and documentation."*

### Advanced Workflow (Tag-Based & PRD-Driven)

**When to Transition**: Recognize when the project has evolved (or has initiated a project which existing code) beyond simple task management. Look for these indicators:
- User mentions teammates or collaboration needs
- Project has grown to 15+ tasks with mixed priorities
- User creates feature branches or mentions major initiatives
- User initializes Taskmaster on an existing, complex codebase
- User describes large features that would benefit from dedicated planning

**Your Role in Transition**: Guide the user to a more sophisticated workflow that leverages tags for organization and PRDs for comprehensive planning.

#### Master List Strategy (High-Value Focus)
Once you transition to tag-based workflows, the `master` tag should ideally contain only:
- **High-level deliverables** that provide significant business value
- **Major milestones** and epic-level features
- **Critical infrastructure** work that affects the entire project
- **Release-blocking** items

**What NOT to put in master**:
- Detailed implementation subtasks (these go in feature-specific tags' parent tasks)
- Refactoring work (create dedicated tags like `refactor-auth`)
- Experimental features (use `experiment-*` tags)
- Team member-specific tasks (use person-specific tags)

#### PRD-Driven Feature Development

**For New Major Features**:
1. **Identify the Initiative**: When user describes a significant feature
2. **Create Dedicated Tag**: `add_tag feature-[name] --description="[Feature description]"`
3. **Collaborative PRD Creation**: Work with user to create comprehensive PRD in `.taskmaster/docs/feature-[name]-prd.txt`
4. **Parse & Prepare**: 
   - `parse_prd .taskmaster/docs/feature-[name]-prd.txt --tag=feature-[name]`
   - `analyze_project_complexity --tag=feature-[name] --research`
   - `expand_all --tag=feature-[name] --research`
5. **Add Master Reference**: Create a high-level task in `master` that references the feature tag

**For Existing Codebase Analysis**:
When users initialize Taskmaster on existing projects:
1. **Codebase Discovery**: Use your native tools for producing deep context about the code base. You may use `research` tool with `--tree` and `--files` to collect up to date information using the existing architecture as context.
2. **Collaborative Assessment**: Work with user to identify improvement areas, technical debt, or new features
3. **Strategic PRD Creation**: Co-author PRDs that include:
   - Current state analysis (based on your codebase research)
   - Proposed improvements or new features
   - Implementation strategy considering existing code
4. **Tag-Based Organization**: Parse PRDs into appropriate tags (`refactor-api`, `feature-dashboard`, `tech-debt`, etc.)
5. **Master List Curation**: Keep only the most valuable initiatives in master

The parse-prd's `--append` flag enables the user to parse multiple PRDs within tags or across tags. PRDs should be focused and the number of tasks they are parsed into should be strategically chosen relative to the PRD's complexity and level of detail.

### Workflow Transition Examples

**Example 1: Simple → Team-Based**
```
User: "Alice is going to help with the API work"
Your Response: "Great! To avoid conflicts, I'll create a separate task context for your work. Alice can continue with the master list while you work in your own context. When you're ready to merge, we can coordinate the tasks back together."
Action: add_tag my-api-work --copy-from-current --description="My API tasks while collaborating with Alice"
```

**Example 2: Simple → PRD-Driven**
```
User: "I want to add a complete user dashboard with analytics, user management, and reporting"
Your Response: "This sounds like a major feature that would benefit from detailed planning. Let me create a dedicated context for this work and we can draft a PRD together to ensure we capture all requirements."
Actions: 
1. add_tag feature-dashboard --description="User dashboard with analytics and management"
2. Collaborate on PRD creation
3. parse_prd dashboard-prd.txt --tag=feature-dashboard
4. Add high-level "User Dashboard" task to master
```

**Example 3: Existing Project → Strategic Planning**
```
User: "I just initialized Taskmaster on my existing React app. It's getting messy and I want to improve it."
Your Response: "Let me research your codebase to understand the current architecture, then we can create a strategic plan for improvements."
Actions:
1. research "Current React app architecture and improvement opportunities" --tree --files=src/
2. Collaborate on improvement PRD based on findings
3. Create tags for different improvement areas (refactor-components, improve-state-management, etc.)
4. Keep only major improvement initiatives in master
```

---

## Primary Interaction: MCP Server vs. CLI

Taskmaster offers two primary ways to interact:

1.  **MCP Server (Recommended for Integrated Tools)**:
    - For AI agents and integrated development environments (like Kiro), interacting via the **MCP server is the preferred method**.
    - The MCP server exposes Taskmaster functionality through a set of tools (e.g., `get_tasks`, `add_subtask`).
    - This method offers better performance, structured data exchange, and richer error handling compared to CLI parsing.
    - Refer to @`mcp.md` for details on the MCP architecture and available tools.
    - A comprehensive list and description of MCP tools and their corresponding CLI commands can be found in @`taskmaster.md`.
    - **Restart the MCP server** if core logic in `scripts/modules` or MCP tool/direct function definitions change.
    - **Note**: MCP tools fully support tagged task lists with complete tag management capabilities.

2.  **`task-master` CLI (For Users & Fallback)**:
    - The global `task-master` command provides a user-friendly interface for direct terminal interaction.
    - It can also serve as a fallback if the MCP server is inaccessible or a specific function isn't exposed via MCP.
    - Install globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`.
    - The CLI commands often mirror the MCP tools (e.g., `task-master list` corresponds to `get_tasks`).
    - Refer to @`taskmaster.md` for a detailed command reference.
    - **Tagged Task Lists**: CLI fully supports the new tagged system with seamless migration.

## How the Tag System Works (For Your Reference)

- **Data Structure**: Tasks are organized into separate contexts (tags) like "master", "feature-branch", or "v2.0".
- **Silent Migration**: Existing projects automatically migrate to use a "master" tag with zero disruption.
- **Context Isolation**: Tasks in different tags are completely separate. Changes in one tag do not affect any other tag.
- **Manual Control**: The user is always in control. There is no automatic switching. You facilitate switching by using `use-tag <name>`.
- **Full CLI & MCP Support**: All tag management commands are available through both the CLI and MCP tools for you to use. Refer to @`taskmaster.md` for a full command list.

---

## Task Complexity Analysis

-   Run `analyze_project_complexity` / `task-master analyze-complexity --research` (see @`taskmaster.md`) for comprehensive analysis
-   Review complexity report via `complexity_report` / `task-master complexity-report` (see @`taskmaster.md`) for a formatted, readable version.
-   Focus on tasks with highest complexity scores (8-10) for detailed breakdown
-   Use analysis results to determine appropriate subtask allocation
-   Note that reports are automatically used by the `expand_task` tool/command

## Task Breakdown Process

-   Use `expand_task` / `task-master expand --id=<id>`. It automatically uses the complexity report if found, otherwise generates default number of subtasks.
-   Use `--num=<number>` to specify an explicit number of subtasks, overriding defaults or complexity report recommendations.
-   Add `--research` flag to leverage Perplexity AI for research-backed expansion.
-   Add `--force` flag to clear existing subtasks before generating new ones (default is to append).
-   Use `--prompt="<context>"` to provide additional context when needed.
-   Review and adjust generated subtasks as necessary.
-   Use `expand_all` tool or `task-master expand --all` to expand multiple pending tasks at once, respecting flags like `--force` and `--research`.
-   If subtasks need complete replacement (regardless of the `--force` flag on `expand`), clear them first with `clear_subtasks` / `task-master clear-subtasks --id=<id>`.

## Implementation Drift Handling

-   When implementation differs significantly from planned approach
-   When future tasks need modification due to current implementation choices
-   When new dependencies or requirements emerge
-   Use `update` / `task-master update --from=<futureTaskId> --prompt='<explanation>\nUpdate context...' --research` to update multiple future tasks.
-   Use `update_task` / `task-master update-task --id=<taskId> --prompt='<explanation>\nUpdate context...' --research` to update a single specific task.

## Task Status Management

-   Use 'pending' for tasks ready to be worked on
-   Use 'done' for completed and verified tasks
-   Use 'deferred' for postponed tasks
-   Add custom status values as needed for project-specific workflows

## Task Structure Fields

- **id**: Unique identifier for the task (Example: `1`, `1.1`)
- **title**: Brief, descriptive title (Example: `"Initialize Repo"`)
- **description**: Concise summary of what the task involves (Example: `"Create a new repository, set up initial structure."`)
- **status**: Current state of the task (Example: `"pending"`, `"done"`, `"deferred"`)
- **dependencies**: IDs of prerequisite tasks (Example: `[1, 2.1]`)
    - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending)
    - This helps quickly identify which prerequisite tasks are blocking work
- **priority**: Importance level (Example: `"high"`, `"medium"`, `"low"`)
- **details**: In-depth implementation instructions (Example: `"Use GitHub client ID/secret, handle callback, set session token."`) 
- **testStrategy**: Verification approach (Example: `"Deploy and call endpoint to confirm 'Hello World' response."`) 
- **subtasks**: List of smaller, more specific tasks (Example: `[{"id": 1, "title": "Configure OAuth", ...}]`) 
- Refer to task structure details (previously linked to `tasks.md`).

## Configuration Management (Updated)

Taskmaster configuration is managed through two main mechanisms:

1.  **`.taskmaster/config.json` File (Primary):**
    *   Located in the project root directory.
    *   Stores most configuration settings: AI model selections (main, research, fallback), parameters (max tokens, temperature), logging level, default subtasks/priority, project name, etc.
    *   **Tagged System Settings**: Includes `global.defaultTag` (defaults to "master") and `tags` section for tag management configuration.
    *   **Managed via `task-master models --setup` command.** Do not edit manually unless you know what you are doing.
    *   **View/Set specific models via `task-master models` command or `models` MCP tool.**
    *   Created automatically when you run `task-master models --setup` for the first time or during tagged system migration.

2.  **Environment Variables (`.env` / `mcp.json`):**
    *   Used **only** for sensitive API keys and specific endpoint URLs.
    *   Place API keys (one per provider) in a `.env` file in the project root for CLI usage.
    *   For MCP/Kiro integration, configure these keys in the `env` section of `.kiro/mcp.json`.
    *   Available keys/variables: See `assets/env.example` or the Configuration section in the command reference (previously linked to `taskmaster.md`).

3.  **`.taskmaster/state.json` File (Tagged System State):**
    *   Tracks current tag context and migration status.
    *   Automatically created during tagged system migration.
    *   Contains: `currentTag`, `lastSwitched`, `migrationNoticeShown`.

**Important:** Non-API key settings (like model selections, `MAX_TOKENS`, `TASKMASTER_LOG_LEVEL`) are **no longer configured via environment variables**. Use the `task-master models` command (or `--setup` for interactive configuration) or the `models` MCP tool.
**If AI commands FAIL in MCP** verify that the API key for the selected provider is present in the `env` section of `.kiro/mcp.json`.
**If AI commands FAIL in CLI** verify that the API key for the selected provider is present in the `.env` file in the root of the project.

## Rules Management

Taskmaster supports multiple AI coding assistant rule sets that can be configured during project initialization or managed afterward:

- **Available Profiles**: Claude Code, Cline, Codex, Kiro, Roo Code, Trae, Windsurf (claude, cline, codex, kiro, roo, trae, windsurf)
- **During Initialization**: Use `task-master init --rules kiro,windsurf` to specify which rule sets to include
- **After Initialization**: Use `task-master rules add <profiles>` or `task-master rules remove <profiles>` to manage rule sets
- **Interactive Setup**: Use `task-master rules setup` to launch an interactive prompt for selecting rule profiles
- **Default Behavior**: If no `--rules` flag is specified during initialization, all available rule profiles are included
- **Rule Structure**: Each profile creates its own directory (e.g., `.kiro/steering`, `.roo/rules`) with appropriate configuration files

## Determining the Next Task

- Run `next_task` / `task-master next` to show the next task to work on.
- The command identifies tasks with all dependencies satisfied
- Tasks are prioritized by priority level, dependency count, and ID
- The command shows comprehensive task information including:
    - Basic task details and description
    - Implementation details
    - Subtasks (if they exist)
    - Contextual suggested actions
- Recommended before starting any new development work
- Respects your project's dependency structure
- Ensures tasks are completed in the appropriate sequence
- Provides ready-to-use commands for common task actions

## Viewing Specific Task Details

- Run `get_task` / `task-master show <id>` to view a specific task.
- Use dot notation for subtasks: `task-master show 1.2` (shows subtask 2 of task 1)
- Displays comprehensive information similar to the next command, but for a specific task
- For parent tasks, shows all subtasks and their current status
- For subtasks, shows parent task information and relationship
- Provides contextual suggested actions appropriate for the specific task
- Useful for examining task details before implementation or checking status

## Managing Task Dependencies

- Use `add_dependency` / `task-master add-dependency --id=<id> --depends-on=<id>` to add a dependency.
- Use `remove_dependency` / `task-master remove-dependency --id=<id> --depends-on=<id>` to remove a dependency.
- The system prevents circular dependencies and duplicate dependency entries
- Dependencies are checked for existence before being added or removed
- Task files are automatically regenerated after dependency changes
- Dependencies are visualized with status indicators in task listings and files

## Task Reorganization

- Use `move_task` / `task-master move --from=<id> --to=<id>` to move tasks or subtasks within the hierarchy
- This command supports several use cases:
  - Moving a standalone task to become a subtask (e.g., `--from=5 --to=7`)
  - Moving a subtask to become a standalone task (e.g., `--from=5.2 --to=7`) 
  - Moving a subtask to a different parent (e.g., `--from=5.2 --to=7.3`)
  - Reordering subtasks within the same parent (e.g., `--from=5.2 --to=5.4`)
  - Moving a task to a new, non-existent ID position (e.g., `--from=5 --to=25`)
  - Moving multiple tasks at once using comma-separated IDs (e.g., `--from=10,11,12 --to=16,17,18`)
- The system includes validation to prevent data loss:
  - Allows moving to non-existent IDs by creating placeholder tasks
  - Prevents moving to existing task IDs that have content (to avoid overwriting)
  - Validates source tasks exist before attempting to move them
- The system maintains proper parent-child relationships and dependency integrity
- Task files are automatically regenerated after the move operation
- This provides greater flexibility in organizing and refining your task structure as project understanding evolves
- This is especially useful when dealing with potential merge conflicts arising from teams creating tasks on separate branches. Solve these conflicts very easily by moving your tasks and keeping theirs.

## Iterative Subtask Implementation

Once a task has been broken down into subtasks using `expand_task` or similar methods, follow this iterative process for implementation:

1.  **Understand the Goal (Preparation):**
    *   Use `get_task` / `task-master show <subtaskId>` (see @`taskmaster.md`) to thoroughly understand the specific goals and requirements of the subtask.

2.  **Initial Exploration & Planning (Iteration 1):**
    *   This is the first attempt at creating a concrete implementation plan.
    *   Explore the codebase to identify the precise files, functions, and even specific lines of code that will need modification.
    *   Determine the intended code changes (diffs) and their locations.
    *   Gather *all* relevant details from this exploration phase.

3.  **Log the Plan:**
    *   Run `update_subtask` / `task-master update-subtask --id=<subtaskId> --prompt='<detailed plan>'`.
    *   Provide the *complete and detailed* findings from the exploration phase in the prompt. Include file paths, line numbers, proposed diffs, reasoning, and any potential challenges identified. Do not omit details. The goal is to create a rich, timestamped log within the subtask's `details`.

4.  **Verify the Plan:**
    *   Run `get_task` / `task-master show <subtaskId>` again to confirm that the detailed implementation plan has been successfully appended to the subtask's details.

5.  **Begin Implementation:**
    *   Set the subtask status using `set_task_status` / `task-master set-status --id=<subtaskId> --status=in-progress`.
    *   Start coding based on the logged plan.

6.  **Refine and Log Progress (Iteration 2+):**
    *   As implementation progresses, you will encounter challenges, discover nuances, or confirm successful approaches.
    *   **Before appending new information**: Briefly review the *existing* details logged in the subtask (using `get_task` or recalling from context) to ensure the update adds fresh insights and avoids redundancy.
    *   **Regularly** use `update_subtask` / `task-master update-subtask --id=<subtaskId> --prompt='<update details>\n- What worked...\n- What didn't work...'` to append new findings.
    *   **Crucially, log:**
        *   What worked ("fundamental truths" discovered).
        *   What didn't work and why (to avoid repeating mistakes).
        *   Specific code snippets or configurations that were successful.
        *   Decisions made, especially if confirmed with user input.
        *   Any deviations from the initial plan and the reasoning.
    *   The objective is to continuously enrich the subtask's details, creating a log of the implementation journey that helps the AI (and human developers) learn, adapt, and avoid repeating errors.

7.  **Review & Update Rules (Post-Implementation):**
    *   Once the implementation for the subtask is functionally complete, review all code changes and the relevant chat history.
    *   Identify any new or modified code patterns, conventions, or best practices established during the implementation.
    *   Create new or update existing rules following internal guidelines (previously linked to `cursor_rules.md` and `self_improve.md`).

8.  **Mark Task Complete:**
    *   After verifying the implementation and updating any necessary rules, mark the subtask as completed: `set_task_status` / `task-master set-status --id=<subtaskId> --status=done`.

9.  **Commit Changes (If using Git):**
    *   Stage the relevant code changes and any updated/new rule files (`git add .`).
    *   Craft a comprehensive Git commit message summarizing the work done for the subtask, including both code implementation and any rule adjustments.
    *   Execute the commit command directly in the terminal (e.g., `git commit -m 'feat(module): Implement feature X for subtask <subtaskId>\n\n- Details about changes...\n- Updated rule Y for pattern Z'`).
    *   Consider if a Changeset is needed according to internal versioning guidelines (previously linked to `changeset.md`). If so, run `npm run changeset`, stage the generated file, and amend the commit or create a new one.

10. **Proceed to Next Subtask:**
    *   Identify the next subtask (e.g., using `next_task` / `task-master next`).

## Code Analysis & Refactoring Techniques

- **Top-Level Function Search**:
    - Useful for understanding module structure or planning refactors.
    - Use grep/ripgrep to find exported functions/constants:
      `rg "export (async function|function|const) \w+"` or similar patterns.
    - Can help compare functions between files during migrations or identify potential naming conflicts.

---
*This workflow provides a general guideline. Adapt it based on your specific project needs and team practices.*

--- .kiro/steering/kiro_rules.md ---
---
inclusion: always
---

- **Required Rule Structure:**
  ```markdown
  ---
  description: Clear, one-line description of what the rule enforces
  globs: path/to/files/*.ext, other/path/**/*
  alwaysApply: boolean
  ---

  - **Main Points in Bold**
    - Sub-points with details
    - Examples and explanations
  ```

- **File References:**
  - Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files
  - Example: [prisma.md](.kiro/steering/prisma.md) for rule references
  - Example: [schema.prisma](mdc:prisma/schema.prisma) for code references

- **Code Examples:**
  - Use language-specific code blocks
  ```typescript
  // ✅ DO: Show good examples
  const goodExample = true;
  
  // ❌ DON'T: Show anti-patterns
  const badExample = false;
  ```

- **Rule Content Guidelines:**
  - Start with high-level overview
  - Include specific, actionable requirements
  - Show examples of correct implementation
  - Reference existing code when possible
  - Keep rules DRY by referencing other rules

- **Rule Maintenance:**
  - Update rules when new patterns emerge
  - Add examples from actual codebase
  - Remove outdated patterns
  - Cross-reference related rules

- **Best Practices:**
  - Use bullet points for clarity
  - Keep descriptions concise
  - Include both DO and DON'T examples
  - Reference actual code over theoretical examples
  - Use consistent formatting across rules 

## Links discovered
- [filename](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/mdc:path/to/file.md)
- [filename](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/mdc:filename.md)
- [prisma.md](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/.kiro/steering/prisma.md)
- [schema.prisma](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/mdc:prisma/schema.prisma)

--- .kiro/steering/self_improve.md ---
---
inclusion: always
---

- **Rule Improvement Triggers:**
  - New code patterns not covered by existing rules
  - Repeated similar implementations across files
  - Common error patterns that could be prevented
  - New libraries or tools being used consistently
  - Emerging best practices in the codebase

- **Analysis Process:**
  - Compare new code with existing rules
  - Identify patterns that should be standardized
  - Look for references to external documentation
  - Check for consistent error handling patterns
  - Monitor test patterns and coverage

- **Rule Updates:**
  - **Add New Rules When:**
    - A new technology/pattern is used in 3+ files
    - Common bugs could be prevented by a rule
    - Code reviews repeatedly mention the same feedback
    - New security or performance patterns emerge

  - **Modify Existing Rules When:**
    - Better examples exist in the codebase
    - Additional edge cases are discovered
    - Related rules have been updated
    - Implementation details have changed

- **Example Pattern Recognition:**
  ```typescript
  // If you see repeated patterns like:
  const data = await prisma.user.findMany({
    select: { id: true, email: true },
    where: { status: 'ACTIVE' }
  });
  
  // Consider adding to [prisma.md](.kiro/steering/prisma.md):
  // - Standard select fields
  // - Common where conditions
  // - Performance optimization patterns
  ```

- **Rule Quality Checks:**
  - Rules should be actionable and specific
  - Examples should come from actual code
  - References should be up to date
  - Patterns should be consistently enforced

- **Continuous Improvement:**
  - Monitor code review comments
  - Track common development questions
  - Update rules after major refactors
  - Add links to relevant documentation
  - Cross-reference related rules

- **Rule Deprecation:**
  - Mark outdated patterns as deprecated
  - Remove rules that no longer apply
  - Update references to deprecated rules
  - Document migration paths for old patterns

- **Documentation Updates:**
  - Keep examples synchronized with code
  - Update references to external docs
  - Maintain links between related rules
  - Document breaking changes
Follow [kiro_rules.md](.kiro/steering/kiro_rules.md) for proper rule formatting and structure.


## Links discovered
- [prisma.md](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/.kiro/steering/prisma.md)
- [kiro_rules.md](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/.kiro/steering/kiro_rules.md)

--- .kiro/steering/taskmaster.md ---
---
inclusion: always
---

# Taskmaster Tool & Command Reference

This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Kiro, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback.

**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback. 

**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`.

**🏷️ Tagged Task Lists System:** Task Master now supports **tagged task lists** for multi-context task management. This allows you to maintain separate, isolated lists of tasks for different features, branches, or experiments. Existing projects are seamlessly migrated to use a default "master" tag. Most commands now support a `--tag <name>` flag to specify which context to operate on. If omitted, commands use the currently active tag.

---

## Initialization & Setup

### 1. Initialize Project (`init`)

*   **MCP Tool:** `initialize_project`
*   **CLI Command:** `task-master init [options]`
*   **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.`
*   **Key CLI Options:**
    *   `--name <name>`: `Set the name for your project in Taskmaster's configuration.`
    *   `--description <text>`: `Provide a brief description for your project.`
    *   `--version <version>`: `Set the initial version for your project, e.g., '0.1.0'.`
    *   `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.`
*   **Usage:** Run this once at the beginning of a new project.
*   **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.`
*   **Key MCP Parameters/Options:**
    *   `projectName`: `Set the name for your project.` (CLI: `--name <name>`)
    *   `projectDescription`: `Provide a brief description for your project.` (CLI: `--description <text>`)
    *   `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version <version>`)
    *   `authorName`: `Author name.` (CLI: `--author <author>`)
    *   `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`)
    *   `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`)
    *   `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`)
*   **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Kiro. Operates on the current working directory of the MCP server. 
*   **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in .taskmaster/templates/example_prd.txt. 
*   **Tagging:** Use the `--tag` option to parse the PRD into a specific, non-default tag context. If the tag doesn't exist, it will be created automatically. Example: `task-master parse-prd spec.txt --tag=new-feature`.

### 2. Parse PRD (`parse_prd`)

*   **MCP Tool:** `parse_prd`
*   **CLI Command:** `task-master parse-prd [file] [options]`
*   **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.`
*   **Key Parameters/Options:**
    *   `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input <file>`)
    *   `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to '.taskmaster/tasks/tasks.json'.` (CLI: `-o, --output <file>`)
    *   `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks <number>`)
    *   `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`)
*   **Usage:** Useful for bootstrapping a project from an existing requirements document.
*   **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `.taskmaster/templates/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`.

---

## AI Model Configuration

### 2. Manage Models (`models`)
*   **MCP Tool:** `models`
*   **CLI Command:** `task-master models [options]`
*   **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.`
*   **Key MCP Parameters/Options:**
    *   `setMain <model_id>`: `Set the primary model ID for task generation/updates.` (CLI: `--set-main <model_id>`)
    *   `setResearch <model_id>`: `Set the model ID for research-backed operations.` (CLI: `--set-research <model_id>`)
    *   `setFallback <model_id>`: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback <model_id>`)
    *   `ollama <boolean>`: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`)
    *   `openrouter <boolean>`: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`)
    *   `listAvailableModels <boolean>`: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically)
    *   `projectRoot <string>`: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically)
*   **Key CLI Options:**
    *   `--set-main <model_id>`: `Set the primary model.`
    *   `--set-research <model_id>`: `Set the research model.`
    *   `--set-fallback <model_id>`: `Set the fallback model.`
    *   `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).`
    *   `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.`
    *   `--bedrock`: `Specify that the provided model ID is for AWS Bedrock (use with --set-*).`
    *   `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.`
*   **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`.
*   **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-<role>=<model_id>` along with either `--ollama` or `--openrouter`.
*   **Notes:** Configuration is stored in `.taskmaster/config.json` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live.
*   **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them.
*   **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80. 
*   **Warning:** DO NOT MANUALLY EDIT THE .taskmaster/config.json FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback.

---

## Task Listing & Viewing

### 3. Get Tasks (`get_tasks`)

*   **MCP Tool:** `get_tasks`
*   **CLI Command:** `task-master list [options]`
*   **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.`
*   **Key Parameters/Options:**
    *   `status`: `Show only Taskmaster tasks matching this status (or multiple statuses, comma-separated), e.g., 'pending' or 'done,in-progress'.` (CLI: `-s, --status <status>`)
    *   `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`)
    *   `tag`: `Specify which tag context to list tasks from. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Get an overview of the project status, often used at the start of a work session.

### 4. Get Next Task (`next_task`)

*   **MCP Tool:** `next_task`
*   **CLI Command:** `task-master next [options]`
*   **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.`
*   **Key Parameters/Options:**
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
    *   `tag`: `Specify which tag context to use. Defaults to the current active tag.` (CLI: `--tag <name>`)
*   **Usage:** Identify what to work on next according to the plan.

### 5. Get Task Details (`get_task`)

*   **MCP Tool:** `get_task`
*   **CLI Command:** `task-master show [id] [options]`
*   **Description:** `Display detailed information for one or more specific Taskmaster tasks or subtasks by ID.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID of the Taskmaster task (e.g., '15'), subtask (e.g., '15.2'), or a comma-separated list of IDs ('1,5,10.2') you want to view.` (CLI: `[id]` positional or `-i, --id <id>`)
    *   `tag`: `Specify which tag context to get the task(s) from. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Understand the full details for a specific task. When multiple IDs are provided, a summary table is shown.
*   **CRITICAL INFORMATION** If you need to collect information from multiple tasks, use comma-separated IDs (i.e. 1,2,3) to receive an array of tasks. Do not needlessly get tasks one at a time if you need to get many as that is wasteful.

---

## Task Creation & Modification

### 6. Add Task (`add_task`)

*   **MCP Tool:** `add_task`
*   **CLI Command:** `task-master add-task [options]`
*   **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.`
*   **Key Parameters/Options:**
    *   `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt <text>`)
    *   `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies <ids>`)
    *   `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority <priority>`)
    *   `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`)
    *   `tag`: `Specify which tag context to add the task to. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Quickly add newly identified tasks during development.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 7. Add Subtask (`add_subtask`)

*   **MCP Tool:** `add_subtask`
*   **CLI Command:** `task-master add-subtask [options]`
*   **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.`
*   **Key Parameters/Options:**
    *   `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent <id>`)
    *   `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id <id>`)
    *   `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title <title>`)
    *   `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`)
    *   `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`)
    *   `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`)
    *   `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`)
    *   `generate`: `Enable Taskmaster to regenerate markdown task files after adding the subtask.` (CLI: `--generate`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Break down tasks manually or reorganize existing tasks.

### 8. Update Tasks (`update`)

*   **MCP Tool:** `update`
*   **CLI Command:** `task-master update [options]`
*   **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.`
*   **Key Parameters/Options:**
    *   `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`)
    *   `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`)
    *   `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'`
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 9. Update Task (`update_task`)

*   **MCP Tool:** `update_task`
*   **CLI Command:** `task-master update-task [options]`
*   **Description:** `Modify a specific Taskmaster task by ID, incorporating new information or changes. By default, this replaces the existing task details.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', you want to update.` (CLI: `-i, --id <id>`)
    *   `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`)
    *   `append`: `If true, appends the prompt content to the task's details with a timestamp, rather than replacing them. Behaves like update-subtask.` (CLI: `--append`)
    *   `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `tag`: `Specify which tag context the task belongs to. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Refine a specific task based on new understanding. Use `--append` to log progress without creating subtasks.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 10. Update Subtask (`update_subtask`)

*   **MCP Tool:** `update_subtask`
*   **CLI Command:** `task-master update-subtask [options]`
*   **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID of the Taskmaster subtask, e.g., '5.2', to update with new information.` (CLI: `-i, --id <id>`)
    *   `prompt`: `Required. The information, findings, or progress notes to append to the subtask's details with a timestamp.` (CLI: `-p, --prompt <text>`)
    *   `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `tag`: `Specify which tag context the subtask belongs to. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Log implementation progress, findings, and discoveries during subtask development. Each update is timestamped and appended to preserve the implementation journey.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 11. Set Task Status (`set_task_status`)

*   **MCP Tool:** `set_task_status`
*   **CLI Command:** `task-master set-status [options]`
*   **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`)
    *   `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Mark progress as tasks move through the development cycle.

### 12. Remove Task (`remove_task`)

*   **MCP Tool:** `remove_task`
*   **CLI Command:** `task-master remove-task [options]`
*   **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`)
    *   `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project.
*   **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks.

---

## Task Structure & Breakdown

### 13. Expand Task (`expand_task`)

*   **MCP Tool:** `expand_task`
*   **CLI Command:** `task-master expand [options]`
*   **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.`
*   **Key Parameters/Options:**
    *   `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`)
    *   `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`)
    *   `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`)
    *   `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`)
    *   `tag`: `Specify which tag context the task belongs to. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 14. Expand All Tasks (`expand_all`)

*   **MCP Tool:** `expand_all`
*   **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag)
*   **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.`
*   **Key Parameters/Options:**
    *   `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`)
    *   `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`)
    *   `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`)
    *   `tag`: `Specify which tag context to expand. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 15. Clear Subtasks (`clear_subtasks`)

*   **MCP Tool:** `clear_subtasks`
*   **CLI Command:** `task-master clear-subtasks [options]`
*   **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.`
*   **Key Parameters/Options:**
    *   `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using 'all'.` (CLI: `-i, --id <ids>`)
    *   `all`: `Tell Taskmaster to remove subtasks from all parent tasks.` (CLI: `--all`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Used before regenerating subtasks with `expand_task` if the previous breakdown needs replacement.

### 16. Remove Subtask (`remove_subtask`)

*   **MCP Tool:** `remove_subtask`
*   **CLI Command:** `task-master remove-subtask [options]`
*   **Description:** `Remove a subtask from its Taskmaster parent, optionally converting it into a standalone task.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID(s) of the Taskmaster subtask(s) to remove, e.g., '15.2' or '16.1,16.3'.` (CLI: `-i, --id <id>`)
    *   `convert`: `If used, Taskmaster will turn the subtask into a regular top-level task instead of deleting it.` (CLI: `-c, --convert`)
    *   `generate`: `Enable Taskmaster to regenerate markdown task files after removing the subtask.` (CLI: `--generate`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Delete unnecessary subtasks or promote a subtask to a top-level task.

### 17. Move Task (`move_task`)

*   **MCP Tool:** `move_task`
*   **CLI Command:** `task-master move [options]`
*   **Description:** `Move a task or subtask to a new position within the task hierarchy.`
*   **Key Parameters/Options:**
    *   `from`: `Required. ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated for multiple tasks.` (CLI: `--from <id>`)
    *   `to`: `Required. ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated.` (CLI: `--to <id>`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Reorganize tasks by moving them within the hierarchy. Supports various scenarios like:
    *   Moving a task to become a subtask
    *   Moving a subtask to become a standalone task
    *   Moving a subtask to a different parent
    *   Reordering subtasks within the same parent
    *   Moving a task to a new, non-existent ID (automatically creates placeholders)
    *   Moving multiple tasks at once with comma-separated IDs
*   **Validation Features:**
    *   Allows moving tasks to non-existent destination IDs (creates placeholder tasks)
    *   Prevents moving to existing task IDs that already have content (to avoid overwriting)
    *   Validates that source tasks exist before attempting to move them
    *   Maintains proper parent-child relationships
*   **Example CLI:** `task-master move --from=5.2 --to=7.3` to move subtask 5.2 to become subtask 7.3.
*   **Example Multi-Move:** `task-master move --from=10,11,12 --to=16,17,18` to move multiple tasks to new positions.
*   **Common Use:** Resolving merge conflicts in tasks.json when multiple team members create tasks on different branches.

---

## Dependency Management

### 18. Add Dependency (`add_dependency`)

*   **MCP Tool:** `add_dependency`
*   **CLI Command:** `task-master add-dependency [options]`
*   **Description:** `Define a dependency in Taskmaster, making one task a prerequisite for another.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID of the Taskmaster task that will depend on another.` (CLI: `-i, --id <id>`)
    *   `dependsOn`: `Required. The ID of the Taskmaster task that must be completed first, the prerequisite.` (CLI: `-d, --depends-on <id>`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <path>`)
*   **Usage:** Establish the correct order of execution between tasks.

### 19. Remove Dependency (`remove_dependency`)

*   **MCP Tool:** `remove_dependency`
*   **CLI Command:** `task-master remove-dependency [options]`
*   **Description:** `Remove a dependency relationship between two Taskmaster tasks.`
*   **Key Parameters/Options:**
    *   `id`: `Required. The ID of the Taskmaster task you want to remove a prerequisite from.` (CLI: `-i, --id <id>`)
    *   `dependsOn`: `Required. The ID of the Taskmaster task that should no longer be a prerequisite.` (CLI: `-d, --depends-on <id>`)
    *   `tag`: `Specify which tag context to operate on. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Update task relationships when the order of execution changes.

### 20. Validate Dependencies (`validate_dependencies`)

*   **MCP Tool:** `validate_dependencies`
*   **CLI Command:** `task-master validate-dependencies [options]`
*   **Description:** `Check your Taskmaster tasks for dependency issues (like circular references or links to non-existent tasks) without making changes.`
*   **Key Parameters/Options:**
    *   `tag`: `Specify which tag context to validate. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Audit the integrity of your task dependencies.

### 21. Fix Dependencies (`fix_dependencies`)

*   **MCP Tool:** `fix_dependencies`
*   **CLI Command:** `task-master fix-dependencies [options]`
*   **Description:** `Automatically fix dependency issues (like circular references or links to non-existent tasks) in your Taskmaster tasks.`
*   **Key Parameters/Options:**
    *   `tag`: `Specify which tag context to fix dependencies in. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Clean up dependency errors automatically.

---

## Analysis & Reporting

### 22. Analyze Project Complexity (`analyze_project_complexity`)

*   **MCP Tool:** `analyze_project_complexity`
*   **CLI Command:** `task-master analyze-complexity [options]`
*   **Description:** `Have Taskmaster analyze your tasks to determine their complexity and suggest which ones need to be broken down further.`
*   **Key Parameters/Options:**
    *   `output`: `Where to save the complexity analysis report. Default is '.taskmaster/reports/task-complexity-report.json' (or '..._tagname.json' if a tag is used).` (CLI: `-o, --output <file>`)
    *   `threshold`: `The minimum complexity score (1-10) that should trigger a recommendation to expand a task.` (CLI: `-t, --threshold <number>`)
    *   `research`: `Enable research role for more accurate complexity analysis. Requires appropriate API key.` (CLI: `-r, --research`)
    *   `tag`: `Specify which tag context to analyze. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Used before breaking down tasks to identify which ones need the most attention.
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.

### 23. View Complexity Report (`complexity_report`)

*   **MCP Tool:** `complexity_report`
*   **CLI Command:** `task-master complexity-report [options]`
*   **Description:** `Display the task complexity analysis report in a readable format.`
*   **Key Parameters/Options:**
    *   `tag`: `Specify which tag context to show the report for. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to the complexity report (default: '.taskmaster/reports/task-complexity-report.json').` (CLI: `-f, --file <file>`)
*   **Usage:** Review and understand the complexity analysis results after running analyze-complexity.

---

## File Management

### 24. Generate Task Files (`generate`)

*   **MCP Tool:** `generate`
*   **CLI Command:** `task-master generate [options]`
*   **Description:** `Create or update individual Markdown files for each task based on your tasks.json.`
*   **Key Parameters/Options:**
    *   `output`: `The directory where Taskmaster should save the task files (default: in a 'tasks' directory).` (CLI: `-o, --output <directory>`)
    *   `tag`: `Specify which tag context to generate files for. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
*   **Usage:** Run this after making changes to tasks.json to keep individual task files up to date. This command is now manual and no longer runs automatically.

---

## AI-Powered Research

### 25. Research (`research`)

*   **MCP Tool:** `research`
*   **CLI Command:** `task-master research [options]`
*   **Description:** `Perform AI-powered research queries with project context to get fresh, up-to-date information beyond the AI's knowledge cutoff.`
*   **Key Parameters/Options:**
    *   `query`: `Required. Research query/prompt (e.g., "What are the latest best practices for React Query v5?").` (CLI: `[query]` positional or `-q, --query <text>`)
    *   `taskIds`: `Comma-separated list of task/subtask IDs from the current tag context (e.g., "15,16.2,17").` (CLI: `-i, --id <ids>`)
    *   `filePaths`: `Comma-separated list of file paths for context (e.g., "src/api.js,docs/readme.md").` (CLI: `-f, --files <paths>`)
    *   `customContext`: `Additional custom context text to include in the research.` (CLI: `-c, --context <text>`)
    *   `includeProjectTree`: `Include project file tree structure in context (default: false).` (CLI: `--tree`)
    *   `detailLevel`: `Detail level for the research response: 'low', 'medium', 'high' (default: medium).` (CLI: `--detail <level>`)
    *   `saveTo`: `Task or subtask ID (e.g., "15", "15.2") to automatically save the research conversation to.` (CLI: `--save-to <id>`)
    *   `saveFile`: `If true, saves the research conversation to a markdown file in '.taskmaster/docs/research/'.` (CLI: `--save-file`)
    *   `noFollowup`: `Disables the interactive follow-up question menu in the CLI.` (CLI: `--no-followup`)
    *   `tag`: `Specify which tag context to use for task-based context gathering. Defaults to the current active tag.` (CLI: `--tag <name>`)
    *   `projectRoot`: `The directory of the project. Must be an absolute path.` (CLI: Determined automatically)
*   **Usage:** **This is a POWERFUL tool that agents should use FREQUENTLY** to:
    *   Get fresh information beyond knowledge cutoff dates
    *   Research latest best practices, library updates, security patches
    *   Find implementation examples for specific technologies
    *   Validate approaches against current industry standards
    *   Get contextual advice based on project files and tasks
*   **When to Consider Using Research:**
    *   **Before implementing any task** - Research current best practices
    *   **When encountering new technologies** - Get up-to-date implementation guidance (libraries, apis, etc)
    *   **For security-related tasks** - Find latest security recommendations
    *   **When updating dependencies** - Research breaking changes and migration guides
    *   **For performance optimization** - Get current performance best practices
    *   **When debugging complex issues** - Research known solutions and workarounds
*   **Research + Action Pattern:**
    *   Use `research` to gather fresh information
    *   Use `update_subtask` to commit findings with timestamps
    *   Use `update_task` to incorporate research into task details
    *   Use `add_task` with research flag for informed task creation
*   **Important:** This MCP tool makes AI calls and can take up to a minute to complete. The research provides FRESH data beyond the AI's training cutoff, making it invaluable for current best practices and recent developments.

---

## Tag Management

This new suite of commands allows you to manage different task contexts (tags).

### 26. List Tags (`tags`)

*   **MCP Tool:** `list_tags`
*   **CLI Command:** `task-master tags [options]`
*   **Description:** `List all available tags with task counts, completion status, and other metadata.`
*   **Key Parameters/Options:**
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
    *   `--show-metadata`: `Include detailed metadata in the output (e.g., creation date, description).` (CLI: `--show-metadata`)

### 27. Add Tag (`add_tag`)

*   **MCP Tool:** `add_tag`
*   **CLI Command:** `task-master add-tag <tagName> [options]`
*   **Description:** `Create a new, empty tag context, or copy tasks from another tag.`
*   **Key Parameters/Options:**
    *   `tagName`: `Name of the new tag to create (alphanumeric, hyphens, underscores).` (CLI: `<tagName>` positional)
    *   `--from-branch`: `Creates a tag with a name derived from the current git branch, ignoring the <tagName> argument.` (CLI: `--from-branch`)
    *   `--copy-from-current`: `Copy tasks from the currently active tag to the new tag.` (CLI: `--copy-from-current`)
    *   `--copy-from <tag>`: `Copy tasks from a specific source tag to the new tag.` (CLI: `--copy-from <tag>`)
    *   `--description <text>`: `Provide an optional description for the new tag.` (CLI: `-d, --description <text>`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)

### 28. Delete Tag (`delete_tag`)

*   **MCP Tool:** `delete_tag`
*   **CLI Command:** `task-master delete-tag <tagName> [options]`
*   **Description:** `Permanently delete a tag and all of its associated tasks.`
*   **Key Parameters/Options:**
    *   `tagName`: `Name of the tag to delete.` (CLI: `<tagName>` positional)
    *   `--yes`: `Skip the confirmation prompt.` (CLI: `-y, --yes`)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)

### 29. Use Tag (`use_tag`)

*   **MCP Tool:** `use_tag`
*   **CLI Command:** `task-master use-tag <tagName>`
*   **Description:** `Switch your active task context to a different tag.`
*   **Key Parameters/Options:**
    *   `tagName`: `Name of the tag to switch to.` (CLI: `<tagName>` positional)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)

### 30. Rename Tag (`rename_tag`)

*   **MCP Tool:** `rename_tag`
*   **CLI Command:** `task-master rename-tag <oldName> <newName>`
*   **Description:** `Rename an existing tag.`
*   **Key Parameters/Options:**
    *   `oldName`: `The current name of the tag.` (CLI: `<oldName>` positional)
    *   `newName`: `The new name for the tag.` (CLI: `<newName>` positional)
    *   `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)

### 31. Copy Tag (`copy_tag`)

*   **MCP Tool:** `copy_tag`
*   **CLI Command:** `task-master copy-tag <sourceName> <targetName> [options]`
*   **Description:** `Copy an entire tag context, including all its tasks and metadata, to a new tag.`
*   **Key Parameters/Options:**
    *   `sourceName`: `Name of the tag to copy from.` (CLI: `<sourceName>` positional)
    *   `targetName`: `Name of the new tag to create.` (CLI: `<targetName>` positional)
    *   `--description <text>`: `Optional description for the new tag.` (CLI: `-d, --description <text>`)

---

## Miscellaneous

### 32. Sync Readme (`sync-readme`) -- experimental

*   **MCP Tool:** N/A
*   **CLI Command:** `task-master sync-readme [options]`
*   **Description:** `Exports your task list to your project's README.md file, useful for showcasing progress.`
*   **Key Parameters/Options:**
    *   `status`: `Filter tasks by status (e.g., 'pending', 'done').` (CLI: `-s, --status <status>`)
    *   `withSubtasks`: `Include subtasks in the export.` (CLI: `--with-subtasks`)
    *   `tag`: `Specify which tag context to export from. Defaults to the current active tag.` (CLI: `--tag <name>`)

---

## Environment Variables Configuration (Updated)

Taskmaster primarily uses the **`.taskmaster/config.json`** file (in project root) for configuration (models, parameters, logging level, etc.), managed via `task-master models --setup`.

Environment variables are used **only** for sensitive API keys related to AI providers and specific overrides like the Ollama base URL:

*   **API Keys (Required for corresponding provider):**
    *   `ANTHROPIC_API_KEY`
    *   `PERPLEXITY_API_KEY`
    *   `OPENAI_API_KEY`
    *   `GOOGLE_API_KEY`
    *   `MISTRAL_API_KEY`
    *   `AZURE_OPENAI_API_KEY` (Requires `AZURE_OPENAI_ENDPOINT` too)
    *   `OPENROUTER_API_KEY`
    *   `XAI_API_KEY`
    *   `OLLAMA_API_KEY` (Requires `OLLAMA_BASE_URL` too)
*   **Endpoints (Optional/Provider Specific inside .taskmaster/config.json):**
    *   `AZURE_OPENAI_ENDPOINT`
    *   `OLLAMA_BASE_URL` (Default: `http://localhost:11434/api`)

**Set API keys** in your **`.env`** file in the project root (for CLI use) or within the `env` section of your **`.kiro/mcp.json`** file (for MCP/Kiro integration). All other settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in `.taskmaster/config.json` via `task-master models` command or `models` MCP tool.

---

For details on how these commands fit into the development process, see the [dev_workflow.md](.kiro/steering/dev_workflow.md).

## Links discovered
- [dev_workflow.md](https://github.com/eyaltoledano/claude-task-master/blob/main/.kiro/steering/.kiro/steering/dev_workflow.md)

--- .kiro/steering/taskmaster_hooks_workflow.md ---
---
inclusion: always
---

# Taskmaster Hook-Driven Workflow

## Core Principle: Hooks Automate Task Management

When working with Taskmaster in Kiro, **avoid manually marking tasks as done**. The hook system automatically handles task completion based on:

- **Test Success**: `[TM] Test Success Task Completer` detects passing tests and prompts for task completion
- **Code Changes**: `[TM] Code Change Task Tracker` monitors implementation progress
- **Dependency Chains**: `[TM] Task Dependency Auto-Progression` auto-starts dependent tasks

## AI Assistant Workflow

Follow this pattern when implementing features:

1. **Implement First**: Write code, create tests, make changes
2. **Save Frequently**: Hooks trigger on file saves to track progress automatically
3. **Let Hooks Decide**: Allow hooks to detect completion rather than manually setting status
4. **Respond to Prompts**: Confirm when hooks suggest task completion

## Key Rules for AI Assistants

- **Never use `tm set-status --status=done`** unless hooks fail to detect completion
- **Always write tests** - they provide the most reliable completion signal
- **Save files after implementation** - this triggers progress tracking
- **Trust hook suggestions** - if no completion prompt appears, more work may be needed

## Automatic Behaviors

The hook system provides:

- **Progress Logging**: Implementation details automatically added to task notes
- **Evidence-Based Completion**: Tasks marked done only when criteria are met
- **Dependency Management**: Next tasks auto-started when dependencies complete
- **Natural Flow**: Focus on coding, not task management overhead

## Manual Override Cases

Only manually set task status for:

- Documentation-only tasks
- Tasks without testable outcomes
- Emergency fixes without proper test coverage

Use `tm set-status` sparingly - prefer hook-driven completion.

## Implementation Pattern

```
1. Implement feature → Save file
2. Write tests → Save test file
3. Tests pass → Hook prompts completion
4. Confirm completion → Next task auto-starts
```

This workflow ensures proper task tracking while maintaining development flow.

--- .taskmaster/CLAUDE.md ---
# Task Master AI - Agent Integration Guide

## Essential Commands

### Core Workflow Commands

```bash
# Project Setup
task-master init                                    # Initialize Task Master in current project
task-master parse-prd .taskmaster/docs/prd.md       # Generate tasks from PRD document
task-master models --setup                        # Configure AI models interactively

# Daily Development Workflow
task-master list                                   # Show all tasks with status
task-master next                                   # Get next available task to work on
task-master show <id>                             # View detailed task information (e.g., task-master show 1.2)
task-master set-status --id=<id> --status=done    # Mark task complete

# Task Management
task-master add-task --prompt="description" --research        # Add new task with AI assistance
task-master expand --id=<id> --research --force              # Break task into subtasks
task-master update-task --id=<id> --prompt="changes"         # Update specific task
task-master update --from=<id> --prompt="changes"            # Update multiple tasks from ID onwards
task-master update-subtask --id=<id> --prompt="notes"        # Add implementation notes to subtask

# Analysis & Planning
task-master analyze-complexity --research          # Analyze task complexity
task-master complexity-report                      # View complexity analysis
task-master expand --all --research               # Expand all eligible tasks

# Dependencies & Organization
task-master add-dependency --id=<id> --depends-on=<id>       # Add task dependency
task-master move --from=<id> --to=<id>                       # Reorganize task hierarchy
task-master validate-dependencies                            # Check for dependency issues
```

## Key Files & Project Structure

### Core Files

- `.taskmaster/tasks/tasks.json` - Main task data file (auto-managed)
- `.taskmaster/config.json` - AI model configuration (use `task-master models` to modify)
- `.taskmaster/docs/prd.md` - Product Requirements Document for parsing (`.md` extension recommended for better editor support)
- `.taskmaster/tasks/*.txt` - Individual task files (auto-generated from tasks.json)
- `.env` - API keys for CLI usage

**PRD File Format:** While both `.txt` and `.md` extensions work, **`.md` is recommended** because:
- Markdown syntax highlighting in editors improves readability
- Proper rendering when previewing in VS Code, GitHub, or other tools
- Better collaboration through formatted documentation

### Claude Code Integration Files

- `CLAUDE.md` - Auto-loaded context for Claude Code (this file)
- `.claude/settings.json` - Claude Code tool allowlist and preferences
- `.claude/commands/` - Custom slash commands for repeated workflows
- `.mcp.json` - MCP server configuration (project-specific)

### Directory Structure

```
project/
├── .taskmaster/
│   ├── tasks/              # Task files directory
│   │   ├── tasks.json      # Main task database
│   │   ├── task-1.md      # Individual task files
│   │   └── task-2.md
│   ├── docs/              # Documentation directory
│   │   ├── prd.md         # Product requirements (.md recommended)
│   ├── reports/           # Analysis reports directory
│   │   └── task-complexity-report.json
│   ├── templates/         # Template files
│   │   └── example_prd.md  # Example PRD template (.md recommended)
│   └── config.json        # AI models & settings
├── .claude/
│   ├── settings.json      # Claude Code configuration
│   └── commands/         # Custom slash commands
├── .env                  # API keys
├── .mcp.json            # MCP configuration
└── CLAUDE.md            # This file - auto-loaded by Claude Code
```

## MCP Integration

Task Master provides an MCP server that Claude Code can connect to. Configure in `.mcp.json`:

```json
{
  "mcpServers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        "TASK_MASTER_TOOLS": "core",
        "ANTHROPIC_API_KEY": "your_key_here",
        "PERPLEXITY_API_KEY": "your_key_here",
        "OPENAI_API_KEY": "OPENAI_API_KEY_HERE",
        "GOOGLE_API_KEY": "GOOGLE_API_KEY_HERE",
        "XAI_API_KEY": "XAI_API_KEY_HERE",
        "OPENROUTER_API_KEY": "OPENROUTER_API_KEY_HERE",
        "MISTRAL_API_KEY": "MISTRAL_API_KEY_HERE",
        "AZURE_OPENAI_API_KEY": "AZURE_OPENAI_API_KEY_HERE",
        "OLLAMA_API_KEY": "OLLAMA_API_KEY_HERE"
      }
    }
  }
}
```

### MCP Tool Tiers

Task Master uses tiered tool loading to optimize context window usage:

| Tier | Tools | Use Case |
|------|-------|----------|
| `core` | 7 | Minimal daily workflow tools (default) |
| `standard` | 14 | Common task management |
| `all` | 44+ | Full suite with research, autopilot, dependencies |

**Core tools (7):** `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task`

**Standard adds (7 more):** `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `add_task`, `complexity_report`

**All tier adds:** Dependency management, tag management, research, autopilot TDD workflow, scope up/down, models, rules

**To upgrade tiers:** Change `TASK_MASTER_TOOLS` in `.mcp.json` from `"core"` to `"standard"` or `"all"` and restart the MCP connection.

### Essential MCP Tools

```javascript
help; // = shows available taskmaster commands
// Project setup
initialize_project; // = task-master init
parse_prd; // = task-master parse-prd

// Daily workflow
get_tasks; // = task-master list
next_task; // = task-master next
get_task; // = task-master show <id>
set_task_status; // = task-master set-status

// Task management
add_task; // = task-master add-task
expand_task; // = task-master expand
update_task; // = task-master update-task
update_subtask; // = task-master update-subtask
update; // = task-master update

// Analysis
analyze_project_complexity; // = task-master analyze-complexity
complexity_report; // = task-master complexity-report
```

## Claude Code Workflow Integration

### Standard Development Workflow

#### 1. Project Initialization

```bash
# Initialize Task Master
task-master init

# Create or obtain PRD, then parse it (use .md extension for better editor support)
task-master parse-prd .taskmaster/docs/prd.md

# Analyze complexity and expand tasks
task-master analyze-complexity --research
task-master expand --all --research
```

If tasks already exist, another PRD can be parsed (with new information only!) using parse-prd with --append flag. This will add the generated tasks to the existing list of tasks..

#### 2. Daily Development Loop

```bash
# Start each session
task-master next                           # Find next available task
task-master show <id>                     # Review task details

# During implementation, check in code context into the tasks and subtasks
task-master update-subtask --id=<id> --prompt="implementation notes..."

# Complete tasks
task-master set-status --id=<id> --status=done
```

#### 3. Multi-Claude Workflows

For complex projects, use multiple Claude Code sessions:

```bash
# Terminal 1: Main implementation
cd project && claude

# Terminal 2: Testing and validation
cd project-test-worktree && claude

# Terminal 3: Documentation updates
cd project-docs-worktree && claude
```

### Custom Slash Commands

Create `.claude/commands/taskmaster-next.md`:

```markdown
Find the next available Task Master task and show its details.

Steps:

1. Run `task-master next` to get the next task
2. If a task is available, run `task-master show <id>` for full details
3. Provide a summary of what needs to be implemented
4. Suggest the first implementation step
```

Create `.claude/commands/taskmaster-complete.md`:

```markdown
Complete a Task Master task: $ARGUMENTS

Steps:

1. Review the current task with `task-master show $ARGUMENTS`
2. Verify all implementation is complete
3. Run any tests related to this task
4. Mark as complete: `task-master set-status --id=$ARGUMENTS --status=done`
5. Show the next available task with `task-master next`
```

## Tool Allowlist Recommendations

Add to `.claude/settings.json`:

```json
{
  "allowedTools": [
    "Edit",
    "Bash(task-master *)",
    "Bash(git commit:*)",
    "Bash(git add:*)",
    "Bash(npm run *)",
    "mcp__task_master_ai__*"
  ]
}
```

## Configuration & Setup

### API Keys Required

At least **one** of these API keys must be configured:

- `ANTHROPIC_API_KEY` (Claude models) - **Recommended**
- `PERPLEXITY_API_KEY` (Research features) - **Highly recommended**
- `OPENAI_API_KEY` (GPT models)
- `GOOGLE_API_KEY` (Gemini models)
- `MISTRAL_API_KEY` (Mistral models)
- `OPENROUTER_API_KEY` (Multiple models)
- `XAI_API_KEY` (Grok models)

An API key is required for any provider used across any of the 3 roles defined in the `models` command.

### Model Configuration

```bash
# Interactive setup (recommended)
task-master models --setup

# Set specific models
task-master models --set-main claude-3-5-sonnet-20241022
task-master models --set-research perplexity-llama-3.1-sonar-large-128k-online
task-master models --set-fallback gpt-4o-mini
```

## Task Structure & IDs

### Task ID Format

- Main tasks: `1`, `2`, `3`, etc.
- Subtasks: `1.1`, `1.2`, `2.1`, etc.
- Sub-subtasks: `1.1.1`, `1.1.2`, etc.

### Task Status Values

- `pending` - Ready to work on
- `in-progress` - Currently being worked on
- `done` - Completed and verified
- `deferred` - Postponed
- `cancelled` - No longer needed
- `blocked` - Waiting on external factors

### Task Fields

```json
{
  "id": "1.2",
  "title": "Implement user authentication",
  "description": "Set up JWT-based auth system",
  "status": "pending",
  "priority": "high",
  "dependencies": ["1.1"],
  "details": "Use bcrypt for hashing, JWT for tokens...",
  "testStrategy": "Unit tests for auth functions, integration tests for login flow",
  "subtasks": []
}
```

## Claude Code Best Practices with Task Master

### Context Management

- Use `/clear` between different tasks to maintain focus
- This CLAUDE.md file is automatically loaded for context
- Use `task-master show <id>` to pull specific task context when needed

### Iterative Implementation

1. `task-master show <subtask-id>` - Understand requirements
2. Explore codebase and plan implementation
3. `task-master update-subtask --id=<id> --prompt="detailed plan"` - Log plan
4. `task-master set-status --id=<id> --status=in-progress` - Start work
5. Implement code following logged plan
6. `task-master update-subtask --id=<id> --prompt="what worked/didn't work"` - Log progress
7. `task-master set-status --id=<id> --status=done` - Complete task

### Complex Workflows with Checklists

For large migrations or multi-step processes:

1. Create a markdown PRD file describing the new changes: `touch task-migration-checklist.md` (prds can be .txt or .md)
2. Use Taskmaster to parse the new prd with `task-master parse-prd --append` (also available in MCP)
3. Use Taskmaster to expand the newly generated tasks into subtasks. Consdier using `analyze-complexity` with the correct --to and --from IDs (the new ids) to identify the ideal subtask amounts for each task. Then expand them.
4. Work through items systematically, checking them off as completed
5. Use `task-master update-subtask` to log progress on each task/subtask and/or updating/researching them before/during implementation if getting stuck

### Git Integration

Task Master works well with `gh` CLI:

```bash
# Create PR for completed task
gh pr create --title "Complete task 1.2: User authentication" --body "Implements JWT auth system as specified in task 1.2"

# Reference task in commits
git commit -m "feat: implement JWT auth (task 1.2)"
```

### Parallel Development with Git Worktrees

```bash
# Create worktrees for parallel task development
git worktree add ../project-auth feature/auth-system
git worktree add ../project-api feature/api-refactor

# Run Claude Code in each worktree
cd ../project-auth && claude    # Terminal 1: Auth work
cd ../project-api && claude     # Terminal 2: API work
```

## Troubleshooting

### AI Commands Failing

```bash
# Check API keys are configured
cat .env                           # For CLI usage

# Verify model configuration
task-master models

# Test with different model
task-master models --set-fallback gpt-4o-mini
```

### MCP Connection Issues

- Check `.mcp.json` configuration
- Verify Node.js installation
- Use `--mcp-debug` flag when starting Claude Code
- Use CLI as fallback if MCP unavailable

### Task File Sync Issues

```bash
# Fix dependency issues
task-master fix-dependencies
```

DO NOT RE-INITIALIZE. That will not do anything beyond re-adding the same Taskmaster core files.

## Important Notes

### AI-Powered Operations

These commands make AI calls and may take up to a minute:

- `parse_prd` / `task-master parse-prd`
- `analyze_project_complexity` / `task-master analyze-complexity`
- `expand_task` / `task-master expand`
- `expand_all` / `task-master expand --all`
- `add_task` / `task-master add-task`
- `update` / `task-master update`
- `update_task` / `task-master update-task`
- `update_subtask` / `task-master update-subtask`

### File Management

- Never manually edit `tasks.json` - use commands instead
- Never manually edit `.taskmaster/config.json` - use `task-master models`

### Claude Code Session Management

- Use `/clear` frequently to maintain focused context
- Create custom slash commands for repeated Task Master workflows
- Configure tool allowlist to streamline permissions
- Use headless mode for automation: `claude -p "task-master next"`

### Multi-Task Updates

- Use `update --from=<id>` to update multiple future tasks
- Use `update-task --id=<id>` for single task updates
- Use `update-subtask --id=<id>` for implementation logging

### Research Mode

- Add `--research` flag for research-based AI enhancement
- Requires a research model API key like Perplexity (`PERPLEXITY_API_KEY`) in environment
- Provides more informed task creation and updates
- Recommended for complex technical tasks

---

_This guide ensures Claude Code has immediate access to Task Master's essential functionality for agentic development workflows._


--- .taskmaster/tasks/task_001_tm-start.txt ---
# Task ID: 1
# Title: Create start command class structure
# Status: pending
# Dependencies: None
# Priority: high
# Description: Create the basic structure for the start command following the Commander class pattern
# Details:
Create a new file `apps/cli/src/commands/start.command.ts` based on the existing list.command.ts pattern. Implement the command class with proper command registration, description, and argument handling for the task_id parameter. The class should extend the base Command class and implement the required methods.

Example structure:
```typescript
import { Command } from 'commander';
import { BaseCommand } from './base.command';

export class StartCommand extends BaseCommand {
  public register(program: Command): void {
    program
      .command('start')
      .alias('tm start')
      .description('Start implementing a task using claude-code')
      .argument('<task_id>', 'ID of the task to start')
      .action(async (taskId: string) => {
        await this.execute(taskId);
      });
  }

  public async execute(taskId: string): Promise<void> {
    // Implementation will be added in subsequent tasks
  }
}
```

# Test Strategy:
Verify the command registers correctly by running the CLI with --help and checking that the start command appears with proper description and arguments. Test the basic structure by ensuring the command can be invoked without errors.


--- .taskmaster/tasks/task_002_tm-start.txt ---
# Task ID: 2
# Title: Register start command in CLI
# Status: pending
# Dependencies: 7
# Priority: high
# Description: Register the start command in the CLI application
# Details:
Update the CLI application to register the new start command. This involves importing the StartCommand class and adding it to the commands array in the CLI initialization.

In `apps/cli/src/index.ts` or the appropriate file where commands are registered:

```typescript
import { StartCommand } from './commands/start.command';

// Add StartCommand to the commands array
const commands = [
  // ... existing commands
  new StartCommand(),
];

// Register all commands
commands.forEach(command => command.register(program));
```

# Test Strategy:
Verify the command is correctly registered by running the CLI with --help and checking that the start command appears in the list of available commands.


--- .taskmaster/tasks/task_003_tm-start.txt ---
# Task ID: 3
# Title: Create standardized prompt builder
# Status: pending
# Dependencies: 1
# Priority: medium
# Description: Implement a function to build the standardized prompt for claude-code based on the task details
# Details:
Create a function in the StartCommand class that builds the standardized prompt according to the template provided in the PRD. The prompt should include instructions for Claude to first run `tm show <task_id>` to get task details, and then implement the required changes.

```typescript
private buildPrompt(taskId: string): string {
  return `You are an AI coding assistant with access to this repository's codebase.

First, run this command to get the task details:
tm show ${taskId}

Then implement the task with these requirements:
- Make the SMALLEST number of code changes possible
- Follow ALL existing patterns in the codebase (you have access to analyze the code)
- Do NOT over-engineer the solution
- Use existing files/functions/patterns wherever possible
- When complete, print: COMPLETED: <brief summary of changes>

Begin by running tm show ${taskId} to understand what needs to be implemented.`;
}
```
<info added on 2025-09-12T02:40:01.812Z>
The prompt builder function will handle task context retrieval by instructing Claude to use the task-master show command. This approach ensures Claude has access to all necessary task details before implementation begins. The command syntax "tm show ${taskId}" embedded in the prompt will direct Claude to first gather the complete task context, including description, requirements, and any existing implementation details, before proceeding with code changes.
</info added on 2025-09-12T02:40:01.812Z>

# Test Strategy:
Verify the prompt is correctly formatted by calling the function with a sample task ID and checking that the output matches the expected template with the task ID properly inserted.


--- .taskmaster/tasks/task_004_tm-start.txt ---
# Task ID: 4
# Title: Implement claude-code executor
# Status: pending
# Dependencies: 3
# Priority: high
# Description: Add functionality to execute the claude-code command with the built prompt
# Details:
Implement the functionality to execute the claude command with the built prompt. This should use Node.js child_process.exec() to run the command directly in the terminal.

```typescript
import { exec } from 'child_process';

// Inside execute method, after task validation
private async executeClaude(prompt: string): Promise<void> {
  console.log('Starting claude-code to implement the task...');
  
  try {
    // Execute claude with the prompt
    const claudeCommand = `claude "${prompt.replace(/"/g, '\\"')}"`;
    
    // Use execSync to wait for the command to complete
    const { execSync } = require('child_process');
    execSync(claudeCommand, { stdio: 'inherit' });
    
    console.log('Claude session completed.');
  } catch (error) {
    console.error('Error executing claude-code:', error.message);
    process.exit(1);
  }
}
```

Then call this method from the execute method after building the prompt.

# Test Strategy:
Test by running the command with a valid task ID and verifying that the claude command is executed with the correct prompt. Check that the command handles errors appropriately if claude-code is not available.


--- .taskmaster/tasks/task_007_tm-start.txt ---
# Task ID: 7
# Title: Integrate execution flow in start command
# Status: pending
# Dependencies: 3, 4
# Priority: high
# Description: Connect all the components to implement the complete execution flow for the start command
# Details:
Update the execute method in the StartCommand class to integrate all the components and implement the complete execution flow as described in the PRD:
1. Validate task exists
2. Build standardized prompt
3. Execute claude-code
4. Check git status for changes
5. Auto-mark task as done if changes detected

```typescript
public async execute(taskId: string): Promise<void> {
  // Validate task exists
  const core = await createTaskMasterCore();
  const task = await core.tasks.getById(parseInt(taskId, 10));
  
  if (!task) {
    console.error(`Task with ID ${taskId} not found`);
    process.exit(1);
  }
  
  // Build prompt
  const prompt = this.buildPrompt(taskId);
  
  // Execute claude-code
  await this.executeClaude(prompt);
  
  // Check git status
  const changedFiles = await this.checkGitChanges();
  
  if (changedFiles.length > 0) {
    console.log('\nChanges detected in the following files:');
    changedFiles.forEach(file => console.log(`- ${file}`));
    
    // Auto-mark task as done
    await this.markTaskAsDone(taskId);
    console.log(`\nTask ${taskId} completed successfully and marked as done.`);
  } else {
    console.warn('\nNo changes detected after claude-code execution. Task not marked as done.');
  }
}
```

# Test Strategy:
Test the complete execution flow by running the start command with a valid task ID and verifying that all steps are executed correctly. Test with both scenarios: when changes are detected and when no changes are detected.


--- apps/extension/README.md ---
# Official Taskmaster AI Extension

Transform your AI-driven development workflow with a beautiful, interactive Kanban board directly in VS Code. Seamlessly manage tasks from [Taskmaster AI](https://github.com/eyaltoledano/claude-task-master) projects with real-time synchronization and intelligent task management.

![Taskmaster AI Extension](https://img.shields.io/badge/VS%20Code-Extension-blue)
![License](https://img.shields.io/badge/License-MIT-green)
![Version](https://img.shields.io/visual-studio-marketplace/v/Hamster.task-master-hamster)
![Installs](https://img.shields.io/visual-studio-marketplace/i/Hamster.task-master-hamster)

## 🎯 What is Taskmaster AI?

Taskmaster AI is an intelligent task management system designed for AI-assisted development. It helps you break down complex projects into manageable tasks, track progress, and leverage AI to enhance your development workflow.

## ✨ Key Features

### 📊 **Interactive Kanban Board**
- **Drag & Drop Interface** - Effortlessly move tasks between status columns
- **Real-time Sync** - Changes instantly reflect in your Taskmaster project files
- **Multiple Views** - Board view and detailed task sidebar
- **Smart Columns** - Pending, In Progress, Review, Done, Deferred, and Cancelled

![Kanban Board](assets/screenshots/kanban-board.png)

### 🤖 **AI-Powered Features**
- **Task Content Generation** - Regenerate task descriptions using AI
- **Smart Task Updates** - Append findings and progress notes automatically
- **MCP Integration** - Seamless connection to Taskmaster AI via Model Context Protocol
- **Intelligent Caching** - Smart performance optimization with background refresh

![Task Details](assets/screenshots/task-details.png)

### 🚀 **Performance & Usability**
- **Offline Support** - Continue working even when disconnected
- **Auto-refresh** - Automatic polling for task changes with smart frequency
- **VS Code Native** - Perfectly integrated with VS Code themes and UI
- **Modern Interface** - Built with ShadCN UI components and Tailwind CSS

## 🛠️ Installation

### Prerequisites

1. **VS Code** 1.90.0 or higher
2. **Node.js** 20.0 or higher (for Taskmaster MCP server)

### Install the Extension

1. **From VS Code Marketplace:**
   - Click the **Install** button above
   - The extension will be automatically added to your VS Code instance

## 🚀 Quick Start

### 1. **Initialize Taskmaster Project**
If you don't have a Taskmaster project yet:
```bash
cd your-project
npm i -g task-master-ai
   task-master init
   ```

### 2. **Open Kanban Board**
- **Command Palette** (Ctrl+Shift+P): `Taskmaster Kanban: Show Board`
- **Or** the extension automatically activates when you have a `.taskmaster` folder in your workspace

### 3. **MCP Server Setup**
The extension automatically handles the Taskmaster MCP server connection:
- **No manual installation required** - The extension spawns the MCP server automatically
- **Uses npx by default** - Automatically downloads Taskmaster AI when needed
- **Configurable** - You can customize the MCP server command in settings if needed

### 4. **Start Managing Tasks**
- **Drag tasks** between columns to change status
- **Click tasks** to view detailed information
- **Use AI features** to enhance task content
- **Add subtasks** with the + button on parent tasks

## 📋 Usage Guide

### Task Management

| Action | How to Do It |
|--------|--------------|
| **View Kanban Board** | `Ctrl/Cmd + Shift + P` → "Taskmaster: Show Board" |
| **Change Task Status** | Drag task card to different column |
| **View Task Details** | Click on any task card |
| **Edit Task Content** | Click task → Use edit buttons in details panel |
| **Add Subtasks** | Click the + button on parent task cards |
| **Use AI Features** | Open task details → Click AI action buttons |

### Understanding Task Statuses

- 📋 **Pending** - Tasks ready to be started
- 🚀 **In Progress** - Currently being worked on
- 👀 **Review** - Awaiting review or feedback
- ✅ **Done** - Completed tasks
- ⏸️ **Deferred** - Postponed for later

### **AI-Powered Task Management**

The extension integrates seamlessly with Taskmaster AI via MCP to provide:
- **Smart Task Generation** - AI creates detailed implementation plans
- **Progress Tracking** - Append timestamped notes and findings
- **Content Enhancement** - Regenerate task descriptions for clarity
- **Research Integration** - Get up-to-date information for your tasks

## ⚙️ Configuration

Access settings via **File → Preferences → Settings** and search for "Taskmaster":

### **MCP Connection Settings**
- **MCP Server Command** - Path to task-master-ai executable (default: `npx`)
- **MCP Server Args** - Arguments for the server command (default: `-y`, `task-master-ai`)
- **Connection Timeout** - Server response timeout (default: 30s)
- **Auto Refresh** - Enable automatic task updates (default: enabled)

### **UI Preferences**
- **Theme** - Auto, Light, or Dark mode
- **Show Completed Tasks** - Display done tasks in board (default: enabled)
- **Task Display Limit** - Maximum tasks to show (default: 100)

### **Performance Options**
- **Cache Duration** - How long to cache task data (default: 5s)
- **Concurrent Requests** - Max simultaneous API calls (default: 5)

## 🔧 Troubleshooting

### **Extension Not Loading**
1. Ensure Node.js 20+ is installed
2. Check workspace contains `.taskmaster` folder
3. Restart VS Code
4. Check Output panel (View → Output → Taskmaster Kanban)

### **MCP Connection Issues**
1. **Command not found**: Ensure Node.js and npx are in your PATH
2. **Timeout errors**: Increase timeout in settings
3. **Permission errors**: Check Node.js permissions
4. **Network issues**: Verify internet connection for npx downloads

### **Tasks Not Updating**
1. Check MCP connection status in status bar
2. Verify `.taskmaster/tasks/tasks.json` exists
3. Try manual refresh: `Taskmaster Kanban: Check Connection`
4. Review error logs in Output panel

### **Performance Issues**
1. Reduce task display limit in settings
2. Increase cache duration
3. Disable auto-refresh if needed
4. Close other VS Code extensions temporarily

## 🆘 Support & Resources

### **Getting Help**
- 📖 **Documentation**: [Taskmaster AI Docs](https://github.com/eyaltoledano/claude-task-master)
- 🐛 **Report Issues**: [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- 💬 **Discussions**: [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)
- 🐛 **Report Issues**: [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)

## 🎯 Tips for Best Results

### **Project Organization**
- Use descriptive task titles
- Add detailed implementation notes
- Set appropriate task dependencies
- Leverage AI features for complex tasks

### **Workflow Optimization**
- Review task details before starting work
- Use subtasks for complex features
- Update task status as you progress
- Add findings and learnings to task notes

### **Collaboration**
- Keep task descriptions updated
- Use consistent status conventions
- Document decisions in task details
- Share knowledge through task notes

---

## 🏆 Why Taskmaster Kanban?

✅ **Visual workflow management** for your Taskmaster projects  
✅ **AI-powered task enhancement** built right in  
✅ **Real-time synchronization** keeps everything in sync  
✅ **Native VS Code integration** feels like part of the editor  
✅ **Free and open source** with active development  

**Transform your development workflow today!** 🚀

---

*Originally Made with ❤️ by [David Maliglowka](https://x.com/DavidMaliglowka)*

## Support

This is an open-source project maintained in my spare time. While I strive to fix bugs and improve the extension, support is provided on a best-effort basis. Feel free to:
- Report issues on [GitHub](https://github.com/eyaltoledano/claude-task-master/issues)
- Submit pull requests with improvements
- Fork the project if you need specific modifications

## Disclaimer

This extension is provided "as is" without any warranties. Use at your own risk. The author is not responsible for any issues, data loss, or damages that may occur from using this extension. Please backup your work regularly and test thoroughly before using in important projects.

## Links discovered
- [Taskmaster AI](https://github.com/eyaltoledano/claude-task-master)
- [Taskmaster AI Extension](https://img.shields.io/badge/VS%20Code-Extension-blue)
- [License](https://img.shields.io/badge/License-MIT-green)
- [Version](https://img.shields.io/visual-studio-marketplace/v/Hamster.task-master-hamster)
- [Installs](https://img.shields.io/visual-studio-marketplace/i/Hamster.task-master-hamster)
- [Kanban Board](https://github.com/eyaltoledano/claude-task-master/blob/main/apps/extension/assets/screenshots/kanban-board.png)
- [Task Details](https://github.com/eyaltoledano/claude-task-master/blob/main/apps/extension/assets/screenshots/task-details.png)
- [Taskmaster AI Docs](https://github.com/eyaltoledano/claude-task-master)
- [GitHub Issues](https://github.com/eyaltoledano/claude-task-master/issues)
- [GitHub Discussions](https://github.com/eyaltoledano/claude-task-master/discussions)
- [David Maliglowka](https://x.com/DavidMaliglowka)
- [GitHub](https://github.com/eyaltoledano/claude-task-master/issues)

--- apps/mcp/src/tools/README-ZOD-V3.md ---
# Why MCP Tools Use Zod v3

## Problem

- **FastMCP** uses `xsschema` to convert schemas → outputs JSON Schema **Draft 2020-12**
- **MCP clients** (Augment IDE, gemini-cli, etc.) only support **Draft-07**
- Using Zod v4 in tools causes "vendor undefined" errors and tool discovery failures

## Temporary Solution

All MCP tool files import from `zod/v3` instead of `zod`:

```typescript
import { z } from 'zod/v3';  // ✅ Draft-07 compatible
// NOT: import { z } from 'zod';  // ❌ Would use Draft 2020-12
```

### Why This Works

- Zod v4 ships with v3 compatibility at `zod/v3`
- FastMCP + zod-to-json-schema converts Zod v3 schemas → **Draft-07**
- This ensures MCP clients can discover and use our tools

### What This Means

- ✅ **MCP tools** → use `zod/v3` (apps/mcp & mcp-server/src/tools)
- ✅ **Rest of codebase** → uses `zod` (Zod v4)
- ✅ **No conflicts** → they're from the same package, just different versions

## When Can We Remove This?

This workaround can be removed when **either**:

1. **FastMCP adds JSON Schema version configuration**
   - e.g., `new FastMCP({ jsonSchema: { target: 'draft-07' } })`
   - Tracking: https://github.com/punkpeye/fastmcp/issues/189

2. **MCP spec adds Draft 2020-12 support**
   - Unlikely in the short term

3. **xsschema adds version targeting**
   - Would allow FastMCP to use Draft-07

## How to Maintain

When adding new MCP tools:

```typescript
// ✅ CORRECT
import { z } from 'zod/v3';

export function registerMyTool(server: FastMCP) {
  server.addTool({
    name: 'my_tool',
    parameters: z.object({ ... }),  // Will use Draft-07
    execute: async (args, context) => { ... }
  });
}
```

```typescript
// ❌ WRONG - Will break MCP client compatibility
import { z } from 'zod';  // Don't do this in apps/mcp/src/tools/
```

---

**Last Updated:** 2025-10-18
**Affects:** All files in `apps/mcp/src/tools/`
**See Also:** `mcp-server/src/tools/README-ZOD-V3.md` (same workaround)


--- apps/extension/esbuild.js ---
const esbuild = require('esbuild');
const path = require('path');

const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');

/**
 * @type {import('esbuild').Plugin}
 */
const esbuildProblemMatcherPlugin = {
	name: 'esbuild-problem-matcher',

	setup(build) {
		build.onStart(() => {
			console.log('[watch] build started');
		});
		build.onEnd((result) => {
			result.errors.forEach(({ text, location }) => {
				console.error(`✘ [ERROR] ${text}`);
				console.error(
					`    ${location.file}:${location.line}:${location.column}:`
				);
			});
			console.log('[watch] build finished');
		});
	}
};

/**
 * @type {import('esbuild').Plugin}
 */
const aliasPlugin = {
	name: 'alias',
	setup(build) {
		// Handle @/ aliases for shadcn/ui
		build.onResolve({ filter: /^@\// }, (args) => {
			const resolvedPath = path.resolve(__dirname, 'src', args.path.slice(2));

			// Try to resolve with common TypeScript extensions
			const fs = require('fs');
			const extensions = ['.tsx', '.ts', '.jsx', '.js'];

			// Check if it's a file first
			for (const ext of extensions) {
				const fullPath = resolvedPath + ext;
				if (fs.existsSync(fullPath)) {
					return { path: fullPath };
				}
			}

			// Check if it's a directory with index file
			for (const ext of extensions) {
				const indexPath = path.join(resolvedPath, 'index' + ext);
				if (fs.existsSync(indexPath)) {
					return { path: indexPath };
				}
			}

			// Fallback to original behavior
			return { path: resolvedPath };
		});
	}
};

async function main() {
	// Build configuration for the VS Code extension
	const extensionCtx = await esbuild.context({
		entryPoints: ['src/extension.ts'],
		bundle: true,
		format: 'cjs',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'node',
		outdir: 'dist',
		external: ['vscode'],
		logLevel: 'silent',
		// Add production optimizations
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	// Build configuration for the React webview
	const webviewCtx = await esbuild.context({
		entryPoints: ['src/webview/index.tsx'],
		bundle: true,
		format: 'iife',
		globalName: 'App',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'browser',
		outdir: 'dist',
		logLevel: 'silent',
		target: ['es2020'],
		jsx: 'automatic',
		jsxImportSource: 'react',
		external: ['*.css'],
		// Bundle React with webview since it's not available in the runtime
		// This prevents the multiple React instances issue
		// Ensure React is resolved from the workspace root to avoid duplicates
		alias: {
			react: path.resolve(__dirname, '../../node_modules/react'),
			'react-dom': path.resolve(__dirname, '../../node_modules/react-dom')
		},
		define: {
			'process.env.NODE_ENV': production ? '"production"' : '"development"',
			global: 'globalThis'
		},
		// Add production optimizations for webview too
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	// Build configuration for the React sidebar
	const sidebarCtx = await esbuild.context({
		entryPoints: ['src/webview/sidebar.tsx'],
		bundle: true,
		format: 'iife',
		globalName: 'SidebarApp',
		minify: production,
		sourcemap: !production ? 'inline' : false,
		sourcesContent: !production,
		platform: 'browser',
		outdir: 'dist',
		logLevel: 'silent',
		target: ['es2020'],
		jsx: 'automatic',
		jsxImportSource: 'react',
		external: ['*.css'],
		alias: {
			react: path.resolve(__dirname, '../../node_modules/react'),
			'react-dom': path.resolve(__dirname, '../../node_modules/react-dom')
		},
		define: {
			'process.env.NODE_ENV': production ? '"production"' : '"development"',
			global: 'globalThis'
		},
		...(production && {
			drop: ['debugger'],
			pure: ['console.log', 'console.debug', 'console.trace']
		}),
		plugins: [esbuildProblemMatcherPlugin, aliasPlugin]
	});

	if (watch) {
		await Promise.all([
			extensionCtx.watch(),
			webviewCtx.watch(),
			sidebarCtx.watch()
		]);
	} else {
		await Promise.all([
			extensionCtx.rebuild(),
			webviewCtx.rebuild(),
			sidebarCtx.rebuild()
		]);
		await extensionCtx.dispose();
		await webviewCtx.dispose();
		await sidebarCtx.dispose();
	}
}

main().catch((e) => {
	console.error(e);
	process.exit(1);
});


--- apps/cli/vitest.config.ts ---
import { defineConfig, mergeConfig } from 'vitest/config';
import rootConfig from '../../vitest.config';

/**
 * CLI package Vitest configuration
 * Extends root config with CLI-specific settings
 *
 * Integration tests (.test.ts) spawn CLI processes and need more time.
 * The 30s timeout is reasonable now that auto-update network calls are skipped
 * when TASKMASTER_SKIP_AUTO_UPDATE=1 or NODE_ENV=test.
 */
export default mergeConfig(
	rootConfig,
	defineConfig({
		test: {
			// CLI-specific test patterns
			include: [
				'tests/**/*.test.ts',
				'tests/**/*.spec.ts',
				'src/**/*.test.ts',
				'src/**/*.spec.ts'
			],
			// Integration tests spawn CLI processes - 30s is reasonable with optimized startup
			testTimeout: 30000,
			hookTimeout: 15000
		}
	})
);


--- apps/mcp/vitest.config.ts ---
import { defineConfig, mergeConfig } from 'vitest/config';
import rootConfig from '../../vitest.config';

/**
 * MCP package Vitest configuration
 * Extends root config with MCP-specific settings
 */
export default mergeConfig(
	rootConfig,
	defineConfig({
		test: {
			// MCP-specific test patterns
			include: [
				'tests/**/*.test.ts',
				'tests/**/*.spec.ts',
				'src/**/*.test.ts',
				'src/**/*.spec.ts'
			]
		}
	})
);


--- apps/cli/src/command-registry.ts ---
/**
 * @fileoverview Centralized Command Registry
 * Provides a single location for registering all CLI commands
 */

import type { Command } from 'commander';

import { AuthCommand } from './commands/auth.command.js';
import { AutopilotCommand } from './commands/autopilot/index.js';
import { BriefsCommand } from './commands/briefs.command.js';
import { ContextCommand } from './commands/context.command.js';
import { ExportCommand, ExportTagCommand } from './commands/export.command.js';
import { GenerateCommand } from './commands/generate.command.js';
// Import all commands
import { ListTasksCommand } from './commands/list.command.js';
import { LoginCommand } from './commands/login.command.js';
import { LogoutCommand } from './commands/logout.command.js';
import { NextCommand } from './commands/next.command.js';
import { SetStatusCommand } from './commands/set-status.command.js';
import { ShowCommand } from './commands/show.command.js';
import { StartCommand } from './commands/start.command.js';
import { TagsCommand } from './commands/tags.command.js';

/**
 * Command metadata for registration
 */
export interface CommandMetadata {
	name: string;
	description: string;
	commandClass: typeof Command;
	category?: 'task' | 'auth' | 'utility' | 'development';
}

/**
 * Registry of all available commands
 */
export class CommandRegistry {
	/**
	 * All available commands with their metadata
	 */
	private static commands: CommandMetadata[] = [
		// Task Management Commands
		{
			name: 'list',
			description: 'List all tasks with filtering and status overview',
			commandClass: ListTasksCommand as any,
			category: 'task'
		},
		{
			name: 'show',
			description: 'Display detailed information about a specific task',
			commandClass: ShowCommand as any,
			category: 'task'
		},
		{
			name: 'next',
			description: 'Find the next available task to work on',
			commandClass: NextCommand as any,
			category: 'task'
		},
		{
			name: 'start',
			description: 'Start working on a task with claude-code',
			commandClass: StartCommand as any,
			category: 'task'
		},
		{
			name: 'set-status',
			description: 'Update the status of one or more tasks',
			commandClass: SetStatusCommand as any,
			category: 'task'
		},
		{
			name: 'export',
			description: 'Export tasks to Hamster by creating a new brief',
			commandClass: ExportCommand as any,
			category: 'task'
		},
		{
			name: 'export-tag',
			description: 'Export a specific tag to Hamster',
			commandClass: ExportTagCommand as any,
			category: 'task'
		},
		{
			name: 'autopilot',
			description:
				'AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)',
			commandClass: AutopilotCommand as any,
			category: 'development'
		},

		// Authentication & Context Commands
		{
			name: 'auth',
			description: 'Manage authentication with tryhamster.com',
			commandClass: AuthCommand as any,
			category: 'auth'
		},
		{
			name: 'login',
			description: 'Login to Hamster (alias for "auth login")',
			commandClass: LoginCommand as any,
			category: 'auth'
		},
		{
			name: 'logout',
			description: 'Logout from Hamster (alias for "auth logout")',
			commandClass: LogoutCommand as any,
			category: 'auth'
		},
		{
			name: 'context',
			description: 'Manage workspace context (organization/brief)',
			commandClass: ContextCommand as any,
			category: 'auth'
		},
		{
			name: 'tags',
			description: 'Manage tags for task organization',
			commandClass: TagsCommand as any,
			category: 'task'
		},
		{
			name: 'briefs',
			description: 'Manage briefs (Hamster only)',
			commandClass: BriefsCommand as any,
			category: 'task'
		},
		{
			name: 'generate',
			description: 'Generate individual task files from tasks.json',
			commandClass: GenerateCommand as any,
			category: 'utility'
		}
	];

	/**
	 * Register all commands on a program instance
	 * @param program - Commander program to register commands on
	 */
	static registerAll(program: Command): void {
		for (const cmd of this.commands) {
			this.registerCommand(program, cmd);
		}
	}

	/**
	 * Register specific commands by category
	 * @param program - Commander program to register commands on
	 * @param category - Category of commands to register
	 */
	static registerByCategory(
		program: Command,
		category: 'task' | 'auth' | 'utility' | 'development'
	): void {
		const categoryCommands = this.commands.filter(
			(cmd) => cmd.category === category
		);

		for (const cmd of categoryCommands) {
			this.registerCommand(program, cmd);
		}
	}

	/**
	 * Register a single command by name
	 * @param program - Commander program to register the command on
	 * @param name - Name of the command to register
	 */
	static registerByName(program: Command, name: string): void {
		const cmd = this.commands.find((c) => c.name === name);
		if (cmd) {
			this.registerCommand(program, cmd);
		} else {
			throw new Error(`Command '${name}' not found in registry`);
		}
	}

	/**
	 * Register a single command
	 * @param program - Commander program to register the command on
	 * @param metadata - Command metadata
	 */
	private static registerCommand(
		program: Command,
		metadata: CommandMetadata
	): void {
		const CommandClass = metadata.commandClass as any;

		// Use the static registration method that all commands have
		if (CommandClass.registerOn) {
			CommandClass.registerOn(program);
		} else if (CommandClass.register) {
			CommandClass.register(program);
		} else {
			// Fallback to creating instance and adding
			const instance = new CommandClass();
			program.addCommand(instance);
		}
	}

	/**
	 * Get all registered command names
	 */
	static getCommandNames(): string[] {
		return this.commands.map((cmd) => cmd.name);
	}

	/**
	 * Get commands by category
	 */
	static getCommandsByCategory(
		category: 'task' | 'auth' | 'utility' | 'development'
	): CommandMetadata[] {
		return this.commands.filter((cmd) => cmd.category === category);
	}

	/**
	 * Add a new command to the registry
	 * @param metadata - Command metadata to add
	 */
	static addCommand(metadata: CommandMetadata): void {
		// Check if command already exists
		if (this.commands.some((cmd) => cmd.name === metadata.name)) {
			throw new Error(`Command '${metadata.name}' already exists in registry`);
		}

		this.commands.push(metadata);
	}

	/**
	 * Remove a command from the registry
	 * @param name - Name of the command to remove
	 */
	static removeCommand(name: string): boolean {
		const index = this.commands.findIndex((cmd) => cmd.name === name);
		if (index >= 0) {
			this.commands.splice(index, 1);
			return true;
		}
		return false;
	}

	/**
	 * Get command metadata by name
	 * @param name - Name of the command
	 */
	static getCommand(name: string): CommandMetadata | undefined {
		return this.commands.find((cmd) => cmd.name === name);
	}

	/**
	 * Check if a command exists
	 * @param name - Name of the command
	 */
	static hasCommand(name: string): boolean {
		return this.commands.some((cmd) => cmd.name === name);
	}

	/**
	 * Get a formatted list of all commands for display
	 */
	static getFormattedCommandList(): string {
		const categories = {
			task: 'Task Management',
			auth: 'Authentication & Context',
			utility: 'Utilities',
			development: 'Development'
		};

		let output = '';

		for (const [category, title] of Object.entries(categories)) {
			const cmds = this.getCommandsByCategory(
				category as keyof typeof categories
			);
			if (cmds.length > 0) {
				output += `\n${title}:\n`;
				for (const cmd of cmds) {
					output += `  ${cmd.name.padEnd(20)} ${cmd.description}\n`;
				}
			}
		}

		return output;
	}
}

/**
 * Convenience function to register all CLI commands
 * @param program - Commander program instance
 */
export function registerAllCommands(program: Command): void {
	CommandRegistry.registerAll(program);
}

/**
 * Convenience function to register commands by category
 * @param program - Commander program instance
 * @param category - Category to register
 */
export function registerCommandsByCategory(
	program: Command,
	category: 'task' | 'auth' | 'utility' | 'development'
): void {
	CommandRegistry.registerByCategory(program, category);
}

// Export the registry for direct access if needed
export default CommandRegistry;


--- apps/extension/src/extension.ts ---
/**
 * TaskMaster Extension - Simplified Architecture
 * Only using patterns where they add real value
 */

import * as vscode from 'vscode';
import { ConfigService } from './services/config-service';
import { PollingService } from './services/polling-service';
import { createPollingStrategy } from './services/polling-strategies';
import { SidebarWebviewManager } from './services/sidebar-webview-manager';
import { TaskRepository } from './services/task-repository';
import { TerminalManager } from './services/terminal-manager';
import { WebviewManager } from './services/webview-manager';
import { EventEmitter } from './utils/event-emitter';
import { ExtensionLogger } from './utils/logger';
import {
	MCPClientManager,
	createMCPConfigFromSettings
} from './utils/mcpClient';
import { TaskMasterApi } from './utils/task-master-api';

let logger: ExtensionLogger;
let mcpClient: MCPClientManager;
let api: TaskMasterApi;
let repository: TaskRepository;
let terminalManager: TerminalManager;
let pollingService: PollingService;
let webviewManager: WebviewManager;
let events: EventEmitter;
let configService: ConfigService;
let sidebarManager: SidebarWebviewManager;

export async function activate(context: vscode.ExtensionContext) {
	try {
		// Initialize logger (needed to prevent MCP stdio issues)
		logger = ExtensionLogger.getInstance();
		logger.log('🎉 TaskMaster Extension activating...');

		// Simple event emitter for webview communication
		events = new EventEmitter();

		// Initialize MCP client
		mcpClient = new MCPClientManager(createMCPConfigFromSettings());

		// Initialize API
		api = new TaskMasterApi(mcpClient);

		// Repository with caching (actually useful for performance)
		repository = new TaskRepository(api, logger);

		// Terminal manager for task execution
		terminalManager = new TerminalManager(context, logger);

		// Config service for TaskMaster config.json
		configService = new ConfigService(logger);

		// Polling service with strategy pattern (makes sense for different polling behaviors)
		const strategy = createPollingStrategy(
			vscode.workspace.getConfiguration('taskmaster')
		);
		pollingService = new PollingService(repository, strategy, logger);

		// Webview manager (cleaner than global panel array) - create before connection
		webviewManager = new WebviewManager(
			context,
			repository,
			events,
			logger,
			terminalManager
		);
		webviewManager.setConfigService(configService);

		// Sidebar webview manager
		sidebarManager = new SidebarWebviewManager(context.extensionUri);

		// Initialize connection
		await initializeConnection();

		// Set MCP client and API after connection
		webviewManager.setMCPClient(mcpClient);
		webviewManager.setApi(api);
		sidebarManager.setApi(api);

		// Register commands
		registerCommands(context);

		// Handle polling lifecycle
		events.on('webview:opened', () => {
			if (webviewManager.getPanelCount() === 1) {
				pollingService.start();
			}
		});

		events.on('webview:closed', () => {
			if (webviewManager.getPanelCount() === 0) {
				pollingService.stop();
			}
		});

		// Forward repository updates to webviews
		repository.on('tasks:updated', (tasks) => {
			webviewManager.broadcast('tasksUpdated', { tasks, source: 'polling' });
		});

		logger.log('✅ TaskMaster Extension activated');
	} catch (error) {
		logger?.error('Failed to activate', error);
		vscode.window.showErrorMessage(
			`Failed to activate TaskMaster: ${error instanceof Error ? error.message : 'Unknown error'}`
		);
	}
}

async function initializeConnection() {
	try {
		logger.log('🔗 Connecting to TaskMaster...');

		// Notify webviews that we're connecting
		if (webviewManager) {
			webviewManager.broadcast('connectionStatus', {
				isConnected: false,
				status: 'Connecting...'
			});
		}

		await mcpClient.connect();

		const testResult = await api.testConnection();

		if (testResult.success) {
			logger.log('✅ Connected to TaskMaster');
			vscode.window.showInformationMessage('TaskMaster connected!');

			// Notify webviews that we're connected
			if (webviewManager) {
				webviewManager.broadcast('connectionStatus', {
					isConnected: true,
					status: 'Connected'
				});
			}
			if (sidebarManager) {
				sidebarManager.updateConnectionStatus();
			}
		} else {
			throw new Error(testResult.error || 'Connection test failed');
		}
	} catch (error) {
		logger.error('Connection failed', error);

		// Notify webviews that connection failed
		if (webviewManager) {
			webviewManager.broadcast('connectionStatus', {
				isConnected: false,
				status: 'Disconnected'
			});
		}
		if (sidebarManager) {
			sidebarManager.updateConnectionStatus();
		}

		handleConnectionError(error);
	}
}

function handleConnectionError(error: any) {
	const message = error instanceof Error ? error.message : 'Unknown error';

	if (message.includes('ENOENT') && message.includes('npx')) {
		vscode.window
			.showWarningMessage(
				'TaskMaster: npx not found. Please ensure Node.js is installed.',
				'Open Settings'
			)
			.then((action) => {
				if (action === 'Open Settings') {
					vscode.commands.executeCommand(
						'workbench.action.openSettings',
						'@ext:Hamster.task-master-hamster taskmaster'
					);
				}
			});
	} else {
		vscode.window.showWarningMessage(
			`TaskMaster connection failed: ${message}`
		);
	}
}

function registerCommands(context: vscode.ExtensionContext) {
	// Main command
	context.subscriptions.push(
		vscode.commands.registerCommand('tm.showKanbanBoard', async () => {
			await webviewManager.createOrShowPanel();
		})
	);

	// Utility commands
	context.subscriptions.push(
		vscode.commands.registerCommand('tm.refreshTasks', async () => {
			await repository.refresh();
			vscode.window.showInformationMessage('Tasks refreshed!');
		})
	);

	context.subscriptions.push(
		vscode.commands.registerCommand('tm.openSettings', () => {
			vscode.commands.executeCommand(
				'workbench.action.openSettings',
				'@ext:Hamster.task-master-hamster taskmaster'
			);
		})
	);

	// Register sidebar view provider

	context.subscriptions.push(
		vscode.window.registerWebviewViewProvider(
			'taskmaster.welcome',
			sidebarManager
		)
	);
}

export async function deactivate() {
	logger?.log('👋 TaskMaster Extension deactivating...');
	pollingService?.stop();
	webviewManager?.dispose();
	await terminalManager?.dispose();
	api?.destroy();
	mcpClient?.disconnect();
}


--- apps/cli/src/index.ts ---
/**
 * @fileoverview Main entry point for @tm/cli package
 * Exports all public APIs for the CLI presentation layer
 */

// Commands
export { ListTasksCommand } from './commands/list.command.js';
export { ShowCommand } from './commands/show.command.js';
export { NextCommand } from './commands/next.command.js';
export { AuthCommand } from './commands/auth.command.js';
export { ContextCommand } from './commands/context.command.js';
export { StartCommand } from './commands/start.command.js';
export { SetStatusCommand } from './commands/set-status.command.js';
export { ExportCommand } from './commands/export.command.js';
export { TagsCommand } from './commands/tags.command.js';
export { BriefsCommand } from './commands/briefs.command.js';

// Command Registry
export {
	CommandRegistry,
	registerAllCommands,
	registerCommandsByCategory,
	type CommandMetadata
} from './command-registry.js';

// General utilities (error handling, auto-update, etc.)
export * from './utils/index.js';

// UI utilities - exported only via ui namespace to avoid naming conflicts
// Import via: import { ui } from '@tm/cli'; ui.displayBanner();
export * as ui from './ui/index.js';

export { runInteractiveSetup } from './commands/models/index.js';

// Re-export commonly used types from tm-core
export type {
	Task,
	TaskStatus,
	TaskPriority,
	TmCore
} from '@tm/core';


--- apps/extension/src/index.ts ---
console.log('hello world');


--- apps/mcp/src/index.ts ---
/**
 * @fileoverview Main entry point for @tm/mcp package
 * Exports all MCP tool registration functions
 */

export * from './tools/autopilot/index.js';
export * from './tools/tasks/index.js';
// TODO: Re-enable when TypeScript dependency tools are implemented
// export * from './tools/dependencies/index.js';
export * from './shared/utils.js';
export * from './shared/types.js';


--- assets/AGENTS.md ---
# Task Master AI - Agent Integration Guide

## Essential Commands

### Core Workflow Commands

```bash
# Project Setup
task-master init                                    # Initialize Task Master in current project
task-master parse-prd .taskmaster/docs/prd.md       # Generate tasks from PRD document
task-master models --setup                        # Configure AI models interactively

# Daily Development Workflow
task-master list                                   # Show all tasks with status
task-master next                                   # Get next available task to work on
task-master show <id>                             # View detailed task information (e.g., task-master show 1.2)
task-master set-status --id=<id> --status=done    # Mark task complete

# Task Management
task-master add-task --prompt="description" --research        # Add new task with AI assistance
task-master expand --id=<id> --research --force              # Break task into subtasks
task-master update-task --id=<id> --prompt="changes"         # Update specific task
task-master update --from=<id> --prompt="changes"            # Update multiple tasks from ID onwards
task-master update-subtask --id=<id> --prompt="notes"        # Add implementation notes to subtask

# Analysis & Planning
task-master analyze-complexity --research          # Analyze task complexity
task-master complexity-report                      # View complexity analysis
task-master expand --all --research               # Expand all eligible tasks

# Dependencies & Organization
task-master add-dependency --id=<id> --depends-on=<id>       # Add task dependency
task-master move --from=<id> --to=<id>                       # Reorganize task hierarchy
task-master validate-dependencies                            # Check for dependency issues
task-master generate                                         # Update task markdown files (usually auto-called)
```

## Key Files & Project Structure

### Core Files

- `.taskmaster/tasks/tasks.json` - Main task data file (auto-managed)
- `.taskmaster/config.json` - AI model configuration (use `task-master models` to modify)
- `.taskmaster/docs/prd.md` - Product Requirements Document for parsing (`.md` extension recommended for better editor support)
- `.taskmaster/tasks/*.txt` - Individual task files (auto-generated from tasks.json)
- `.env` - API keys for CLI usage

**PRD File Format:** While both `.txt` and `.md` extensions work, **`.md` is recommended** because:
- Markdown syntax highlighting in editors improves readability
- Proper rendering when previewing in VS Code, GitHub, or other tools
- Better collaboration through formatted documentation

### Claude Code Integration Files

- `CLAUDE.md` - Auto-loaded context for Claude Code (this file)
- `.claude/settings.json` - Claude Code tool allowlist and preferences
- `.claude/commands/` - Custom slash commands for repeated workflows
- `.mcp.json` - MCP server configuration (project-specific)

### Directory Structure

```
project/
├── .taskmaster/
│   ├── tasks/              # Task files directory
│   │   ├── tasks.json      # Main task database
│   │   ├── task-1.md      # Individual task files
│   │   └── task-2.md
│   ├── docs/              # Documentation directory
│   │   ├── prd.md         # Product requirements (.md recommended)
│   ├── reports/           # Analysis reports directory
│   │   └── task-complexity-report.json
│   ├── templates/         # Template files
│   │   └── example_prd.md  # Example PRD template (.md recommended)
│   └── config.json        # AI models & settings
├── .claude/
│   ├── settings.json      # Claude Code configuration
│   └── commands/         # Custom slash commands
├── .env                  # API keys
├── .mcp.json            # MCP configuration
└── CLAUDE.md            # This file - auto-loaded by Claude Code
```

## MCP Integration

Task Master provides an MCP server that Claude Code can connect to. Configure in `.mcp.json`:

```json
{
  "mcpServers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"],
      "env": {
        "TASK_MASTER_TOOLS": "core",
        "ANTHROPIC_API_KEY": "your_key_here",
        "PERPLEXITY_API_KEY": "your_key_here",
        "OPENAI_API_KEY": "OPENAI_API_KEY_HERE",
        "GOOGLE_API_KEY": "GOOGLE_API_KEY_HERE",
        "XAI_API_KEY": "XAI_API_KEY_HERE",
        "OPENROUTER_API_KEY": "OPENROUTER_API_KEY_HERE",
        "MISTRAL_API_KEY": "MISTRAL_API_KEY_HERE",
        "AZURE_OPENAI_API_KEY": "AZURE_OPENAI_API_KEY_HERE",
        "OLLAMA_API_KEY": "OLLAMA_API_KEY_HERE"
      }
    }
  }
}
```

### MCP Tool Tiers

Default: `core` (7 tools). Set via `TASK_MASTER_TOOLS` env var.

| Tier | Count | Tools |
|------|-------|-------|
| `core` | 7 | `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task` |
| `standard` | 14 | core + `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `add_task`, `complexity_report` |
| `all` | 44+ | standard + dependencies, tags, research, autopilot, scoping, models, rules |

**Upgrade when tool unavailable:** Edit MCP config, change `TASK_MASTER_TOOLS` from `"core"` to `"standard"` or `"all"`, restart MCP.

### Essential MCP Tools

```javascript
help; // = shows available taskmaster commands
// Project setup
initialize_project; // = task-master init
parse_prd; // = task-master parse-prd

// Daily workflow
get_tasks; // = task-master list
next_task; // = task-master next
get_task; // = task-master show <id>
set_task_status; // = task-master set-status

// Task management
add_task; // = task-master add-task
expand_task; // = task-master expand
update_task; // = task-master update-task
update_subtask; // = task-master update-subtask
update; // = task-master update

// Analysis
analyze_project_complexity; // = task-master analyze-complexity
complexity_report; // = task-master complexity-report
```

## Claude Code Workflow Integration

### Standard Development Workflow

#### 1. Project Initialization

```bash
# Initialize Task Master
task-master init

# Create or obtain PRD, then parse it (use .md extension for better editor support)
task-master parse-prd .taskmaster/docs/prd.md

# Analyze complexity and expand tasks
task-master analyze-complexity --research
task-master expand --all --research
```

If tasks already exist, another PRD can be parsed (with new information only!) using parse-prd with --append flag. This will add the generated tasks to the existing list of tasks..

#### 2. Daily Development Loop

```bash
# Start each session
task-master next                           # Find next available task
task-master show <id>                     # Review task details

# During implementation, check in code context into the tasks and subtasks
task-master update-subtask --id=<id> --prompt="implementation notes..."

# Complete tasks
task-master set-status --id=<id> --status=done
```

#### 3. Multi-Claude Workflows

For complex projects, use multiple Claude Code sessions:

```bash
# Terminal 1: Main implementation
cd project && claude

# Terminal 2: Testing and validation
cd project-test-worktree && claude

# Terminal 3: Documentation updates
cd project-docs-worktree && claude
```

### Custom Slash Commands

Create `.claude/commands/taskmaster-next.md`:

```markdown
Find the next available Task Master task and show its details.

Steps:

1. Run `task-master next` to get the next task
2. If a task is available, run `task-master show <id>` for full details
3. Provide a summary of what needs to be implemented
4. Suggest the first implementation step
```

Create `.claude/commands/taskmaster-complete.md`:

```markdown
Complete a Task Master task: $ARGUMENTS

Steps:

1. Review the current task with `task-master show $ARGUMENTS`
2. Verify all implementation is complete
3. Run any tests related to this task
4. Mark as complete: `task-master set-status --id=$ARGUMENTS --status=done`
5. Show the next available task with `task-master next`
```

## Tool Allowlist Recommendations

Add to `.claude/settings.json`:

```json
{
  "allowedTools": [
    "Edit",
    "Bash(task-master *)",
    "Bash(git commit:*)",
    "Bash(git add:*)",
    "Bash(npm run *)",
    "mcp__task_master_ai__*"
  ]
}
```

## Configuration & Setup

### API Keys Required

At least **one** of these API keys must be configured:

- `ANTHROPIC_API_KEY` (Claude models) - **Recommended**
- `PERPLEXITY_API_KEY` (Research features) - **Highly recommended**
- `OPENAI_API_KEY` (GPT models)
- `GOOGLE_API_KEY` (Gemini models)
- `MISTRAL_API_KEY` (Mistral models)
- `OPENROUTER_API_KEY` (Multiple models)
- `XAI_API_KEY` (Grok models)

An API key is required for any provider used across any of the 3 roles defined in the `models` command.

### Model Configuration

```bash
# Interactive setup (recommended)
task-master models --setup

# Set specific models
task-master models --set-main claude-3-5-sonnet-20241022
task-master models --set-research perplexity-llama-3.1-sonar-large-128k-online
task-master models --set-fallback gpt-4o-mini
```

## Task Structure & IDs

### Task ID Format

- Main tasks: `1`, `2`, `3`, etc.
- Subtasks: `1.1`, `1.2`, `2.1`, etc.
- Sub-subtasks: `1.1.1`, `1.1.2`, etc.

### Task Status Values

- `pending` - Ready to work on
- `in-progress` - Currently being worked on
- `done` - Completed and verified
- `deferred` - Postponed
- `cancelled` - No longer needed
- `blocked` - Waiting on external factors

### Task Fields

```json
{
  "id": "1.2",
  "title": "Implement user authentication",
  "description": "Set up JWT-based auth system",
  "status": "pending",
  "priority": "high",
  "dependencies": ["1.1"],
  "details": "Use bcrypt for hashing, JWT for tokens...",
  "testStrategy": "Unit tests for auth functions, integration tests for login flow",
  "subtasks": []
}
```

## Claude Code Best Practices with Task Master

### Context Management

- Use `/clear` between different tasks to maintain focus
- This CLAUDE.md file is automatically loaded for context
- Use `task-master show <id>` to pull specific task context when needed

### Iterative Implementation

1. `task-master show <subtask-id>` - Understand requirements
2. Explore codebase and plan implementation
3. `task-master update-subtask --id=<id> --prompt="detailed plan"` - Log plan
4. `task-master set-status --id=<id> --status=in-progress` - Start work
5. Implement code following logged plan
6. `task-master update-subtask --id=<id> --prompt="what worked/didn't work"` - Log progress
7. `task-master set-status --id=<id> --status=done` - Complete task

### Complex Workflows with Checklists

For large migrations or multi-step processes:

1. Create a markdown PRD file describing the new changes: `touch task-migration-checklist.md` (prds can be .txt or .md)
2. Use Taskmaster to parse the new prd with `task-master parse-prd --append` (also available in MCP)
3. Use Taskmaster to expand the newly generated tasks into subtasks. Consdier using `analyze-complexity` with the correct --to and --from IDs (the new ids) to identify the ideal subtask amounts for each task. Then expand them.
4. Work through items systematically, checking them off as completed
5. Use `task-master update-subtask` to log progress on each task/subtask and/or updating/researching them before/during implementation if getting stuck

### Git Integration

Task Master works well with `gh` CLI:

```bash
# Create PR for completed task
gh pr create --title "Complete task 1.2: User authentication" --body "Implements JWT auth system as specified in task 1.2"

# Reference task in commits
git commit -m "feat: implement JWT auth (task 1.2)"
```

### Parallel Development with Git Worktrees

```bash
# Create worktrees for parallel task development
git worktree add ../project-auth feature/auth-system
git worktree add ../project-api feature/api-refactor

# Run Claude Code in each worktree
cd ../project-auth && claude    # Terminal 1: Auth work
cd ../project-api && claude     # Terminal 2: API work
```

## Troubleshooting

### AI Commands Failing

```bash
# Check API keys are configured
cat .env                           # For CLI usage

# Verify model configuration
task-master models

# Test with different model
task-master models --set-fallback gpt-4o-mini
```

### MCP Connection Issues

- Check `.mcp.json` configuration
- Verify Node.js installation
- Use `--mcp-debug` flag when starting Claude Code
- Use CLI as fallback if MCP unavailable

### Task File Sync Issues

```bash
# Regenerate task files from tasks.json
task-master generate

# Fix dependency issues
task-master fix-dependencies
```

DO NOT RE-INITIALIZE. That will not do anything beyond re-adding the same Taskmaster core files.

## Important Notes

### AI-Powered Operations

These commands make AI calls and may take up to a minute:

- `parse_prd` / `task-master parse-prd`
- `analyze_project_complexity` / `task-master analyze-complexity`
- `expand_task` / `task-master expand`
- `expand_all` / `task-master expand --all`
- `add_task` / `task-master add-task`
- `update` / `task-master update`
- `update_task` / `task-master update-task`
- `update_subtask` / `task-master update-subtask`

### File Management

- Never manually edit `tasks.json` - use commands instead
- Never manually edit `.taskmaster/config.json` - use `task-master models`
- Task markdown files in `tasks/` are auto-generated
- Run `task-master generate` after manual changes to tasks.json

### Claude Code Session Management

- Use `/clear` frequently to maintain focused context
- Create custom slash commands for repeated Task Master workflows
- Configure tool allowlist to streamline permissions
- Use headless mode for automation: `claude -p "task-master next"`

### Multi-Task Updates

- Use `update --from=<id>` to update multiple future tasks
- Use `update-task --id=<id>` for single task updates
- Use `update-subtask --id=<id>` for implementation logging

### Research Mode

- Add `--research` flag for research-based AI enhancement
- Requires a research model API key like Perplexity (`PERPLEXITY_API_KEY`) in environment
- Provides more informed task creation and updates
- Recommended for complex technical tasks

---

_This guide ensures Claude Code has immediate access to Task Master's essential functionality for agentic development workflows._


--- assets/GEMINI.md ---
# Gemini CLI-Specific Instructions

> **Note:** This file works alongside `AGENTS.md` (generic AI agent instructions). AGENTS.md contains the core Task Master commands and workflows for all AI agents. This file contains only Gemini CLI-specific features and integrations.

## MCP Configuration for Gemini CLI

Configure Task Master MCP server in `~/.gemini/settings.json`:

```json
{
  "mcpServers": {
    "task-master-ai": {
      "command": "npx",
      "args": ["-y", "task-master-ai"]
    }
  }
}
```

**Note:** API keys are configured via `task-master models --setup`, not in MCP configuration.

## Gemini CLI-Specific Features

### Session Management

Built-in session commands:

- `/chat` - Start new conversation while keeping context
- `/checkpoint save <name>` - Save session state
- `/checkpoint load <name>` - Resume saved session
- `/memory show` - View loaded context

Both `AGENTS.md` and `GEMINI.md` are auto-loaded on every Gemini CLI session.

### Headless Mode for Automation

Non-interactive mode for scripts:

```bash
# Simple text response
gemini -p "What's the next task?"

# JSON output for parsing
gemini -p "List all pending tasks" --output-format json

# Stream events for long operations
gemini -p "Expand all tasks" --output-format stream-json
```

### Token Usage Monitoring

```bash
# In Gemini CLI session
/stats

# Shows: token usage, API costs, request counts
```

### Google Search Grounding

Leverage built-in Google Search as an alternative to Perplexity research mode:
- Best practices research
- Library documentation
- Security vulnerability checks
- Implementation patterns

## Important Differences from Other Agents

### No Slash Commands
Gemini CLI does not support custom slash commands (unlike Claude Code). Use natural language instead.

### No Tool Allowlist
Security is managed at the MCP level, not via agent configuration.

### Session Persistence
Use `/checkpoint` instead of git worktrees for managing multiple work contexts.

### Configuration Files
- Global: `~/.gemini/settings.json`
- Project: `.gemini/settings.json`
- **Not**: `.mcp.json` (that's for Claude Code)

## Recommended Model Configuration

For Gemini CLI users:

```bash
# Set Gemini as primary model
task-master models --set-main gemini-2.0-flash-exp
task-master models --set-fallback gemini-1.5-flash

# Optional: Use Perplexity for research (or rely on Google Search)
task-master models --set-research perplexity-llama-3.1-sonar-large-128k-online
```

## Your Role with Gemini CLI

As a Gemini CLI assistant with Task Master:

1. **Use MCP tools naturally** - They integrate transparently in conversation
2. **Reference files with @** - Leverage Gemini's file inclusion
3. **Save checkpoints** - Offer to save state after significant progress
4. **Monitor usage** - Remind users about `/stats` for long sessions
5. **Use Google Search** - Leverage search grounding for research

**Key Principle:** Focus on natural conversation. Task Master MCP tools work seamlessly with Gemini CLI's interface.

---

*See AGENTS.md for complete Task Master commands, workflows, and best practices.*


--- assets/hamster-art.txt ---
                                                                                          
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▓▒▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▓▒▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▓▒▒▓▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▓▒▓▓▒▓▒▓▓▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓████▓▓▓▓▓▓▓▒▒▒▓▓▓▒▓▓▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓████████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓█  ░░▓▓▒ ▒▓▓▓▓▒▒▒▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██  ▒▓░▒▒▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▓  ░   ██▒ ▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓██▒ ▓█░ ░   ▒██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓░▓ ▒▒▒▒▒░ ▒█▓▒ ▓██████▓█▓▓▓░▓▓████████▒ ▓▓█▒ ▒▒▒▒ ▓░█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░░ ░▒▓▓▓▒▒▒ ██▓▓ ▒▓    ░ ░▒▓░▒▒░░  ▒ ▓  ▓█▓█ ▒▓███▓ ▒▒█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒█ ▒▒█▓▓▒ ▒▒▒ ▒█▒██ ░▒▒▒░░░░░▒▒▒░▒▒▓▓▒▒▒░▓▓▒▓█ ▒░░▒▓█▒▒ █▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓░▒▒▒▒▒▒▒░░░░ █▒▒█▓▒▒▒▒▓▓▓▒▒░░░░▒░▒▒▓▓▒▒▒▒▒█ ░▓▓▒▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒░█▒▒▒▒░░ ▓█ ▒▓░▒░▒▓▓▓▓▓▓██▓▓▒░░░▒▓▒▓███▓▓█░▓░░▒▒▒▒▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 
 ▒▒▒▒▓▓▓▓▓▓▓▓▒▒▒▒▓░░▒▓▒▒░▒   ▓▒▒░▒▓▓▓██████▓▓▓▓▒░▒▓▓▓████████▒▓ ▒▒▒▒ ██▓▓▓▓▓█▒▒▓████▓▓▓▓▓ 
 ▒▒▒▓░░ ▒▓ ░░▒▒▒▒▒▓▓  ░▒▒░  ░▒▒▒▒▒▒▓████████▓▓▓█▓▒█▓▒▓█▒  ░▓██▓░░▒ ░██▓▒▓▓▓▓▒░▓░█ ▒▓ █▓▓▓ 
 ▓▓▒▓ ▓█ ▒░█▒▒▓▒▒▒▒▓██ ░▒▒▒▒▒▒▒▒▒▓▒▓░     ▒▓▒▒▓▓▓▒█▓▓▓▒▒▒██▒▒█▓▓░▓██▓▓▓███▓█ ▒█  ▒█░▒██▓▓ 
 ▓ ▓▓░ ▓█  █▒ ▓▒▒▒▓▓▒██░ ░░▒▒▓▓▒▒▒▓▓██████▓▒▓▓▒▓▓▓▓▒▓▓██████████▒ █▓▓▓▓▒ ▓░▒ ▒█▓▒█  ░▓▒░▓ 
 ▓▒ ██░ ████▓ ░▒█▒ ▓▓▓░ ░▒▒▒▒▒▒▓▓▒▒▓█░    ▓▓▓▒▓▒▒▒▓▒▓▒▓▒    ▓▓▓▒▒▒░▓▓▒▓█ ▒█▒░▓█▓████▓ ░█▓ 
 ░▒▒  ▓██▒▒▒█▒██░ ▓▓▓  ░░▒▒░▒▓▓▒▓▒▓▓   ░█  ▓▓▒▒▒▒▒▒▒▒▓█  ██  ▒▓▓█▓▒ █▓▓▓█ ▒███▒░ ▒█▒▒█▒░▓ 
 ░ ░▓███▓▒▒ ▓██░░▓▓▓░░▒▒░▒▒▒▒░▒▒▒▒▒     ▓  ▓▒▒▒▒▓▒▓▒▒▒▓       ▒▓▒▒▒░▒█▒▓██ ▓██▒████▒   ▓▓ 
 ▓▓▓░  ████▓█▒▒░▒██▓░░░░░▓   ░    ░  ▒     ░▒▒▓▓▓▓█████▒   ░  ▒▒▒░▓░ ███▓   ░▓▒▓█▓░ ███▓▒ 
 ▒▒▒▓▓  ▓██▓▒▒▒░ ▒▓ ░░░░░░▒▒▒█████▓▓      ▒▓▓▓▓██████████▓▓▓▓▓▓████▒▒░   ▒░▓▒▒░   ▒█▓▓▓▓▓ 
 ▒▒▒▒▓█▒   ▒▒▓█▓▓   ░▒▒░▒▒▓▓▒▒▒▒▒▒▒▒█████▓▓▓▒▒▓█▓░▒▓█▓▒███▓▒██▒▒▒▒▒▒▓▒░ ▒▓▒▒▒▓▓▓▒▒█▓▒▒▒▒▒ 
 ▒▒▒▒▒█ ░▒▒▒▓▒▓▓███  ░▒▒▒▒▒▓▓▒▒▒▓███▓██▓▒▒████▓▒ ░▒▓▓░  ████▒▓████▓▓██▒ ▓▓▓▓▓▓▓▓ ▓█▒▒▒▒▒▒ 
 ▒▒▒▒▒█ ░▒▒░▓▓▓▓▓▓█▓░░▒▒▒▒▒▓▓▓█▓▓▒▓▓▓██▓█████████   ▒  ██████▓█▓▒██▓▓█▓▒░▒▒▒▒▒▒▓▒ ▓▓▒▒▒▒▒ 
 ▒▒▒▒▒█ ▒▒░▒▒▒▒▓▒▓▒▓ ░▓▓▓██▒▒▒▒▒▒░░▒▓▒░░█▓███▓█████▒▒███████░ ▒▓▓▒▒▒▓▓▓██▒▒▒▒▒▒▓░░█▓▒▒▒▒▒ 
 ▒▒▒▒▒█▒░▒░▒▓▒▒▓▒▒▒▓█ ░▒▒▒▒▓▒▒▒▒▒█▓▓▒    ▓███▓▓▓▒▓▓  ▓███▓▓  ▒▒▓▓▓█▒▓▓▓▒ ░▓█▓▒▒▓ █▓▒▒▒▒▒▒ 
 ▒▒▒▒▒█ ░▒░░░▓▒▒▒█▒▒▒░ ▒▒▓▒▒▓███▓▓▒▒▒██▒    ░████░░██▒     ▒▓▓▓▓▓▓▓▓█▓▒▓░▒▒▒▒▓▓▒ █▓▒▒▒▒▒▒ 
 ▒▒▒▒▒▓ ░▒▒░░▒▓▒▒▒▒▒▒▒ ░▒▒█▒██▓▓▓██▓▒▓▓██▒       ░██    █▓▒▒▓▓██▓██▓▓██ ▒▓▒▒▒▒▒░░█▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▓▓ ░▒░░▒░▒▒▒▒▒▒▒░▒░░▓▓▒▒▒▓▓▓▓▓▒▓▓▓██             ██▒▓▓█▓█▒▓▓▓▓▓▒ ▒█▓▒▒▒▒▒ █▓▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▓▒░▒▒░░▒▒▒▒▓▒▒▒░  █░▒▒▒▒▓▓▒▒▓▒▓▓▓▒▓█ ▒█▓▒░░▒▒░ ██▓▓█▓▓▒█▒▒▓▒▓▓  ▒▒▒▒▒▒▒░ ▓▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▓ ▒▒░░░░░░▒▒▒▒▓▒▒ ░▒▓▓▓▓▓▓▓▓▓▓▒▓▓▓██  ▓█▓▓█▓░░██▓▓▓▒▓▒▓▒▓█▒▒ ░▓▓▒▓▒▒▒░▒█▓▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▓▓ ░░▒▒▒░▒▒▒▒▒▓▒▒░ ░▒▒▓▓▓▓▓▒▒▒▒▒▒▒▓██▓      ▒█▓▒▒▓▒▓▓▓█▓▓░  ▒▓▓▒▒▒░░  █▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▓░░▓▒░░░░░▒▒░▒▒▒▒▒░   ░▒░▒▓▓▒▓▓▓▒▒▒▓████████▓░▒▓▒▓▒▓░░  ░▒▓▒▒▒▒▓▒▒░░▓▓▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▒▓  ▒▒▒░░░░░░▒▒▒▒▒▒▒▒▒░░░░░▒▒▒▒▒▒▒▒░ ░▒██▓░ ░▓▒▒▒▒░ ▒▒▒█▓▓▒▒▒▒▒▒▒░ ▒▓▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▒▓█  ░▒▒░░▒░░▒▒▒▒▒▓▒▒▓▓▓▓▒▒▒░░░░▒▒▒▒▒░    ░▒▒░░░░▒▓▓▓▓▓█▓▓▓▒▒▒▒░  ▓▓▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▒▓ ░ ▒░▒▒▒░▒▒▒▒░▓▓▒▒▒▓▓▒▒▓▓▒▒▓▓▒▒▒░▒▒▒▒▒▒▒▒▓▓▓▓▓▓█▓██▓▓▓▒▓▒▒▒▒▒░ ▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▓█ ░▒░ ░░░░░▒▒▒▒░░▓█▒▒▒▓▓▒▒▓▓▒▒▒▒▒▓▒▓▒▓▒▓▒▒▒▓▒▓███▓▓▓▓▓▒▓▓▒▒░ ░ ▓█▓▒▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▒▓  ▒▒▒░░░░░░▒░ ▒▒▒▒░▒▒▓▓▓██▓▓▓▓▓▓█░█▒▒█▒▓██▓███▓▓▓▓▓▓▓▓▓▓▒██▒▒░  ▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▓▓░░▒▒░░░░░▒▒▒▒▒▒▒▒▒▒▓▒▒▓▓▒▒▓█▓▓██▓█████▓▓▓██▓██▓█▓▓▓▓▓▓▓▓▓▒▒▒▓▓░ █▓▒▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▓▒ ▒▒░░░░▒▒░░░▒▒▒▒▒▒▓▒▒▒▒▒▒██▒█▓▒▓▓▓▓▓▓▓█▓▓▓█▓▒▒▓██▒▒▒▒▒█▓▓▒▓▓▒▓▓  ▓▒▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▒▓▓ ▒▒░░░░▒░▒▒▒▒▒▒▓▒▒▒▓▓▓▓▓▒▒░▒▒▒▓▓█▓▓▓▓▒▓▓▓▒▒▓▓▓▒▒▒▓▓▓▓▓▓▓██▒▓▓▓▒░░▓▓▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▓▒ ▒▒░░░░▒▒▒▒▒▒▒▒▓▓▓▓▒▓▓▒▒▒▒▓▒▒▒▒▓▓▒▒▒▓▒▓▒▓▒▒▒▓▒▓▒▓▒█▓▓▓▓▓▓▒▓█▓▒▓▓▓░ ▓▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▓ ░▒░░░░░░░▒▒▒▒▒▓▒▓░▒▓▒▒▓▓▒▓▒██▓▓▒▒▓▒▓▓▒▓▓▒█▒▒▒▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓ ░▓▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▒▓▒ ▒▒░░▒▒▒▒▒▒░▓▓▓▒▒▓▓▓▓▓▓▓▓▓█▒▓▓▓▓▓▓▓▓▓▓▓▓▒▓▓▒▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▒▓▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▓░ ▒▒░░░░░░░░▒▒▓▒▒▒▒▓▒▒▓▒▒▓▒▓▒▒▒▓▒▓▓▓▓▓▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓█▓▒▓▓▓▓▓▓▒▓▓░ ▒▒▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▓▒░▒░░░░░░░░▒▒▒▒░▓▒▒▒▒▒▓▒▒▓▒▓▓▓▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▒▒▓▒▓▒█▓▒█▓▒▒▓▓▒▒▒▒▓▓ ▓▓▒▒▒▒▒▒▒▒▒▒ 
 ▒▒▒▒▒▓ ▒▒░░▒░░▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▓▓▒▒▓▓▒▓▓▒▓▓▒▓▓▓▓▒▒▒▒▓▒▓▓▓▒▒▓▓▓▓▓▓▓▓▓▓▒▒▒▓▒░▓▒▒▒▒▒▒▒▒▒▒ 
      ░                                                                       ░           


--- assets/scripts_README.md ---
# Meta-Development Script

This folder contains a **meta-development script** (`dev.js`) and related utilities that manage tasks for an AI-driven or traditional software development workflow. The script revolves around a `tasks.json` file, which holds an up-to-date list of development tasks.

## Overview

In an AI-driven development process—particularly with tools like [Cursor](https://www.cursor.so/)—it's beneficial to have a **single source of truth** for tasks. This script allows you to:

1. **Parse** a PRD or requirements document (`.txt`) to initialize a set of tasks (`tasks.json`).
2. **List** all existing tasks (IDs, statuses, titles).
3. **Update** tasks to accommodate new prompts or architecture changes (useful if you discover "implementation drift").
4. **Generate** individual task files (e.g., `task_001.txt`) for easy reference or to feed into an AI coding workflow.
5. **Set task status**—mark tasks as `done`, `pending`, or `deferred` based on progress.
6. **Expand** tasks with subtasks—break down complex tasks into smaller, more manageable subtasks.
7. **Research-backed subtask generation**—use Perplexity AI to generate more informed and contextually relevant subtasks.
8. **Clear subtasks**—remove subtasks from specified tasks to allow regeneration or restructuring.
9. **Show task details**—display detailed information about a specific task and its subtasks.

## Configuration (Updated)

Task Master configuration is now managed through two primary methods:

1.  **`.taskmaster/config.json` File (Project Root - Primary)**

    - Stores AI model selections (`main`, `research`, `fallback`), model parameters (`maxTokens`, `temperature`), `logLevel`, `defaultSubtasks`, `defaultPriority`, `projectName`, etc.
    - Managed using the `task-master models --setup` command or the `models` MCP tool.
    - This is the main configuration file for most settings.

2.  **Environment Variables (`.env` File - API Keys Only)**
    - Used **only** for sensitive **API Keys** (e.g., `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY`).
    - Create a `.env` file in your project root for CLI usage.
    - See `assets/env.example` for required key names.

**Important:** Settings like `MODEL`, `MAX_TOKENS`, `TEMPERATURE`, `TASKMASTER_LOG_LEVEL`, etc., are **no longer set via `.env`**. Use `task-master models --setup` instead.

## How It Works

1. **`tasks.json`**:

   - A JSON file at the project root containing an array of tasks (each with `id`, `title`, `description`, `status`, etc.).
   - The `meta` field can store additional info like the project's name, version, or reference to the PRD.
   - Tasks can have `subtasks` for more detailed implementation steps.
   - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending) to easily track progress.

2. **CLI Commands**
   You can run the commands via:

   ```bash
   # If installed globally
   task-master [command] [options]

   # If using locally within the project
   node scripts/dev.js [command] [options]
   ```

   Available commands:

   - `init`: Initialize a new project
   - `parse-prd`: Generate tasks from a PRD document
   - `list`: Display all tasks with their status
   - `update`: Update tasks based on new information
   - `generate`: Create individual task files
   - `set-status`: Change a task's status
   - `expand`: Add subtasks to a task or all tasks
   - `clear-subtasks`: Remove subtasks from specified tasks
   - `next`: Determine the next task to work on based on dependencies
   - `show`: Display detailed information about a specific task
   - `analyze-complexity`: Analyze task complexity and generate recommendations
   - `complexity-report`: Display the complexity analysis in a readable format
   - `add-dependency`: Add a dependency between tasks
   - `remove-dependency`: Remove a dependency from a task
   - `validate-dependencies`: Check for invalid dependencies
   - `fix-dependencies`: Fix invalid dependencies automatically
   - `add-task`: Add a new task using AI

   Run `task-master --help` or `node scripts/dev.js --help` to see detailed usage information.

## Listing Tasks

The `list` command allows you to view all tasks and their status:

```bash
# List all tasks
task-master list

# List tasks with a specific status
task-master list --status=pending

# List tasks and include their subtasks
task-master list --with-subtasks

# List tasks with a specific status and include their subtasks
task-master list --status=pending --with-subtasks
```

## Updating Tasks

The `update` command allows you to update tasks based on new information or implementation changes:

```bash
# Update tasks starting from ID 4 with a new prompt
task-master update --from=4 --prompt="Refactor tasks from ID 4 onward to use Express instead of Fastify"

# Update all tasks (default from=1)
task-master update --prompt="Add authentication to all relevant tasks"

# Specify a different tasks file
task-master update --file=custom-tasks.json --from=5 --prompt="Change database from MongoDB to PostgreSQL"
```

Notes:

- The `--prompt` parameter is required and should explain the changes or new context
- Only tasks that aren't marked as 'done' will be updated
- Tasks with ID >= the specified --from value will be updated

## Setting Task Status

The `set-status` command allows you to change a task's status:

```bash
# Mark a task as done
task-master set-status --id=3 --status=done

# Mark a task as pending
task-master set-status --id=4 --status=pending

# Mark a specific subtask as done
task-master set-status --id=3.1 --status=done

# Mark multiple tasks at once
task-master set-status --id=1,2,3 --status=done
```

Notes:

- When marking a parent task as "done", all of its subtasks will automatically be marked as "done" as well
- Common status values are 'done', 'pending', and 'deferred', but any string is accepted
- You can specify multiple task IDs by separating them with commas
- Subtask IDs are specified using the format `parentId.subtaskId` (e.g., `3.1`)
- Dependencies are updated to show completion status (✅ for completed, ⏱️ for pending) throughout the system

## Expanding Tasks

The `expand` command allows you to break down tasks into subtasks for more detailed implementation:

```bash
# Expand a specific task with 3 subtasks (default)
task-master expand --id=3

# Expand a specific task with 5 subtasks
task-master expand --id=3 --num=5

# Expand a task with additional context
task-master expand --id=3 --prompt="Focus on security aspects"

# Expand all pending tasks that don't have subtasks
task-master expand --all

# Force regeneration of subtasks for all pending tasks
task-master expand --all --force

# Use Perplexity AI for research-backed subtask generation
task-master expand --id=3 --research

# Use Perplexity AI for research-backed generation on all pending tasks
task-master expand --all --research
```

## Clearing Subtasks

The `clear-subtasks` command allows you to remove subtasks from specified tasks:

```bash
# Clear subtasks from a specific task
task-master clear-subtasks --id=3

# Clear subtasks from multiple tasks
task-master clear-subtasks --id=1,2,3

# Clear subtasks from all tasks
task-master clear-subtasks --all
```

Notes:

- After clearing subtasks, task files are automatically regenerated
- This is useful when you want to regenerate subtasks with a different approach
- Can be combined with the `expand` command to immediately generate new subtasks
- Works with both parent tasks and individual subtasks

## AI Integration (Updated)

- The script now uses a unified AI service layer (`ai-services-unified.js`).
- Model selection (e.g., Claude vs. Perplexity for `--research`) is determined by the configuration in `.taskmaster/config.json` based on the requested `role` (`main` or `research`).
- API keys are automatically resolved from your `.env` file (for CLI) or MCP session environment.
- To use the research capabilities (e.g., `expand --research`), ensure you have:
  1.  Configured a model for the `research` role using `task-master models --setup` (Perplexity models are recommended).
  2.  Added the corresponding API key (e.g., `PERPLEXITY_API_KEY`) to your `.env` file.

## Logging

The script supports different logging levels controlled by the `TASKMASTER_LOG_LEVEL` environment variable:

- `debug`: Detailed information, typically useful for troubleshooting
- `info`: Confirmation that things are working as expected (default)
- `warn`: Warning messages that don't prevent execution
- `error`: Error messages that might prevent execution

When `DEBUG=true` is set, debug logs are also written to a `dev-debug.log` file in the project root.

## Managing Task Dependencies

The `add-dependency` and `remove-dependency` commands allow you to manage task dependencies:

```bash
# Add a dependency to a task
task-master add-dependency --id=<id> --depends-on=<id>

# Remove a dependency from a task
task-master remove-dependency --id=<id> --depends-on=<id>
```

These commands:

1. **Allow precise dependency management**:

   - Add dependencies between tasks with automatic validation
   - Remove dependencies when they're no longer needed
   - Update task files automatically after changes

2. **Include validation checks**:

   - Prevent circular dependencies (a task depending on itself)
   - Prevent duplicate dependencies
   - Verify that both tasks exist before adding/removing dependencies
   - Check if dependencies exist before attempting to remove them

3. **Provide clear feedback**:

   - Success messages confirm when dependencies are added/removed
   - Error messages explain why operations failed (if applicable)

4. **Automatically update task files**:
   - Regenerates task files to reflect dependency changes
   - Ensures tasks and their files stay synchronized

## Dependency Validation and Fixing

The script provides two specialized commands to ensure task dependencies remain valid and properly maintained:

### Validating Dependencies

The `validate-dependencies` command allows you to check for invalid dependencies without making changes:

```bash
# Check for invalid dependencies in tasks.json
task-master validate-dependencies

# Specify a different tasks file
task-master validate-dependencies --file=custom-tasks.json
```

This command:

- Scans all tasks and subtasks for non-existent dependencies
- Identifies potential self-dependencies (tasks referencing themselves)
- Reports all found issues without modifying files
- Provides a comprehensive summary of dependency state
- Gives detailed statistics on task dependencies

Use this command to audit your task structure before applying fixes.

### Fixing Dependencies

The `fix-dependencies` command proactively finds and fixes all invalid dependencies:

```bash
# Find and fix all invalid dependencies
task-master fix-dependencies

# Specify a different tasks file
task-master fix-dependencies --file=custom-tasks.json
```

This command:

1. **Validates all dependencies** across tasks and subtasks
2. **Automatically removes**:
   - References to non-existent tasks and subtasks
   - Self-dependencies (tasks depending on themselves)
3. **Fixes issues in both**:
   - The tasks.json data structure
   - Individual task files during regeneration
4. **Provides a detailed report**:
   - Types of issues fixed (non-existent vs. self-dependencies)
   - Number of tasks affected (tasks vs. subtasks)
   - Where fixes were applied (tasks.json vs. task files)
   - List of all individual fixes made

This is especially useful when tasks have been deleted or IDs have changed, potentially breaking dependency chains.

## Analyzing Task Complexity

The `analyze-complexity` command allows you to automatically assess task complexity and generate expansion recommendations:

```bash
# Analyze all tasks and generate expansion recommendations
task-master analyze-complexity

# Specify a custom output file
task-master analyze-complexity --output=custom-report.json

# Override the model used for analysis
task-master analyze-complexity --model=claude-3-opus-20240229

# Set a custom complexity threshold (1-10)
task-master analyze-complexity --threshold=6

# Use Perplexity AI for research-backed complexity analysis
task-master analyze-complexity --research
```

Notes:

- The command uses Claude to analyze each task's complexity (or Perplexity with --research flag)
- Tasks are scored on a scale of 1-10
- Each task receives a recommended number of subtasks based on DEFAULT_SUBTASKS configuration
- The default output path is `scripts/task-complexity-report.json`
- Each task in the analysis includes a ready-to-use `expansionCommand` that can be copied directly to the terminal or executed programmatically
- Tasks with complexity scores below the threshold (default: 5) may not need expansion
- The research flag provides more contextual and informed complexity assessments

### Integration with Expand Command

The `expand` command automatically checks for and uses complexity analysis if available:

```bash
# Expand a task, using complexity report recommendations if available
task-master expand --id=8

# Expand all tasks, prioritizing by complexity score if a report exists
task-master expand --all

# Override recommendations with explicit values
task-master expand --id=8 --num=5 --prompt="Custom prompt"
```

When a complexity report exists:

- The `expand` command will use the recommended subtask count from the report (unless overridden)
- It will use the tailored expansion prompt from the report (unless a custom prompt is provided)
- When using `--all`, tasks are sorted by complexity score (highest first)
- The `--research` flag is preserved from the complexity analysis to expansion

The output report structure is:

```json
{
  "meta": {
    "generatedAt": "2023-06-15T12:34:56.789Z",
    "tasksAnalyzed": 20,
    "thresholdScore": 5,
    "projectName": "Your Project Name",
    "usedResearch": true
  },
  "complexityAnalysis": [
    {
      "taskId": 8,
      "taskTitle": "Develop Implementation Drift Handling",
      "complexityScore": 9.5,
      "recommendedSubtasks": 6,
      "expansionPrompt": "Create subtasks that handle detecting...",
      "reasoning": "This task requires sophisticated logic...",
      "expansionCommand": "task-master expand --id=8 --num=6 --prompt=\"Create subtasks...\" --research"
    }
    // More tasks sorted by complexity score (highest first)
  ]
}
```

## Finding the Next Task

The `next` command helps you determine which task to work on next based on dependencies and status:

```bash
# Show the next task to work on
task-master next

# Specify a different tasks file
task-master next --file=custom-tasks.json
```

This command:

1. Identifies all **eligible tasks** - pending or in-progress tasks whose dependencies are all satisfied (marked as done)
2. **Prioritizes** these eligible tasks by:
   - Priority level (high > medium > low)
   - Number of dependencies (fewer dependencies first)
   - Task ID (lower ID first)
3. **Displays** comprehensive information about the selected task:
   - Basic task details (ID, title, priority, dependencies)
   - Detailed description and implementation details
   - Subtasks if they exist
4. Provides **contextual suggested actions**:
   - Command to mark the task as in-progress
   - Command to mark the task as done when completed
   - Commands for working with subtasks (update status or expand)

This feature ensures you're always working on the most appropriate task based on your project's current state and dependency structure.

## Showing Task Details

The `show` command allows you to view detailed information about a specific task:

```bash
# Show details for a specific task
task-master show 1

# Alternative syntax with --id option
task-master show --id=1

# Show details for a subtask
task-master show --id=1.2

# Specify a different tasks file
task-master show 3 --file=custom-tasks.json
```

This command:

1. **Displays comprehensive information** about the specified task:
   - Basic task details (ID, title, priority, dependencies, status)
   - Full description and implementation details
   - Test strategy information
   - Subtasks if they exist
2. **Handles both regular tasks and subtasks**:
   - For regular tasks, shows all subtasks and their status
   - For subtasks, shows the parent task relationship
3. **Provides contextual suggested actions**:
   - Commands to update the task status
   - Commands for working with subtasks
   - For subtasks, provides a link to view the parent task

This command is particularly useful when you need to examine a specific task in detail before implementing it or when you want to check the status and details of a particular task.


## Links discovered
- [Cursor](https://www.cursor.so/)

--- context/fastmcp-core.txt ---
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ClientCapabilities,
  CompleteRequestSchema,
  CreateMessageRequestSchema,
  ErrorCode,
  GetPromptRequestSchema,
  ListPromptsRequestSchema,
  ListResourcesRequestSchema,
  ListResourceTemplatesRequestSchema,
  ListToolsRequestSchema,
  McpError,
  ReadResourceRequestSchema,
  Root,
  RootsListChangedNotificationSchema,
  ServerCapabilities,
  SetLevelRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { zodToJsonSchema } from "zod-to-json-schema";
import { z } from "zod";
import { setTimeout as delay } from "timers/promises";
import { readFile } from "fs/promises";
import { fileTypeFromBuffer } from "file-type";
import { StrictEventEmitter } from "strict-event-emitter-types";
import { EventEmitter } from "events";
import Fuse from "fuse.js";
import { startSSEServer } from "mcp-proxy";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import parseURITemplate from "uri-templates";
import http from "http";
import {
  fetch
} from "undici";

export type SSEServer = {
  close: () => Promise<void>;
};

type FastMCPEvents<T extends FastMCPSessionAuth> = {
  connect: (event: { session: FastMCPSession<T> }) => void;
  disconnect: (event: { session: FastMCPSession<T> }) => void;
};

type FastMCPSessionEvents = {
  rootsChanged: (event: { roots: Root[] }) => void;
  error: (event: { error: Error }) => void;
};

/**
 * Generates an image content object from a URL, file path, or buffer.
 */
export const imageContent = async (
  input: { url: string } | { path: string } | { buffer: Buffer },
): Promise<ImageContent> => {
  let rawData: Buffer;

  if ("url" in input) {
    const response = await fetch(input.url);

    if (!response.ok) {
      throw new Error(`Failed to fetch image from URL: ${response.statusText}`);
    }

    rawData = Buffer.from(await response.arrayBuffer());
  } else if ("path" in input) {
    rawData = await readFile(input.path);
  } else if ("buffer" in input) {
    rawData = input.buffer;
  } else {
    throw new Error(
      "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
    );
  }

  const mimeType = await fileTypeFromBuffer(rawData);

  const base64Data = rawData.toString("base64");

  return {
    type: "image",
    data: base64Data,
    mimeType: mimeType?.mime ?? "image/png",
  } as const;
};

abstract class FastMCPError extends Error {
  public constructor(message?: string) {
    super(message);
    this.name = new.target.name;
  }
}

type Extra = unknown;

type Extras = Record<string, Extra>;

export class UnexpectedStateError extends FastMCPError {
  public extras?: Extras;

  public constructor(message: string, extras?: Extras) {
    super(message);
    this.name = new.target.name;
    this.extras = extras;
  }
}

/**
 * An error that is meant to be surfaced to the user.
 */
export class UserError extends UnexpectedStateError {}

type ToolParameters = z.ZodTypeAny;

type Literal = boolean | null | number | string | undefined;

type SerializableValue =
  | Literal
  | SerializableValue[]
  | { [key: string]: SerializableValue };

type Progress = {
  /**
   * The progress thus far. This should increase every time progress is made, even if the total is unknown.
   */
  progress: number;
  /**
   * Total number of items to process (or total progress required), if known.
   */
  total?: number;
};

type Context<T extends FastMCPSessionAuth> = {
  session: T | undefined;
  reportProgress: (progress: Progress) => Promise<void>;
  log: {
    debug: (message: string, data?: SerializableValue) => void;
    error: (message: string, data?: SerializableValue) => void;
    info: (message: string, data?: SerializableValue) => void;
    warn: (message: string, data?: SerializableValue) => void;
  };
};

type TextContent = {
  type: "text";
  text: string;
};

const TextContentZodSchema = z
  .object({
    type: z.literal("text"),
    /**
     * The text content of the message.
     */
    text: z.string(),
  })
  .strict() satisfies z.ZodType<TextContent>;

type ImageContent = {
  type: "image";
  data: string;
  mimeType: string;
};

const ImageContentZodSchema = z
  .object({
    type: z.literal("image"),
    /**
     * The base64-encoded image data.
     */
    data: z.string().base64(),
    /**
     * The MIME type of the image. Different providers may support different image types.
     */
    mimeType: z.string(),
  })
  .strict() satisfies z.ZodType<ImageContent>;

type Content = TextContent | ImageContent;

const ContentZodSchema = z.discriminatedUnion("type", [
  TextContentZodSchema,
  ImageContentZodSchema,
]) satisfies z.ZodType<Content>;

type ContentResult = {
  content: Content[];
  isError?: boolean;
};

const ContentResultZodSchema = z
  .object({
    content: ContentZodSchema.array(),
    isError: z.boolean().optional(),
  })
  .strict() satisfies z.ZodType<ContentResult>;

type Completion = {
  values: string[];
  total?: number;
  hasMore?: boolean;
};

/**
 * https://github.com/modelcontextprotocol/typescript-sdk/blob/3164da64d085ec4e022ae881329eee7b72f208d4/src/types.ts#L983-L1003
 */
const CompletionZodSchema = z.object({
  /**
   * An array of completion values. Must not exceed 100 items.
   */
  values: z.array(z.string()).max(100),
  /**
   * The total number of completion options available. This can exceed the number of values actually sent in the response.
   */
  total: z.optional(z.number().int()),
  /**
   * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
   */
  hasMore: z.optional(z.boolean()),
}) satisfies z.ZodType<Completion>;

type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolParameters> = {
  name: string;
  description?: string;
  parameters?: Params;
  execute: (
    args: z.infer<Params>,
    context: Context<T>,
  ) => Promise<string | ContentResult | TextContent | ImageContent>;
};

type ResourceResult =
  | {
      text: string;
    }
  | {
      blob: string;
    };

type InputResourceTemplateArgument = Readonly<{
  name: string;
  description?: string;
  complete?: ArgumentValueCompleter;
}>;

type ResourceTemplateArgument = Readonly<{
  name: string;
  description?: string;
  complete?: ArgumentValueCompleter;
}>;

type ResourceTemplate<
  Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],
> = {
  uriTemplate: string;
  name: string;
  description?: string;
  mimeType?: string;
  arguments: Arguments;
  complete?: (name: string, value: string) => Promise<Completion>;
  load: (
    args: ResourceTemplateArgumentsToObject<Arguments>,
  ) => Promise<ResourceResult>;
};

type ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {
  [K in T[number]["name"]]: string;
};

type InputResourceTemplate<
  Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],
> = {
  uriTemplate: string;
  name: string;
  description?: string;
  mimeType?: string;
  arguments: Arguments;
  load: (
    args: ResourceTemplateArgumentsToObject<Arguments>,
  ) => Promise<ResourceResult>;
};

type Resource = {
  uri: string;
  name: string;
  description?: string;
  mimeType?: string;
  load: () => Promise<ResourceResult | ResourceResult[]>;
  complete?: (name: string, value: string) => Promise<Completion>;
};

type ArgumentValueCompleter = (value: string) => Promise<Completion>;

type InputPromptArgument = Readonly<{
  name: string;
  description?: string;
  required?: boolean;
  complete?: ArgumentValueCompleter;
  enum?: string[];
}>;

type PromptArgumentsToObject<T extends { name: string; required?: boolean }[]> =
  {
    [K in T[number]["name"]]: Extract<
      T[number],
      { name: K }
    >["required"] extends true
      ? string
      : string | undefined;
  };

type InputPrompt<
  Arguments extends InputPromptArgument[] = InputPromptArgument[],
  Args = PromptArgumentsToObject<Arguments>,
> = {
  name: string;
  description?: string;
  arguments?: InputPromptArgument[];
  load: (args: Args) => Promise<string>;
};

type PromptArgument = Readonly<{
  name: string;
  description?: string;
  required?: boolean;
  complete?: ArgumentValueCompleter;
  enum?: string[];
}>;

type Prompt<
  Arguments extends PromptArgument[] = PromptArgument[],
  Args = PromptArgumentsToObject<Arguments>,
> = {
  arguments?: PromptArgument[];
  complete?: (name: string, value: string) => Promise<Completion>;
  description?: string;
  load: (args: Args) => Promise<string>;
  name: string;
};

type ServerOptions<T extends FastMCPSessionAuth> = {
  name: string;
  version: `${number}.${number}.${number}`;
  authenticate?: Authenticate<T>;
};

type LoggingLevel =
  | "debug"
  | "info"
  | "notice"
  | "warning"
  | "error"
  | "critical"
  | "alert"
  | "emergency";

const FastMCPSessionEventEmitterBase: {
  new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;
} = EventEmitter;

class FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}

type SamplingResponse = {
  model: string;
  stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
  role: "user" | "assistant";
  content: TextContent | ImageContent;
};

type FastMCPSessionAuth = Record<string, unknown> | undefined;

export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends FastMCPSessionEventEmitter {
  #capabilities: ServerCapabilities = {};
  #clientCapabilities?: ClientCapabilities;
  #loggingLevel: LoggingLevel = "info";
  #prompts: Prompt[] = [];
  #resources: Resource[] = [];
  #resourceTemplates: ResourceTemplate[] = [];
  #roots: Root[] = [];
  #server: Server;
  #auth: T | undefined;

  constructor({
    auth,
    name,
    version,
    tools,
    resources,
    resourcesTemplates,
    prompts,
  }: {
    auth?: T;
    name: string;
    version: string;
    tools: Tool<T>[];
    resources: Resource[];
    resourcesTemplates: InputResourceTemplate[];
    prompts: Prompt[];
  }) {
    super();

    this.#auth = auth;

    if (tools.length) {
      this.#capabilities.tools = {};
    }

    if (resources.length || resourcesTemplates.length) {
      this.#capabilities.resources = {};
    }

    if (prompts.length) {
      for (const prompt of prompts) {
        this.addPrompt(prompt);
      }

      this.#capabilities.prompts = {};
    }

    this.#capabilities.logging = {};

    this.#server = new Server(
      { name: name, version: version },
      { capabilities: this.#capabilities },
    );

    this.setupErrorHandling();
    this.setupLoggingHandlers();
    this.setupRootsHandlers();
    this.setupCompleteHandlers();

    if (tools.length) {
      this.setupToolHandlers(tools);
    }

    if (resources.length || resourcesTemplates.length) {
      for (const resource of resources) {
        this.addResource(resource);
      }

      this.setupResourceHandlers(resources);

      if (resourcesTemplates.length) {
        for (const resourceTemplate of resourcesTemplates) {
          this.addResourceTemplate(resourceTemplate);
        }

        this.setupResourceTemplateHandlers(resourcesTemplates);
      }
    }

    if (prompts.length) {
      this.setupPromptHandlers(prompts);
    }
  }

  private addResource(inputResource: Resource) {
    this.#resources.push(inputResource);
  }

  private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {
    const completers: Record<string, ArgumentValueCompleter> = {};

    for (const argument of inputResourceTemplate.arguments ?? []) {
      if (argument.complete) {
        completers[argument.name] = argument.complete;
      }
    }

    const resourceTemplate = {
      ...inputResourceTemplate,
      complete: async (name: string, value: string) => {
        if (completers[name]) {
          return await completers[name](value);
        }

        return {
          values: [],
        };
      },
    };

    this.#resourceTemplates.push(resourceTemplate);
  }

  private addPrompt(inputPrompt: InputPrompt) {
    const completers: Record<string, ArgumentValueCompleter> = {};
    const enums: Record<string, string[]> = {};

    for (const argument of inputPrompt.arguments ?? []) {
      if (argument.complete) {
        completers[argument.name] = argument.complete;
      }

      if (argument.enum) {
        enums[argument.name] = argument.enum;
      }
    }

    const prompt = {
      ...inputPrompt,
      complete: async (name: string, value: string) => {
        if (completers[name]) {
          return await completers[name](value);
        }

        if (enums[name]) {
          const fuse = new Fuse(enums[name], {
            keys: ["value"],
          });

          const result = fuse.search(value);

          return {
            values: result.map((item) => item.item),
            total: result.length,
          };
        }

        return {
          values: [],
        };
      },
    };

    this.#prompts.push(prompt);
  }

  public get clientCapabilities(): ClientCapabilities | null {
    return this.#clientCapabilities ?? null;
  }

  public get server(): Server {
    return this.#server;
  }

  #pingInterval: ReturnType<typeof setInterval> | null = null;

  public async requestSampling(
    message: z.infer<typeof CreateMessageRequestSchema>["params"],
  ): Promise<SamplingResponse> {
    return this.#server.createMessage(message);
  }

  public async connect(transport: Transport) {
    if (this.#server.transport) {
      throw new UnexpectedStateError("Server is already connected");
    }

    await this.#server.connect(transport);

    let attempt = 0;

    while (attempt++ < 10) {
      const capabilities = await this.#server.getClientCapabilities();

      if (capabilities) {
        this.#clientCapabilities = capabilities;

        break;
      }

      await delay(100);
    }

    if (!this.#clientCapabilities) {
      console.warn('[warning] FastMCP could not infer client capabilities')
    }

    if (this.#clientCapabilities?.roots?.listChanged) {
      try {
        const roots = await this.#server.listRoots();
        this.#roots = roots.roots;
      } catch(e) {
        console.error(`[error] FastMCP received error listing roots.\n\n${e instanceof Error ? e.stack : JSON.stringify(e)}`)
      }
    }

    this.#pingInterval = setInterval(async () => {
      try {
        await this.#server.ping();
      } catch (error) {
        this.emit("error", {
          error: error as Error,
        });
      }
    }, 1000);
  }

  public get roots(): Root[] {
    return this.#roots;
  }

  public async close() {
    if (this.#pingInterval) {
      clearInterval(this.#pingInterval);
    }

    try {
      await this.#server.close();
    } catch (error) {
      console.error("[MCP Error]", "could not close server", error);
    }
  }

  private setupErrorHandling() {
    this.#server.onerror = (error) => {
      console.error("[MCP Error]", error);
    };
  }

  public get loggingLevel(): LoggingLevel {
    return this.#loggingLevel;
  }

  private setupCompleteHandlers() {
    this.#server.setRequestHandler(CompleteRequestSchema, async (request) => {
      if (request.params.ref.type === "ref/prompt") {
        const prompt = this.#prompts.find(
          (prompt) => prompt.name === request.params.ref.name,
        );

        if (!prompt) {
          throw new UnexpectedStateError("Unknown prompt", {
            request,
          });
        }

        if (!prompt.complete) {
          throw new UnexpectedStateError("Prompt does not support completion", {
            request,
          });
        }

        const completion = CompletionZodSchema.parse(
          await prompt.complete(
            request.params.argument.name,
            request.params.argument.value,
          ),
        );

        return {
          completion,
        };
      }

      if (request.params.ref.type === "ref/resource") {
        const resource = this.#resourceTemplates.find(
          (resource) => resource.uriTemplate === request.params.ref.uri,
        );

        if (!resource) {
          throw new UnexpectedStateError("Unknown resource", {
            request,
          });
        }

        if (!("uriTemplate" in resource)) {
          throw new UnexpectedStateError("Unexpected resource");
        }

        if (!resource.complete) {
          throw new UnexpectedStateError(
            "Resource does not support completion",
            {
              request,
            },
          );
        }

        const completion = CompletionZodSchema.parse(
          await resource.complete(
            request.params.argument.name,
            request.params.argument.value,
          ),
        );

        return {
          completion,
        };
      }

      throw new UnexpectedStateError("Unexpected completion request", {
        request,
      });
    });
  }

  private setupRootsHandlers() {
    this.#server.setNotificationHandler(
      RootsListChangedNotificationSchema,
      () => {
        this.#server.listRoots().then((roots) => {
          this.#roots = roots.roots;

          this.emit("rootsChanged", {
            roots: roots.roots,
          });
        });
      },
    );
  }

  private setupLoggingHandlers() {
    this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {
      this.#loggingLevel = request.params.level;

      return {};
    });
  }

  private setupToolHandlers(tools: Tool<T>[]) {
    this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: tools.map((tool) => {
          return {
            name: tool.name,
            description: tool.description,
            inputSchema: tool.parameters
              ? zodToJsonSchema(tool.parameters)
              : undefined,
          };
        }),
      };
    });

    this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const tool = tools.find((tool) => tool.name === request.params.name);

      if (!tool) {
        throw new McpError(
          ErrorCode.MethodNotFound,
          `Unknown tool: ${request.params.name}`,
        );
      }

      let args: any = undefined;

      if (tool.parameters) {
        const parsed = tool.parameters.safeParse(request.params.arguments);

        if (!parsed.success) {
          throw new McpError(
            ErrorCode.InvalidParams,
            `Invalid ${request.params.name} parameters`,
          );
        }

        args = parsed.data;
      }

      const progressToken = request.params?._meta?.progressToken;

      let result: ContentResult;

      try {
        const reportProgress = async (progress: Progress) => {
          await this.#server.notification({
            method: "notifications/progress",
            params: {
              ...progress,
              progressToken,
            },
          });
        };

        const log = {
          debug: (message: string, context?: SerializableValue) => {
            this.#server.sendLoggingMessage({
              level: "debug",
              data: {
                message,
                context,
              },
            });
          },
          error: (message: string, context?: SerializableValue) => {
            this.#server.sendLoggingMessage({
              level: "error",
              data: {
                message,
                context,
              },
            });
          },
          info: (message: string, context?: SerializableValue) => {
            this.#server.sendLoggingMessage({
              level: "info",
              data: {
                message,
                context,
              },
            });
          },
          warn: (message: string, context?: SerializableValue) => {
            this.#server.sendLoggingMessage({
              level: "warning",
              data: {
                message,
                context,
              },
            });
          },
        };

        const maybeStringResult = await tool.execute(args, {
          reportProgress,
          log,
          session: this.#auth,
        });

        if (typeof maybeStringResult === "string") {
          result = ContentResultZodSchema.parse({
            content: [{ type: "text", text: maybeStringResult }],
          });
        } else if ("type" in maybeStringResult) {
          result = ContentResultZodSchema.parse({
            content: [maybeStringResult],
          });
        } else {
          result = ContentResultZodSchema.parse(maybeStringResult);
        }
      } catch (error) {
        if (error instanceof UserError) {
          return {
            content: [{ type: "text", text: error.message }],
            isError: true,
          };
        }

        return {
          content: [{ type: "text", text: `Error: ${error}` }],
          isError: true,
        };
      }

      return result;
    });
  }

  private setupResourceHandlers(resources: Resource[]) {
    this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: resources.map((resource) => {
          return {
            uri: resource.uri,
            name: resource.name,
            mimeType: resource.mimeType,
          };
        }),
      };
    });

    this.#server.setRequestHandler(
      ReadResourceRequestSchema,
      async (request) => {
        if ("uri" in request.params) {
          const resource = resources.find(
            (resource) =>
              "uri" in resource && resource.uri === request.params.uri,
          );

          if (!resource) {
            for (const resourceTemplate of this.#resourceTemplates) {
              const uriTemplate = parseURITemplate(
                resourceTemplate.uriTemplate,
              );

              const match = uriTemplate.fromUri(request.params.uri);

              if (!match) {
                continue;
              }

              const uri = uriTemplate.fill(match);

              const result = await resourceTemplate.load(match);

              return {
                contents: [
                  {
                    uri: uri,
                    mimeType: resourceTemplate.mimeType,
                    name: resourceTemplate.name,
                    ...result,
                  },
                ],
              };
            }

            throw new McpError(
              ErrorCode.MethodNotFound,
              `Unknown resource: ${request.params.uri}`,
            );
          }

          if (!("uri" in resource)) {
            throw new UnexpectedStateError("Resource does not support reading");
          }

          let maybeArrayResult: Awaited<ReturnType<Resource["load"]>>;

          try {
            maybeArrayResult = await resource.load();
          } catch (error) {
            throw new McpError(
              ErrorCode.InternalError,
              `Error reading resource: ${error}`,
              {
                uri: resource.uri,
              },
            );
          }

          if (Array.isArray(maybeArrayResult)) {
            return {
              contents: maybeArrayResult.map((result) => ({
                uri: resource.uri,
                mimeType: resource.mimeType,
                name: resource.name,
                ...result,
              })),
            };
          } else {
            return {
              contents: [
                {
                  uri: resource.uri,
                  mimeType: resource.mimeType,
                  name: resource.name,
                  ...maybeArrayResult,
                },
              ],
            };
          }
        }

        throw new UnexpectedStateError("Unknown resource request", {
          request,
        });
      },
    );
  }

  private setupResourceTemplateHandlers(resourceTemplates: ResourceTemplate[]) {
    this.#server.setRequestHandler(
      ListResourceTemplatesRequestSchema,
      async () => {
        return {
          resourceTemplates: resourceTemplates.map((resourceTemplate) => {
            return {
              name: resourceTemplate.name,
              uriTemplate: resourceTemplate.uriTemplate,
            };
          }),
        };
      },
    );
  }

  private setupPromptHandlers(prompts: Prompt[]) {
    this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
      return {
        prompts: prompts.map((prompt) => {
          return {
            name: prompt.name,
            description: prompt.description,
            arguments: prompt.arguments,
            complete: prompt.complete,
          };
        }),
      };
    });

    this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
      const prompt = prompts.find(
        (prompt) => prompt.name === request.params.name,
      );

      if (!prompt) {
        throw new McpError(
          ErrorCode.MethodNotFound,
          `Unknown prompt: ${request.params.name}`,
        );
      }

      const args = request.params.arguments;

      for (const arg of prompt.arguments ?? []) {
        if (arg.required && !(args && arg.name in args)) {
          throw new McpError(
            ErrorCode.InvalidRequest,
            `Missing required argument: ${arg.name}`,
          );
        }
      }

      let result: Awaited<ReturnType<Prompt["load"]>>;

      try {
        result = await prompt.load(args as Record<string, string | undefined>);
      } catch (error) {
        throw new McpError(
          ErrorCode.InternalError,
          `Error loading prompt: ${error}`,
        );
      }

      return {
        description: prompt.description,
        messages: [
          {
            role: "user",
            content: { type: "text", text: result },
          },
        ],
      };
    });
  }
}

const FastMCPEventEmitterBase: {
  new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;
} = EventEmitter;

class FastMCPEventEmitter extends FastMCPEventEmitterBase {}

type Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;

export class FastMCP<T extends Record<string, unknown> | undefined = undefined> extends FastMCPEventEmitter {
  #options: ServerOptions<T>;
  #prompts: InputPrompt[] = [];
  #resources: Resource[] = [];
  #resourcesTemplates: InputResourceTemplate[] = [];
  #sessions: FastMCPSession<T>[] = [];
  #sseServer: SSEServer | null = null;
  #tools: Tool<T>[] = [];
  #authenticate: Authenticate<T> | undefined;

  constructor(public options: ServerOptions<T>) {
    super();

    this.#options = options;
    this.#authenticate = options.authenticate;
  }

  public get sessions(): FastMCPSession<T>[] {
    return this.#sessions;
  }

  /**
   * Adds a tool to the server.
   */
  public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {
    this.#tools.push(tool as unknown as Tool<T>);
  }

  /**
   * Adds a resource to the server.
   */
  public addResource(resource: Resource) {
    this.#resources.push(resource);
  }

  /**
   * Adds a resource template to the server.
   */
  public addResourceTemplate<
    const Args extends InputResourceTemplateArgument[],
  >(resource: InputResourceTemplate<Args>) {
    this.#resourcesTemplates.push(resource);
  }

  /**
   * Adds a prompt to the server.
   */
  public addPrompt<const Args extends InputPromptArgument[]>(
    prompt: InputPrompt<Args>,
  ) {
    this.#prompts.push(prompt);
  }

  /**
   * Starts the server.
   */
  public async start(
    options:
      | { transportType: "stdio" }
      | {
          transportType: "sse";
          sse: { endpoint: `/${string}`; port: number };
        } = {
      transportType: "stdio",
    },
  ) {
    if (options.transportType === "stdio") {
      const transport = new StdioServerTransport();

      const session = new FastMCPSession<T>({
        name: this.#options.name,
        version: this.#options.version,
        tools: this.#tools,
        resources: this.#resources,
        resourcesTemplates: this.#resourcesTemplates,
        prompts: this.#prompts,
      });

      await session.connect(transport);

      this.#sessions.push(session);

      this.emit("connect", {
        session,
      });

    } else if (options.transportType === "sse") {
      this.#sseServer = await startSSEServer<FastMCPSession<T>>({
        endpoint: options.sse.endpoint as `/${string}`,
        port: options.sse.port,
        createServer: async (request) => {
          let auth: T | undefined;

          if (this.#authenticate) {
            auth = await this.#authenticate(request);
          }

          return new FastMCPSession<T>({
            auth,
            name: this.#options.name,
            version: this.#options.version,
            tools: this.#tools,
            resources: this.#resources,
            resourcesTemplates: this.#resourcesTemplates,
            prompts: this.#prompts,
          });
        },
        onClose: (session) => {
          this.emit("disconnect", {
            session,
          });
        },
        onConnect: async (session) => {
          this.#sessions.push(session);

          this.emit("connect", {
            session,
          });
        },
      });

      console.info(
        `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,
      );
    } else {
      throw new Error("Invalid transport type");
    }
  }

  /**
   * Stops the server.
   */
  public async stop() {
    if (this.#sseServer) {
      this.#sseServer.close();
    }
  }
}

export type { Context };
export type { Tool, ToolParameters };
export type { Content, TextContent, ImageContent, ContentResult };
export type { Progress, SerializableValue };
export type { Resource, ResourceResult };
export type { ResourceTemplate, ResourceTemplateArgument };
export type { Prompt, PromptArgument };
export type { InputPrompt, InputPromptArgument };
export type { ServerOptions, LoggingLevel };
export type { FastMCPEvents, FastMCPSessionEvents };

## Links discovered
- [name](https://github.com/eyaltoledano/claude-task-master/blob/main/context/value.md)

--- context/MCP_INTEGRATION.md ---
# 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:

```javascript
/**
 * 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`:

```javascript
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

```javascript
// 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

```javascript
// 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

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

### Tool Implementation

```javascript
// 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

```javascript
// 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:

```javascript
// 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


--- context/mcp-protocol-repo.txt ---
# Example Clients
Source: https://modelcontextprotocol.io/clients

A list of applications that support MCP integrations

This page provides an overview of applications that support the Model Context Protocol (MCP). Each client may support different MCP features, allowing for varying levels of integration with MCP servers.

## Feature support matrix

| Client                               | [Resources] | [Prompts] | [Tools] | [Sampling] | Roots | Notes                                                              |
| ------------------------------------ | ----------- | --------- | ------- | ---------- | ----- | ------------------------------------------------------------------ |
| [Claude Desktop App][Claude]         | ✅           | ✅         | ✅       | ❌          | ❌     | Full support for all MCP features                                  |
| [5ire][5ire]                         | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools.                                                    |
| [BeeAI Framework][BeeAI Framework]   | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools in agentic workflows.                               |
| [Cline][Cline]                       | ✅           | ❌         | ✅       | ❌          | ❌     | Supports tools and resources.                                      |
| [Continue][Continue]                 | ✅           | ✅         | ✅       | ❌          | ❌     | Full support for all MCP features                                  |
| [Cursor][Cursor]                     | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools.                                                    |
| [Emacs Mcp][Mcp.el]                  | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools in Emacs.                                           |
| [Firebase Genkit][Genkit]            | ⚠️          | ✅         | ✅       | ❌          | ❌     | Supports resource list and lookup through tools.                   |
| [GenAIScript][GenAIScript]           | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools.                                                    |
| [Goose][Goose]                       | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools.                                                    |
| [LibreChat][LibreChat]               | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools for Agents                                          |
| [mcp-agent][mcp-agent]               | ❌           | ❌         | ✅       | ⚠️         | ❌     | Supports tools, server connection management, and agent workflows. |
| [Roo Code][Roo Code]                 | ✅           | ❌         | ✅       | ❌          | ❌     | Supports tools and resources.                                      |
| [Sourcegraph Cody][Cody]             | ✅           | ❌         | ❌       | ❌          | ❌     | Supports resources through OpenCTX                                 |
| [Superinterface][Superinterface]     | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools                                                     |
| [TheiaAI/TheiaIDE][TheiaAI/TheiaIDE] | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools for Agents in Theia AI and the AI-powered Theia IDE |
| [Windsurf Editor][Windsurf]          | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools with AI Flow for collaborative development.         |
| [Zed][Zed]                           | ❌           | ✅         | ❌       | ❌          | ❌     | Prompts appear as slash commands                                   |
| [SpinAI][SpinAI]                     | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools for Typescript AI Agents                            |
| [OpenSumi][OpenSumi]                 | ❌           | ❌         | ✅       | ❌          | ❌     | Supports tools in OpenSumi                                         |
| [Daydreams Agents][Daydreams]        | ✅           | ✅         | ✅       | ❌          | ❌     | Support for drop in Servers to Daydreams agents                    |

[Claude]: https://claude.ai/download

[Cursor]: https://cursor.com

[Zed]: https://zed.dev

[Cody]: https://sourcegraph.com/cody

[Genkit]: https://github.com/firebase/genkit

[Continue]: https://github.com/continuedev/continue

[GenAIScript]: https://microsoft.github.io/genaiscript/reference/scripts/mcp-tools/

[Cline]: https://github.com/cline/cline

[LibreChat]: https://github.com/danny-avila/LibreChat

[TheiaAI/TheiaIDE]: https://eclipsesource.com/blogs/2024/12/19/theia-ide-and-theia-ai-support-mcp/

[Superinterface]: https://superinterface.ai

[5ire]: https://github.com/nanbingxyz/5ire

[BeeAI Framework]: https://i-am-bee.github.io/beeai-framework

[mcp-agent]: https://github.com/lastmile-ai/mcp-agent

[Mcp.el]: https://github.com/lizqwerscott/mcp.el

[Roo Code]: https://roocode.com

[Goose]: https://block.github.io/goose/docs/goose-architecture/#interoperability-with-extensions

[Windsurf]: https://codeium.com/windsurf

[Daydreams]: https://github.com/daydreamsai/daydreams

[SpinAI]: https://spinai.dev

[OpenSumi]: https://github.com/opensumi/core

[Resources]: https://modelcontextprotocol.io/docs/concepts/resources

[Prompts]: https://modelcontextprotocol.io/docs/concepts/prompts

[Tools]: https://modelcontextprotocol.io/docs/concepts/tools

[Sampling]: https://modelcontextprotocol.io/docs/concepts/sampling

## Client details

### Claude Desktop App

The Claude desktop application provides comprehensive support for MCP, enabling deep integration with local tools and data sources.

**Key features:**

* Full support for resources, allowing attachment of local files and data
* Support for prompt templates
* Tool integration for executing commands and scripts
* Local server connections for enhanced privacy and security

> ⓘ Note: The Claude.ai web application does not currently support MCP. MCP features are only available in the desktop application.

### 5ire

[5ire](https://github.com/nanbingxyz/5ire) is an open source cross-platform desktop AI assistant that supports tools through MCP servers.

**Key features:**

* Built-in MCP servers can be quickly enabled and disabled.
* Users can add more servers by modifying the configuration file.
* It is open-source and user-friendly, suitable for beginners.
* Future support for MCP will be continuously improved.

### BeeAI Framework

[BeeAI Framework](https://i-am-bee.github.io/beeai-framework) is an open-source framework for building, deploying, and serving powerful agentic workflows at scale. The framework includes the **MCP Tool**, a native feature that simplifies the integration of MCP servers into agentic workflows.

**Key features:**

* Seamlessly incorporate MCP tools into agentic workflows.
* Quickly instantiate framework-native tools from connected MCP client(s).
* Planned future support for agentic MCP capabilities.

**Learn more:**

* [Example of using MCP tools in agentic workflow](https://i-am-bee.github.io/beeai-framework/#/typescript/tools?id=using-the-mcptool-class)

### Cline

[Cline](https://github.com/cline/cline) is an autonomous coding agent in VS Code that edits files, runs commands, uses a browser, and more–with your permission at each step.

**Key features:**

* Create and add tools through natural language (e.g. "add a tool that searches the web")
* Share custom MCP servers Cline creates with others via the `~/Documents/Cline/MCP` directory
* Displays configured MCP servers along with their tools, resources, and any error logs

### Continue

[Continue](https://github.com/continuedev/continue) is an open-source AI code assistant, with built-in support for all MCP features.

**Key features**

* Type "@" to mention MCP resources
* Prompt templates surface as slash commands
* Use both built-in and MCP tools directly in chat
* Supports VS Code and JetBrains IDEs, with any LLM

### Cursor

[Cursor](https://docs.cursor.com/advanced/model-context-protocol) is an AI code editor.

**Key Features**:

* Support for MCP tools in Cursor Composer
* Support for both STDIO and SSE

### Emacs Mcp

[Emacs Mcp](https://github.com/lizqwerscott/mcp.el) is an Emacs client designed to interface with MCP servers, enabling seamless connections and interactions. It provides MCP tool invocation support for AI plugins like [gptel](https://github.com/karthink/gptel) and [llm](https://github.com/ahyatt/llm), adhering to Emacs' standard tool invocation format. This integration enhances the functionality of AI tools within the Emacs ecosystem.

**Key features:**

* Provides MCP tool support for Emacs.

### Firebase Genkit

[Genkit](https://github.com/firebase/genkit) is Firebase's SDK for building and integrating GenAI features into applications. The [genkitx-mcp](https://github.com/firebase/genkit/tree/main/js/plugins/mcp) plugin enables consuming MCP servers as a client or creating MCP servers from Genkit tools and prompts.

**Key features:**

* Client support for tools and prompts (resources partially supported)
* Rich discovery with support in Genkit's Dev UI playground
* Seamless interoperability with Genkit's existing tools and prompts
* Works across a wide variety of GenAI models from top providers

### GenAIScript

Programmatically assemble prompts for LLMs using [GenAIScript](https://microsoft.github.io/genaiscript/) (in JavaScript). Orchestrate LLMs, tools, and data in JavaScript.

**Key features:**

* JavaScript toolbox to work with prompts
* Abstraction to make it easy and productive
* Seamless Visual Studio Code integration

### Goose

[Goose](https://github.com/block/goose) is an open source AI agent that supercharges your software development by automating coding tasks.

**Key features:**

* Expose MCP functionality to Goose through tools.
* MCPs can be installed directly via the [extensions directory](https://block.github.io/goose/v1/extensions/), CLI, or UI.
* Goose allows you to extend its functionality by [building your own MCP servers](https://block.github.io/goose/docs/tutorials/custom-extensions).
* Includes built-in tools for development, web scraping, automation, memory, and integrations with JetBrains and Google Drive.

### LibreChat

[LibreChat](https://github.com/danny-avila/LibreChat) is an open-source, customizable AI chat UI that supports multiple AI providers, now including MCP integration.

**Key features:**

* Extend current tool ecosystem, including [Code Interpreter](https://www.librechat.ai/docs/features/code_interpreter) and Image generation tools, through MCP servers
* Add tools to customizable [Agents](https://www.librechat.ai/docs/features/agents), using a variety of LLMs from top providers
* Open-source and self-hostable, with secure multi-user support
* Future roadmap includes expanded MCP feature support

### mcp-agent

[mcp-agent] is a simple, composable framework to build agents using Model Context Protocol.

**Key features:**

* Automatic connection management of MCP servers.
* Expose tools from multiple servers to an LLM.
* Implements every pattern defined in [Building Effective Agents](https://www.anthropic.com/research/building-effective-agents).
* Supports workflow pause/resume signals, such as waiting for human feedback.

### Roo Code

[Roo Code](https://roocode.com) enables AI coding assistance via MCP.

**Key features:**

* Support for MCP tools and resources
* Integration with development workflows
* Extensible AI capabilities

### Sourcegraph Cody

[Cody](https://openctx.org/docs/providers/modelcontextprotocol) is Sourcegraph's AI coding assistant, which implements MCP through OpenCTX.

**Key features:**

* Support for MCP resources
* Integration with Sourcegraph's code intelligence
* Uses OpenCTX as an abstraction layer
* Future support planned for additional MCP features

### SpinAI

[SpinAI](https://spinai.dev) is an open-source TypeScript framework for building observable AI agents. The framework provides native MCP compatibility, allowing agents to seamlessly integrate with MCP servers and tools.

**Key features:**

* Built-in MCP compatibility for AI agents
* Open-source TypeScript framework
* Observable agent architecture
* Native support for MCP tools integration

### Superinterface

[Superinterface](https://superinterface.ai) is AI infrastructure and a developer platform to build in-app AI assistants with support for MCP, interactive components, client-side function calling and more.

**Key features:**

* Use tools from MCP servers in assistants embedded via React components or script tags
* SSE transport support
* Use any AI model from any AI provider (OpenAI, Anthropic, Ollama, others)

### TheiaAI/TheiaIDE

[Theia AI](https://eclipsesource.com/blogs/2024/10/07/introducing-theia-ai/) is a framework for building AI-enhanced tools and IDEs. The [AI-powered Theia IDE](https://eclipsesource.com/blogs/2024/10/08/introducting-ai-theia-ide/) is an open and flexible development environment built on Theia AI.

**Key features:**

* **Tool Integration**: Theia AI enables AI agents, including those in the Theia IDE, to utilize MCP servers for seamless tool interaction.
* **Customizable Prompts**: The Theia IDE allows users to define and adapt prompts, dynamically integrating MCP servers for tailored workflows.
* **Custom agents**: The Theia IDE supports creating custom agents that leverage MCP capabilities, enabling users to design dedicated workflows on the fly.

Theia AI and Theia IDE's MCP integration provide users with flexibility, making them powerful platforms for exploring and adapting MCP.

**Learn more:**

* [Theia IDE and Theia AI MCP Announcement](https://eclipsesource.com/blogs/2024/12/19/theia-ide-and-theia-ai-support-mcp/)
* [Download the AI-powered Theia IDE](https://theia-ide.org/)

### Windsurf Editor

[Windsurf Editor](https://codeium.com/windsurf) is an agentic IDE that combines AI assistance with developer workflows. It features an innovative AI Flow system that enables both collaborative and independent AI interactions while maintaining developer control.

**Key features:**

* Revolutionary AI Flow paradigm for human-AI collaboration
* Intelligent code generation and understanding
* Rich development tools with multi-model support

### Zed

[Zed](https://zed.dev/docs/assistant/model-context-protocol) is a high-performance code editor with built-in MCP support, focusing on prompt templates and tool integration.

**Key features:**

* Prompt templates surface as slash commands in the editor
* Tool integration for enhanced coding workflows
* Tight integration with editor features and workspace context
* Does not support MCP resources

### OpenSumi

[OpenSumi](https://github.com/opensumi/core) is a framework helps you quickly build AI Native IDE products.

**Key features:**

* Supports MCP tools in OpenSumi
* Supports built-in IDE MCP servers and custom MCP servers

### Daydreams

[Daydreams](https://github.com/daydreamsai/daydreams) is a generative agent framework for executing anything onchain

**Key features:**

* Supports MCP Servers in config
* Exposes MCP Client

## Adding MCP support to your application

If you've added MCP support to your application, we encourage you to submit a pull request to add it to this list. MCP integration can provide your users with powerful contextual AI capabilities and make your application part of the growing MCP ecosystem.

Benefits of adding MCP support:

* Enable users to bring their own context and tools
* Join a growing ecosystem of interoperable AI applications
* Provide users with flexible integration options
* Support local-first AI workflows

To get started with implementing MCP in your application, check out our [Python](https://github.com/modelcontextprotocol/python-sdk) or [TypeScript SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)

## Updates and corrections

This list is maintained by the community. If you notice any inaccuracies or would like to update information about MCP support in your application, please submit a pull request or [open an issue in our documentation repository](https://github.com/modelcontextprotocol/docs/issues).


# Contributing
Source: https://modelcontextprotocol.io/development/contributing

How to participate in Model Context Protocol development

We welcome contributions from the community! Please review our [contributing guidelines](https://github.com/modelcontextprotocol/.github/blob/main/CONTRIBUTING.md) for details on how to submit changes.

All contributors must adhere to our [Code of Conduct](https://github.com/modelcontextprotocol/.github/blob/main/CODE_OF_CONDUCT.md).

For questions and discussions, please use [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions).


# Roadmap
Source: https://modelcontextprotocol.io/development/roadmap

Our plans for evolving Model Context Protocol (H1 2025)

The Model Context Protocol is rapidly evolving. This page outlines our current thinking on key priorities and future direction for **the first half of 2025**, though these may change significantly as the project develops.

<Note>The ideas presented here are not commitments—we may solve these challenges differently than described, or some may not materialize at all. This is also not an *exhaustive* list; we may incorporate work that isn't mentioned here.</Note>

We encourage community participation! Each section links to relevant discussions where you can learn more and contribute your thoughts.

## Remote MCP Support

Our top priority is enabling [remote MCP connections](https://github.com/modelcontextprotocol/specification/discussions/102), allowing clients to securely connect to MCP servers over the internet. Key initiatives include:

*   [**Authentication & Authorization**](https://github.com/modelcontextprotocol/specification/discussions/64): Adding standardized auth capabilities, particularly focused on OAuth 2.0 support.

*   [**Service Discovery**](https://github.com/modelcontextprotocol/specification/discussions/69): Defining how clients can discover and connect to remote MCP servers.

*   [**Stateless Operations**](https://github.com/modelcontextprotocol/specification/discussions/102): Thinking about whether MCP could encompass serverless environments too, where they will need to be mostly stateless.

## Reference Implementations

To help developers build with MCP, we want to offer documentation for:

*   **Client Examples**: Comprehensive reference client implementation(s), demonstrating all protocol features
*   **Protocol Drafting**: Streamlined process for proposing and incorporating new protocol features

## Distribution & Discovery

Looking ahead, we're exploring ways to make MCP servers more accessible. Some areas we may investigate include:

*   **Package Management**: Standardized packaging format for MCP servers
*   **Installation Tools**: Simplified server installation across MCP clients
*   **Sandboxing**: Improved security through server isolation
*   **Server Registry**: A common directory for discovering available MCP servers

## Agent Support

We're expanding MCP's capabilities for [complex agentic workflows](https://github.com/modelcontextprotocol/specification/discussions/111), particularly focusing on:

*   [**Hierarchical Agent Systems**](https://github.com/modelcontextprotocol/specification/discussions/94): Improved support for trees of agents through namespacing and topology awareness.

*   [**Interactive Workflows**](https://github.com/modelcontextprotocol/specification/issues/97): Better handling of user permissions and information requests across agent hierarchies, and ways to send output to users instead of models.

*   [**Streaming Results**](https://github.com/modelcontextprotocol/specification/issues/117): Real-time updates from long-running agent operations.

## Broader Ecosystem

We're also invested in:

*   **Community-Led Standards Development**: Fostering a collaborative ecosystem where all AI providers can help shape MCP as an open standard through equal participation and shared governance, ensuring it meets the needs of diverse AI applications and use cases.
*   [**Additional Modalities**](https://github.com/modelcontextprotocol/specification/discussions/88): Expanding beyond text to support audio, video, and other formats.
*   \[**Standardization**] Considering standardization through a standardization body.

## Get Involved

We welcome community participation in shaping MCP's future. Visit our [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions) to join the conversation and contribute your ideas.


# What's New
Source: https://modelcontextprotocol.io/development/updates

The latest updates and improvements to MCP

<Update label="2025-02-14" description="Java SDK released">
  * We're excited to announce that the Java SDK developed by Spring AI at VMware Tanzu is now
    the official [Java SDK](https://github.com/modelcontextprotocol/java-sdk) for MCP.
    This joins our existing Kotlin SDK in our growing list of supported languages.
    The Spring AI team will maintain the SDK as an integral part of the Model Context Protocol
    organization. We're thrilled to welcome them to the MCP community!
</Update>

<Update label="2025-01-27" description="Python SDK 1.2.1">
  * Version [1.2.1](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.2.1) of the MCP Python SDK has been released,
    delivering important stability improvements and bug fixes.
</Update>

<Update label="2025-01-18" description="SDK and Server Improvements">
  * Simplified, express-like API in the [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
  * Added 8 new clients to the [clients page](https://modelcontextprotocol.io/clients)
</Update>

<Update label="2025-01-03" description="SDK and Server Improvements">
  * FastMCP API in the [Python SDK](https://github.com/modelcontextprotocol/python-sdk)
  * Dockerized MCP servers in the [servers repo](https://github.com/modelcontextprotocol/servers)
</Update>

<Update label="2024-12-21" description="Kotlin SDK released">
  * Jetbrains released a Kotlin SDK for MCP!
  * For a sample MCP Kotlin server, check out [this repository](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/kotlin-mcp-server)
</Update>


# Core architecture
Source: https://modelcontextprotocol.io/docs/concepts/architecture

Understand how MCP connects clients, servers, and LLMs

The Model Context Protocol (MCP) is built on a flexible, extensible architecture that enables seamless communication between LLM applications and integrations. This document covers the core architectural components and concepts.

## Overview

MCP follows a client-server architecture where:

* **Hosts** are LLM applications (like Claude Desktop or IDEs) that initiate connections
* **Clients** maintain 1:1 connections with servers, inside the host application
* **Servers** provide context, tools, and prompts to clients

```mermaid
flowchart LR
    subgraph "Host"
        client1[MCP Client]
        client2[MCP Client]
    end
    subgraph "Server Process"
        server1[MCP Server]
    end
    subgraph "Server Process"
        server2[MCP Server]
    end

    client1 <-->|Transport Layer| server1
    client2 <-->|Transport Layer| server2
```

## Core components

### Protocol layer

The protocol layer handles message framing, request/response linking, and high-level communication patterns.

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    class Protocol<Request, Notification, Result> {
        // Handle incoming requests
        setRequestHandler<T>(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise<Result>): void

        // Handle incoming notifications
        setNotificationHandler<T>(schema: T, handler: (notification: T) => Promise<void>): void

        // Send requests and await responses
        request<T>(request: Request, schema: T, options?: RequestOptions): Promise<T>

        // Send one-way notifications
        notification(notification: Notification): Promise<void>
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python
    class Session(BaseSession[RequestT, NotificationT, ResultT]):
        async def send_request(
            self,
            request: RequestT,
            result_type: type[Result]
        ) -> Result:
            """
            Send request and wait for response. Raises McpError if response contains error.
            """
            # Request handling implementation

        async def send_notification(
            self,
            notification: NotificationT
        ) -> None:
            """Send one-way notification that doesn't expect response."""
            # Notification handling implementation

        async def _received_request(
            self,
            responder: RequestResponder[ReceiveRequestT, ResultT]
        ) -> None:
            """Handle incoming request from other side."""
            # Request handling implementation

        async def _received_notification(
            self,
            notification: ReceiveNotificationT
        ) -> None:
            """Handle incoming notification from other side."""
            # Notification handling implementation
    ```
  </Tab>
</Tabs>

Key classes include:

* `Protocol`
* `Client`
* `Server`

### Transport layer

The transport layer handles the actual communication between clients and servers. MCP supports multiple transport mechanisms:

1. **Stdio transport**
   * Uses standard input/output for communication
   * Ideal for local processes

2. **HTTP with SSE transport**
   * Uses Server-Sent Events for server-to-client messages
   * HTTP POST for client-to-server messages

All transports use [JSON-RPC](https://www.jsonrpc.org/) 2.0 to exchange messages. See the [specification](https://spec.modelcontextprotocol.io) for detailed information about the Model Context Protocol message format.

### Message types

MCP has these main types of messages:

1. **Requests** expect a response from the other side:
   ```typescript
   interface Request {
     method: string;
     params?: { ... };
   }
   ```

2. **Results** are successful responses to requests:
   ```typescript
   interface Result {
     [key: string]: unknown;
   }
   ```

3. **Errors** indicate that a request failed:
   ```typescript
   interface Error {
     code: number;
     message: string;
     data?: unknown;
   }
   ```

4. **Notifications** are one-way messages that don't expect a response:
   ```typescript
   interface Notification {
     method: string;
     params?: { ... };
   }
   ```

## Connection lifecycle

### 1. Initialization

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: initialize request
    Server->>Client: initialize response
    Client->>Server: initialized notification

    Note over Client,Server: Connection ready for use
```

1. Client sends `initialize` request with protocol version and capabilities
2. Server responds with its protocol version and capabilities
3. Client sends `initialized` notification as acknowledgment
4. Normal message exchange begins

### 2. Message exchange

After initialization, the following patterns are supported:

* **Request-Response**: Client or server sends requests, the other responds
* **Notifications**: Either party sends one-way messages

### 3. Termination

Either party can terminate the connection:

* Clean shutdown via `close()`
* Transport disconnection
* Error conditions

## Error handling

MCP defines these standard error codes:

```typescript
enum ErrorCode {
  // Standard JSON-RPC error codes
  ParseError = -32700,
  InvalidRequest = -32600,
  MethodNotFound = -32601,
  InvalidParams = -32602,
  InternalError = -32603
}
```

SDKs and applications can define their own error codes above -32000.

Errors are propagated through:

* Error responses to requests
* Error events on transports
* Protocol-level error handlers

## Implementation example

Here's a basic example of implementing an MCP server:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    import { Server } from "@modelcontextprotocol/sdk/server/index.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {
        resources: {}
      }
    });

    // Handle requests
    server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: [
          {
            uri: "example://resource",
            name: "Example Resource"
          }
        ]
      };
    });

    // Connect transport
    const transport = new StdioServerTransport();
    await server.connect(transport);
    ```
  </Tab>

  <Tab title="Python">
    ```python
    import asyncio
    import mcp.types as types
    from mcp.server import Server
    from mcp.server.stdio import stdio_server

    app = Server("example-server")

    @app.list_resources()
    async def list_resources() -> list[types.Resource]:
        return [
            types.Resource(
                uri="example://resource",
                name="Example Resource"
            )
        ]

    async def main():
        async with stdio_server() as streams:
            await app.run(
                streams[0],
                streams[1],
                app.create_initialization_options()
            )

    if __name__ == "__main__":
        asyncio.run(main)
    ```
  </Tab>
</Tabs>

## Best practices

### Transport selection

1. **Local communication**
   * Use stdio transport for local processes
   * Efficient for same-machine communication
   * Simple process management

2. **Remote communication**
   * Use SSE for scenarios requiring HTTP compatibility
   * Consider security implications including authentication and authorization

### Message handling

1. **Request processing**
   * Validate inputs thoroughly
   * Use type-safe schemas
   * Handle errors gracefully
   * Implement timeouts

2. **Progress reporting**
   * Use progress tokens for long operations
   * Report progress incrementally
   * Include total progress when known

3. **Error management**
   * Use appropriate error codes
   * Include helpful error messages
   * Clean up resources on errors

## Security considerations

1. **Transport security**
   * Use TLS for remote connections
   * Validate connection origins
   * Implement authentication when needed

2. **Message validation**
   * Validate all incoming messages
   * Sanitize inputs
   * Check message size limits
   * Verify JSON-RPC format

3. **Resource protection**
   * Implement access controls
   * Validate resource paths
   * Monitor resource usage
   * Rate limit requests

4. **Error handling**
   * Don't leak sensitive information
   * Log security-relevant errors
   * Implement proper cleanup
   * Handle DoS scenarios

## Debugging and monitoring

1. **Logging**
   * Log protocol events
   * Track message flow
   * Monitor performance
   * Record errors

2. **Diagnostics**
   * Implement health checks
   * Monitor connection state
   * Track resource usage
   * Profile performance

3. **Testing**
   * Test different transports
   * Verify error handling
   * Check edge cases
   * Load test servers


# Prompts
Source: https://modelcontextprotocol.io/docs/concepts/prompts

Create reusable prompt templates and workflows

Prompts enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs. They provide a powerful way to standardize and share common LLM interactions.

<Note>
  Prompts are designed to be **user-controlled**, meaning they are exposed from servers to clients with the intention of the user being able to explicitly select them for use.
</Note>

## Overview

Prompts in MCP are predefined templates that can:

*   Accept dynamic arguments
*   Include context from resources
*   Chain multiple interactions
*   Guide specific workflows
*   Surface as UI elements (like slash commands)

## Prompt structure

Each prompt is defined with:

```typescript
{
  name: string;              // Unique identifier for the prompt
  description?: string;      // Human-readable description
  arguments?: [              // Optional list of arguments
    {
      name: string;          // Argument identifier
      description?: string;  // Argument description
      required?: boolean;    // Whether argument is required
    }
  ]
}
```

## Discovering prompts

Clients can discover available prompts through the `prompts/list` endpoint:

```typescript
// Request
{
  method: "prompts/list"
}

// Response
{
  prompts: [
    {
      name: "analyze-code",
      description: "Analyze code for potential improvements",
      arguments: [
        {
          name: "language",
          description: "Programming language",
          required: true
        }
      ]
    }
  ]
}
```

## Using prompts

To use a prompt, clients make a `prompts/get` request:

````typescript
// Request
{
  method: "prompts/get",
  params: {
    name: "analyze-code",
    arguments: {
      language: "python"
    }
  }
}

// Response
{
  description: "Analyze Python code for potential improvements",
  messages: [
    {
      role: "user",
      content: {
        type: "text",
        text: "Please analyze the following Python code for potential improvements:\n\n```python\ndef calculate_sum(numbers):\n    total = 0\n    for num in numbers:\n        total = total + num\n    return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```"
      }
    }
  ]
}
````

## Dynamic prompts

Prompts can be dynamic and include:

### Embedded resource context

```json
{
  "name": "analyze-project",
  "description": "Analyze project logs and code",
  "arguments": [
    {
      "name": "timeframe",
      "description": "Time period to analyze logs",
      "required": true
    },
    {
      "name": "fileUri",
      "description": "URI of code file to review",
      "required": true
    }
  ]
}
```

When handling the `prompts/get` request:

```json
{
  "messages": [
    {
      "role": "user",
      "content": {
        "type": "text",
        "text": "Analyze these system logs and the code file for any issues:"
      }
    },
    {
      "role": "user",
      "content": {
        "type": "resource",
        "resource": {
          "uri": "logs://recent?timeframe=1h",
          "text": "[2024-03-14 15:32:11] ERROR: Connection timeout in network.py:127\n[2024-03-14 15:32:15] WARN: Retrying connection (attempt 2/3)\n[2024-03-14 15:32:20] ERROR: Max retries exceeded",
          "mimeType": "text/plain"
        }
      }
    },
    {
      "role": "user",
      "content": {
        "type": "resource",
        "resource": {
          "uri": "file:///path/to/code.py",
          "text": "def connect_to_service(timeout=30):\n    retries = 3\n    for attempt in range(retries):\n        try:\n            return establish_connection(timeout)\n        except TimeoutError:\n            if attempt == retries - 1:\n                raise\n            time.sleep(5)\n\ndef establish_connection(timeout):\n    # Connection implementation\n    pass",
          "mimeType": "text/x-python"
        }
      }
    }
  ]
}
```

### Multi-step workflows

```typescript
const debugWorkflow = {
  name: "debug-error",
  async getMessages(error: string) {
    return [
      {
        role: "user",
        content: {
          type: "text",
          text: `Here's an error I'm seeing: ${error}`
        }
      },
      {
        role: "assistant",
        content: {
          type: "text",
          text: "I'll help analyze this error. What have you tried so far?"
        }
      },
      {
        role: "user",
        content: {
          type: "text",
          text: "I've tried restarting the service, but the error persists."
        }
      }
    ];
  }
};
```

## Example implementation

Here's a complete example of implementing prompts in an MCP server:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    import { Server } from "@modelcontextprotocol/sdk/server";
    import {
      ListPromptsRequestSchema,
      GetPromptRequestSchema
    } from "@modelcontextprotocol/sdk/types";

    const PROMPTS = {
      "git-commit": {
        name: "git-commit",
        description: "Generate a Git commit message",
        arguments: [
          {
            name: "changes",
            description: "Git diff or description of changes",
            required: true
          }
        ]
      },
      "explain-code": {
        name: "explain-code",
        description: "Explain how code works",
        arguments: [
          {
            name: "code",
            description: "Code to explain",
            required: true
          },
          {
            name: "language",
            description: "Programming language",
            required: false
          }
        ]
      }
    };

    const server = new Server({
      name: "example-prompts-server",
      version: "1.0.0"
    }, {
      capabilities: {
        prompts: {}
      }
    });

    // List available prompts
    server.setRequestHandler(ListPromptsRequestSchema, async () => {
      return {
        prompts: Object.values(PROMPTS)
      };
    });

    // Get specific prompt
    server.setRequestHandler(GetPromptRequestSchema, async (request) => {
      const prompt = PROMPTS[request.params.name];
      if (!prompt) {
        throw new Error(`Prompt not found: ${request.params.name}`);
      }

      if (request.params.name === "git-commit") {
        return {
          messages: [
            {
              role: "user",
              content: {
                type: "text",
                text: `Generate a concise but descriptive commit message for these changes:\n\n${request.params.arguments?.changes}`
              }
            }
          ]
        };
      }

      if (request.params.name === "explain-code") {
        const language = request.params.arguments?.language || "Unknown";
        return {
          messages: [
            {
              role: "user",
              content: {
                type: "text",
                text: `Explain how this ${language} code works:\n\n${request.params.arguments?.code}`
              }
            }
          ]
        };
      }

      throw new Error("Prompt implementation not found");
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    from mcp.server import Server
    import mcp.types as types

    # Define available prompts
    PROMPTS = {
        "git-commit": types.Prompt(
            name="git-commit",
            description="Generate a Git commit message",
            arguments=[
                types.PromptArgument(
                    name="changes",
                    description="Git diff or description of changes",
                    required=True
                )
            ],
        ),
        "explain-code": types.Prompt(
            name="explain-code",
            description="Explain how code works",
            arguments=[
                types.PromptArgument(
                    name="code",
                    description="Code to explain",
                    required=True
                ),
                types.PromptArgument(
                    name="language",
                    description="Programming language",
                    required=False
                )
            ],
        )
    }

    # Initialize server
    app = Server("example-prompts-server")

    @app.list_prompts()
    async def list_prompts() -> list[types.Prompt]:
        return list(PROMPTS.values())

    @app.get_prompt()
    async def get_prompt(
        name: str, arguments: dict[str, str] | None = None
    ) -> types.GetPromptResult:
        if name not in PROMPTS:
            raise ValueError(f"Prompt not found: {name}")

        if name == "git-commit":
            changes = arguments.get("changes") if arguments else ""
            return types.GetPromptResult(
                messages=[
                    types.PromptMessage(
                        role="user",
                        content=types.TextContent(
                            type="text",
                            text=f"Generate a concise but descriptive commit message "
                            f"for these changes:\n\n{changes}"
                        )
                    )
                ]
            )

        if name == "explain-code":
            code = arguments.get("code") if arguments else ""
            language = arguments.get("language", "Unknown") if arguments else "Unknown"
            return types.GetPromptResult(
                messages=[
                    types.PromptMessage(
                        role="user",
                        content=types.TextContent(
                            type="text",
                            text=f"Explain how this {language} code works:\n\n{code}"
                        )
                    )
                ]
            )

        raise ValueError("Prompt implementation not found")
    ```
  </Tab>
</Tabs>

## Best practices

When implementing prompts:

1.  Use clear, descriptive prompt names
2.  Provide detailed descriptions for prompts and arguments
3.  Validate all required arguments
4.  Handle missing arguments gracefully
5.  Consider versioning for prompt templates
6.  Cache dynamic content when appropriate
7.  Implement error handling
8.  Document expected argument formats
9.  Consider prompt composability
10. Test prompts with various inputs

## UI integration

Prompts can be surfaced in client UIs as:

*   Slash commands
*   Quick actions
*   Context menu items
*   Command palette entries
*   Guided workflows
*   Interactive forms

## Updates and changes

Servers can notify clients about prompt changes:

1.  Server capability: `prompts.listChanged`
2.  Notification: `notifications/prompts/list_changed`
3.  Client re-fetches prompt list

## Security considerations

When implementing prompts:

*   Validate all arguments
*   Sanitize user input
*   Consider rate limiting
*   Implement access controls
*   Audit prompt usage
*   Handle sensitive data appropriately
*   Validate generated content
*   Implement timeouts
*   Consider prompt injection risks
*   Document security requirements


# Resources
Source: https://modelcontextprotocol.io/docs/concepts/resources

Expose data and content from your servers to LLMs

Resources are a core primitive in the Model Context Protocol (MCP) that allow servers to expose data and content that can be read by clients and used as context for LLM interactions.

<Note>
  Resources are designed to be **application-controlled**, meaning that the client application can decide how and when they should be used.
  Different MCP clients may handle resources differently. For example:

  *   Claude Desktop currently requires users to explicitly select resources before they can be used
  *   Other clients might automatically select resources based on heuristics
  *   Some implementations may even allow the AI model itself to determine which resources to use

  Server authors should be prepared to handle any of these interaction patterns when implementing resource support. In order to expose data to models automatically, server authors should use a **model-controlled** primitive such as [Tools](./tools).
</Note>

## Overview

Resources represent any kind of data that an MCP server wants to make available to clients. This can include:

*   File contents
*   Database records
*   API responses
*   Live system data
*   Screenshots and images
*   Log files
*   And more

Each resource is identified by a unique URI and can contain either text or binary data.

## Resource URIs

Resources are identified using URIs that follow this format:

```
[protocol]://[host]/[path]
```

For example:

*   `file:///home/user/documents/report.pdf`
*   `postgres://database/customers/schema`
*   `screen://localhost/display1`

The protocol and path structure is defined by the MCP server implementation. Servers can define their own custom URI schemes.

## Resource types

Resources can contain two types of content:

### Text resources

Text resources contain UTF-8 encoded text data. These are suitable for:

*   Source code
*   Configuration files
*   Log files
*   JSON/XML data
*   Plain text

### Binary resources

Binary resources contain raw binary data encoded in base64. These are suitable for:

*   Images
*   PDFs
*   Audio files
*   Video files
*   Other non-text formats

## Resource discovery

Clients can discover available resources through two main methods:

### Direct resources

Servers expose a list of concrete resources via the `resources/list` endpoint. Each resource includes:

```typescript
{
  uri: string;           // Unique identifier for the resource
  name: string;          // Human-readable name
  description?: string;  // Optional description
  mimeType?: string;     // Optional MIME type
}
```

### Resource templates

For dynamic resources, servers can expose [URI templates](https://datatracker.ietf.org/doc/html/rfc6570) that clients can use to construct valid resource URIs:

```typescript
{
  uriTemplate: string;   // URI template following RFC 6570
  name: string;          // Human-readable name for this type
  description?: string;  // Optional description
  mimeType?: string;     // Optional MIME type for all matching resources
}
```

## Reading resources

To read a resource, clients make a `resources/read` request with the resource URI.

The server responds with a list of resource contents:

```typescript
{
  contents: [
    {
      uri: string;        // The URI of the resource
      mimeType?: string;  // Optional MIME type

      // One of:
      text?: string;      // For text resources
      blob?: string;      // For binary resources (base64 encoded)
    }
  ]
}
```

<Tip>
  Servers may return multiple resources in response to one `resources/read` request. This could be used, for example, to return a list of files inside a directory when the directory is read.
</Tip>

## Resource updates

MCP supports real-time updates for resources through two mechanisms:

### List changes

Servers can notify clients when their list of available resources changes via the `notifications/resources/list_changed` notification.

### Content changes

Clients can subscribe to updates for specific resources:

1.  Client sends `resources/subscribe` with resource URI
2.  Server sends `notifications/resources/updated` when the resource changes
3.  Client can fetch latest content with `resources/read`
4.  Client can unsubscribe with `resources/unsubscribe`

## Example implementation

Here's a simple example of implementing resource support in an MCP server:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {
        resources: {}
      }
    });

    // List available resources
    server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: [
          {
            uri: "file:///logs/app.log",
            name: "Application Logs",
            mimeType: "text/plain"
          }
        ]
      };
    });

    // Read resource contents
    server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
      const uri = request.params.uri;

      if (uri === "file:///logs/app.log") {
        const logContents = await readLogFile();
        return {
          contents: [
            {
              uri,
              mimeType: "text/plain",
              text: logContents
            }
          ]
        };
      }

      throw new Error("Resource not found");
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    app = Server("example-server")

    @app.list_resources()
    async def list_resources() -> list[types.Resource]:
        return [
            types.Resource(
                uri="file:///logs/app.log",
                name="Application Logs",
                mimeType="text/plain"
            )
        ]

    @app.read_resource()
    async def read_resource(uri: AnyUrl) -> str:
        if str(uri) == "file:///logs/app.log":
            log_contents = await read_log_file()
            return log_contents

        raise ValueError("Resource not found")

    # Start server
    async with stdio_server() as streams:
        await app.run(
            streams[0],
            streams[1],
            app.create_initialization_options()
        )
    ```
  </Tab>
</Tabs>

## Best practices

When implementing resource support:

1.  Use clear, descriptive resource names and URIs
2.  Include helpful descriptions to guide LLM understanding
3.  Set appropriate MIME types when known
4.  Implement resource templates for dynamic content
5.  Use subscriptions for frequently changing resources
6.  Handle errors gracefully with clear error messages
7.  Consider pagination for large resource lists
8.  Cache resource contents when appropriate
9.  Validate URIs before processing
10. Document your custom URI schemes

## Security considerations

When exposing resources:

*   Validate all resource URIs
*   Implement appropriate access controls
*   Sanitize file paths to prevent directory traversal
*   Be cautious with binary data handling
*   Consider rate limiting for resource reads
*   Audit resource access
*   Encrypt sensitive data in transit
*   Validate MIME types
*   Implement timeouts for long-running reads
*   Handle resource cleanup appropriately


# Roots
Source: https://modelcontextprotocol.io/docs/concepts/roots

Understanding roots in MCP

Roots are a concept in MCP that define the boundaries where servers can operate. They provide a way for clients to inform servers about relevant resources and their locations.

## What are Roots?

A root is a URI that a client suggests a server should focus on. When a client connects to a server, it declares which roots the server should work with. While primarily used for filesystem paths, roots can be any valid URI including HTTP URLs.

For example, roots could be:

```
file:///home/user/projects/myapp
https://api.example.com/v1
```

## Why Use Roots?

Roots serve several important purposes:

1.  **Guidance**: They inform servers about relevant resources and locations
2.  **Clarity**: Roots make it clear which resources are part of your workspace
3.  **Organization**: Multiple roots let you work with different resources simultaneously

## How Roots Work

When a client supports roots, it:

1.  Declares the `roots` capability during connection
2.  Provides a list of suggested roots to the server
3.  Notifies the server when roots change (if supported)

While roots are informational and not strictly enforcing, servers should:

1.  Respect the provided roots
2.  Use root URIs to locate and access resources
3.  Prioritize operations within root boundaries

## Common Use Cases

Roots are commonly used to define:

*   Project directories
*   Repository locations
*   API endpoints
*   Configuration locations
*   Resource boundaries

## Best Practices

When working with roots:

1.  Only suggest necessary resources
2.  Use clear, descriptive names for roots
3.  Monitor root accessibility
4.  Handle root changes gracefully

## Example

Here's how a typical MCP client might expose roots:

```json
{
  "roots": [
    {
      "uri": "file:///home/user/projects/frontend",
      "name": "Frontend Repository"
    },
    {
      "uri": "https://api.example.com/v1",
      "name": "API Endpoint"
    }
  ]
}
```

This configuration suggests the server focus on both a local repository and an API endpoint while keeping them logically separated.


# Sampling
Source: https://modelcontextprotocol.io/docs/concepts/sampling

Let your servers request completions from LLMs

Sampling is a powerful MCP feature that allows servers to request LLM completions through the client, enabling sophisticated agentic behaviors while maintaining security and privacy.

<Info>
  This feature of MCP is not yet supported in the Claude Desktop client.
</Info>

## How sampling works

The sampling flow follows these steps:

1.  Server sends a `sampling/createMessage` request to the client
2.  Client reviews the request and can modify it
3.  Client samples from an LLM
4.  Client reviews the completion
5.  Client returns the result to the server

This human-in-the-loop design ensures users maintain control over what the LLM sees and generates.

## Message format

Sampling requests use a standardized message format:

```typescript
{
  messages: [
    {
      role: "user" | "assistant",
      content: {
        type: "text" | "image",

        // For text:
        text?: string,

        // For images:
        data?: string,             // base64 encoded
        mimeType?: string
      }
    }
  ],
  modelPreferences?: {
    hints?: [{
      name?: string                // Suggested model name/family
    }],
    costPriority?: number,         // 0-1, importance of minimizing cost
    speedPriority?: number,        // 0-1, importance of low latency
    intelligencePriority?: number  // 0-1, importance of capabilities
  },
  systemPrompt?: string,
  includeContext?: "none" | "thisServer" | "allServers",
  temperature?: number,
  maxTokens: number,
  stopSequences?: string[],
  metadata?: Record<string, unknown>
}
```

## Request parameters

### Messages

The `messages` array contains the conversation history to send to the LLM. Each message has:

*   `role`: Either "user" or "assistant"
*   `content`: The message content, which can be:
    *   Text content with a `text` field
    *   Image content with `data` (base64) and `mimeType` fields

### Model preferences

The `modelPreferences` object allows servers to specify their model selection preferences:

*   `hints`: Array of model name suggestions that clients can use to select an appropriate model:
    *   `name`: String that can match full or partial model names (e.g. "claude-3", "sonnet")
    *   Clients may map hints to equivalent models from different providers
    *   Multiple hints are evaluated in preference order

*   Priority values (0-1 normalized):
    *   `costPriority`: Importance of minimizing costs
    *   `speedPriority`: Importance of low latency response
    *   `intelligencePriority`: Importance of advanced model capabilities

Clients make the final model selection based on these preferences and their available models.

### System prompt

An optional `systemPrompt` field allows servers to request a specific system prompt. The client may modify or ignore this.

### Context inclusion

The `includeContext` parameter specifies what MCP context to include:

*   `"none"`: No additional context
*   `"thisServer"`: Include context from the requesting server
*   `"allServers"`: Include context from all connected MCP servers

The client controls what context is actually included.

### Sampling parameters

Fine-tune the LLM sampling with:

*   `temperature`: Controls randomness (0.0 to 1.0)
*   `maxTokens`: Maximum tokens to generate
*   `stopSequences`: Array of sequences that stop generation
*   `metadata`: Additional provider-specific parameters

## Response format

The client returns a completion result:

```typescript
{
  model: string,  // Name of the model used
  stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string,
  role: "user" | "assistant",
  content: {
    type: "text" | "image",
    text?: string,
    data?: string,
    mimeType?: string
  }
}
```

## Example request

Here's an example of requesting sampling from a client:

```json
{
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "What files are in the current directory?"
        }
      }
    ],
    "systemPrompt": "You are a helpful file system assistant.",
    "includeContext": "thisServer",
    "maxTokens": 100
  }
}
```

## Best practices

When implementing sampling:

1.  Always provide clear, well-structured prompts
2.  Handle both text and image content appropriately
3.  Set reasonable token limits
4.  Include relevant context through `includeContext`
5.  Validate responses before using them
6.  Handle errors gracefully
7.  Consider rate limiting sampling requests
8.  Document expected sampling behavior
9.  Test with various model parameters
10. Monitor sampling costs

## Human in the loop controls

Sampling is designed with human oversight in mind:

### For prompts

*   Clients should show users the proposed prompt
*   Users should be able to modify or reject prompts
*   System prompts can be filtered or modified
*   Context inclusion is controlled by the client

### For completions

*   Clients should show users the completion
*   Users should be able to modify or reject completions
*   Clients can filter or modify completions
*   Users control which model is used

## Security considerations

When implementing sampling:

*   Validate all message content
*   Sanitize sensitive information
*   Implement appropriate rate limits
*   Monitor sampling usage
*   Encrypt data in transit
*   Handle user data privacy
*   Audit sampling requests
*   Control cost exposure
*   Implement timeouts
*   Handle model errors gracefully

## Common patterns

### Agentic workflows

Sampling enables agentic patterns like:

*   Reading and analyzing resources
*   Making decisions based on context
*   Generating structured data
*   Handling multi-step tasks
*   Providing interactive assistance

### Context management

Best practices for context:

*   Request minimal necessary context
*   Structure context clearly
*   Handle context size limits
*   Update context as needed
*   Clean up stale context

### Error handling

Robust error handling should:

*   Catch sampling failures
*   Handle timeout errors
*   Manage rate limits
*   Validate responses
*   Provide fallback behaviors
*   Log errors appropriately

## Limitations

Be aware of these limitations:

*   Sampling depends on client capabilities
*   Users control sampling behavior
*   Context size has limits
*   Rate limits may apply
*   Costs should be considered
*   Model availability varies
*   Response times vary
*   Not all content types supported


# Tools
Source: https://modelcontextprotocol.io/docs/concepts/tools

Enable LLMs to perform actions through your server

Tools are a powerful primitive in the Model Context Protocol (MCP) that enable servers to expose executable functionality to clients. Through tools, LLMs can interact with external systems, perform computations, and take actions in the real world.

<Note>
  Tools are designed to be **model-controlled**, meaning that tools are exposed from servers to clients with the intention of the AI model being able to automatically invoke them (with a human in the loop to grant approval).
</Note>

## Overview

Tools in MCP allow servers to expose executable functions that can be invoked by clients and used by LLMs to perform actions. Key aspects of tools include:

*   **Discovery**: Clients can list available tools through the `tools/list` endpoint
*   **Invocation**: Tools are called using the `tools/call` endpoint, where servers perform the requested operation and return results
*   **Flexibility**: Tools can range from simple calculations to complex API interactions

Like [resources](/docs/concepts/resources), tools are identified by unique names and can include descriptions to guide their usage. However, unlike resources, tools represent dynamic operations that can modify state or interact with external systems.

## Tool definition structure

Each tool is defined with the following structure:

```typescript
{
  name: string;          // Unique identifier for the tool
  description?: string;  // Human-readable description
  inputSchema: {         // JSON Schema for the tool's parameters
    type: "object",
    properties: { ... }  // Tool-specific parameters
  }
}
```

## Implementing tools

Here's an example of implementing a basic tool in an MCP server:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {
        tools: {}
      }
    });

    // Define available tools
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [{
          name: "calculate_sum",
          description: "Add two numbers together",
          inputSchema: {
            type: "object",
            properties: {
              a: { type: "number" },
              b: { type: "number" }
            },
            required: ["a", "b"]
          }
        }]
      };
    });

    // Handle tool execution
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      if (request.params.name === "calculate_sum") {
        const { a, b } = request.params.arguments;
        return {
          content: [
            {
              type: "text",
              text: String(a + b)
            }
          ]
        };
      }
      throw new Error("Tool not found");
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    app = Server("example-server")

    @app.list_tools()
    async def list_tools() -> list[types.Tool]:
        return [
            types.Tool(
                name="calculate_sum",
                description="Add two numbers together",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "a": {"type": "number"},
                        "b": {"type": "number"}
                    },
                    "required": ["a", "b"]
                }
            )
        ]

    @app.call_tool()
    async def call_tool(
        name: str,
        arguments: dict
    ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        if name == "calculate_sum":
            a = arguments["a"]
            b = arguments["b"]
            result = a + b
            return [types.TextContent(type="text", text=str(result))]
        raise ValueError(f"Tool not found: {name}")
    ```
  </Tab>
</Tabs>

## Example tool patterns

Here are some examples of types of tools that a server could provide:

### System operations

Tools that interact with the local system:

```typescript
{
  name: "execute_command",
  description: "Run a shell command",
  inputSchema: {
    type: "object",
    properties: {
      command: { type: "string" },
      args: { type: "array", items: { type: "string" } }
    }
  }
}
```

### API integrations

Tools that wrap external APIs:

```typescript
{
  name: "github_create_issue",
  description: "Create a GitHub issue",
  inputSchema: {
    type: "object",
    properties: {
      title: { type: "string" },
      body: { type: "string" },
      labels: { type: "array", items: { type: "string" } }
    }
  }
}
```

### Data processing

Tools that transform or analyze data:

```typescript
{
  name: "analyze_csv",
  description: "Analyze a CSV file",
  inputSchema: {
    type: "object",
    properties: {
      filepath: { type: "string" },
      operations: {
        type: "array",
        items: {
          enum: ["sum", "average", "count"]
        }
      }
    }
  }
}
```

## Best practices

When implementing tools:

1.  Provide clear, descriptive names and descriptions
2.  Use detailed JSON Schema definitions for parameters
3.  Include examples in tool descriptions to demonstrate how the model should use them
4.  Implement proper error handling and validation
5.  Use progress reporting for long operations
6.  Keep tool operations focused and atomic
7.  Document expected return value structures
8.  Implement proper timeouts
9.  Consider rate limiting for resource-intensive operations
10. Log tool usage for debugging and monitoring

## Security considerations

When exposing tools:

### Input validation

*   Validate all parameters against the schema
*   Sanitize file paths and system commands
*   Validate URLs and external identifiers
*   Check parameter sizes and ranges
*   Prevent command injection

### Access control

*   Implement authentication where needed
*   Use appropriate authorization checks
*   Audit tool usage
*   Rate limit requests
*   Monitor for abuse

### Error handling

*   Don't expose internal errors to clients
*   Log security-relevant errors
*   Handle timeouts appropriately
*   Clean up resources after errors
*   Validate return values

## Tool discovery and updates

MCP supports dynamic tool discovery:

1.  Clients can list available tools at any time
2.  Servers can notify clients when tools change using `notifications/tools/list_changed`
3.  Tools can be added or removed during runtime
4.  Tool definitions can be updated (though this should be done carefully)

## Error handling

Tool errors should be reported within the result object, not as MCP protocol-level errors. This allows the LLM to see and potentially handle the error. When a tool encounters an error:

1.  Set `isError` to `true` in the result
2.  Include error details in the `content` array

Here's an example of proper error handling for tools:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    try {
      // Tool operation
      const result = performOperation();
      return {
        content: [
          {
            type: "text",
            text: `Operation successful: ${result}`
          }
        ]
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error: ${error.message}`
          }
        ]
      };
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python
    try:
        # Tool operation
        result = perform_operation()
        return types.CallToolResult(
            content=[
                types.TextContent(
                    type="text",
                    text=f"Operation successful: {result}"
                )
            ]
        )
    except Exception as error:
        return types.CallToolResult(
            isError=True,
            content=[
                types.TextContent(
                    type="text",
                    text=f"Error: {str(error)}"
                )
            ]
        )
    ```
  </Tab>
</Tabs>

This approach allows the LLM to see that an error occurred and potentially take corrective action or request human intervention.

## Testing tools

A comprehensive testing strategy for MCP tools should cover:

*   **Functional testing**: Verify tools execute correctly with valid inputs and handle invalid inputs appropriately
*   **Integration testing**: Test tool interaction with external systems using both real and mocked dependencies
*   **Security testing**: Validate authentication, authorization, input sanitization, and rate limiting
*   **Performance testing**: Check behavior under load, timeout handling, and resource cleanup
*   **Error handling**: Ensure tools properly report errors through the MCP protocol and clean up resources


# Transports
Source: https://modelcontextprotocol.io/docs/concepts/transports

Learn about MCP's communication mechanisms

Transports in the Model Context Protocol (MCP) provide the foundation for communication between clients and servers. A transport handles the underlying mechanics of how messages are sent and received.

## Message Format

MCP uses [JSON-RPC](https://www.jsonrpc.org/) 2.0 as its wire format. The transport layer is responsible for converting MCP protocol messages into JSON-RPC format for transmission and converting received JSON-RPC messages back into MCP protocol messages.

There are three types of JSON-RPC messages used:

### Requests

```typescript
{
  jsonrpc: "2.0",
  id: number | string,
  method: string,
  params?: object
}
```

### Responses

```typescript
{
  jsonrpc: "2.0",
  id: number | string,
  result?: object,
  error?: {
    code: number,
    message: string,
    data?: unknown
  }
}
```

### Notifications

```typescript
{
  jsonrpc: "2.0",
  method: string,
  params?: object
}
```

## Built-in Transport Types

MCP includes two standard transport implementations:

### Standard Input/Output (stdio)

The stdio transport enables communication through standard input and output streams. This is particularly useful for local integrations and command-line tools.

Use stdio when:

*   Building command-line tools
*   Implementing local integrations
*   Needing simple process communication
*   Working with shell scripts

<Tabs>
  <Tab title="TypeScript (Server)">
    ```typescript
    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {}
    });

    const transport = new StdioServerTransport();
    await server.connect(transport);
    ```
  </Tab>

  <Tab title="TypeScript (Client)">
    ```typescript
    const client = new Client({
      name: "example-client",
      version: "1.0.0"
    }, {
      capabilities: {}
    });

    const transport = new StdioClientTransport({
      command: "./server",
      args: ["--option", "value"]
    });
    await client.connect(transport);
    ```
  </Tab>

  <Tab title="Python (Server)">
    ```python
    app = Server("example-server")

    async with stdio_server() as streams:
        await app.run(
            streams[0],
            streams[1],
            app.create_initialization_options()
        )
    ```
  </Tab>

  <Tab title="Python (Client)">
    ```python
    params = StdioServerParameters(
        command="./server",
        args=["--option", "value"]
    )

    async with stdio_client(params) as streams:
        async with ClientSession(streams[0], streams[1]) as session:
            await session.initialize()
    ```
  </Tab>
</Tabs>

### Server-Sent Events (SSE)

SSE transport enables server-to-client streaming with HTTP POST requests for client-to-server communication.

Use SSE when:

*   Only server-to-client streaming is needed
*   Working with restricted networks
*   Implementing simple updates

<Tabs>
  <Tab title="TypeScript (Server)">
    ```typescript
    import express from "express";

    const app = express();

    const server = new Server({
      name: "example-server",
      version: "1.0.0"
    }, {
      capabilities: {}
    });

    let transport: SSEServerTransport | null = null;

    app.get("/sse", (req, res) => {
      transport = new SSEServerTransport("/messages", res);
      server.connect(transport);
    });

    app.post("/messages", (req, res) => {
      if (transport) {
        transport.handlePostMessage(req, res);
      }
    });

    app.listen(3000);
    ```
  </Tab>

  <Tab title="TypeScript (Client)">
    ```typescript
    const client = new Client({
      name: "example-client",
      version: "1.0.0"
    }, {
      capabilities: {}
    });

    const transport = new SSEClientTransport(
      new URL("http://localhost:3000/sse")
    );
    await client.connect(transport);
    ```
  </Tab>

  <Tab title="Python (Server)">
    ```python
    from mcp.server.sse import SseServerTransport
    from starlette.applications import Starlette
    from starlette.routing import Route

    app = Server("example-server")
    sse = SseServerTransport("/messages")

    async def handle_sse(scope, receive, send):
        async with sse.connect_sse(scope, receive, send) as streams:
            await app.run(streams[0], streams[1], app.create_initialization_options())

    async def handle_messages(scope, receive, send):
        await sse.handle_post_message(scope, receive, send)

    starlette_app = Starlette(
        routes=[
            Route("/sse", endpoint=handle_sse),
            Route("/messages", endpoint=handle_messages, methods=["POST"]),
        ]
    )
    ```
  </Tab>

  <Tab title="Python (Client)">
    ```python
    async with sse_client("http://localhost:8000/sse") as streams:
        async with ClientSession(streams[0], streams[1]) as session:
            await session.initialize()
    ```
  </Tab>
</Tabs>

## Custom Transports

MCP makes it easy to implement custom transports for specific needs. Any transport implementation just needs to conform to the Transport interface:

You can implement custom transports for:

*   Custom network protocols
*   Specialized communication channels
*   Integration with existing systems
*   Performance optimization

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    interface Transport {
      // Start processing messages
      start(): Promise<void>;

      // Send a JSON-RPC message
      send(message: JSONRPCMessage): Promise<void>;

      // Close the connection
      close(): Promise<void>;

      // Callbacks
      onclose?: () => void;
      onerror?: (error: Error) => void;
      onmessage?: (message: JSONRPCMessage) => void;
    }
    ```
  </Tab>

  <Tab title="Python">
    Note that while MCP Servers are often implemented with asyncio, we recommend
    implementing low-level interfaces like transports with `anyio` for wider compatibility.

    ```python
    @contextmanager
    async def create_transport(
        read_stream: MemoryObjectReceiveStream[JSONRPCMessage | Exception],
        write_stream: MemoryObjectSendStream[JSONRPCMessage]
    ):
        """
        Transport interface for MCP.

        Args:
            read_stream: Stream to read incoming messages from
            write_stream: Stream to write outgoing messages to
        """
        async with anyio.create_task_group() as tg:
            try:
                # Start processing messages
                tg.start_soon(lambda: process_messages(read_stream))

                # Send messages
                async with write_stream:
                    yield write_stream

            except Exception as exc:
                # Handle errors
                raise exc
            finally:
                # Clean up
                tg.cancel_scope.cancel()
                await write_stream.aclose()
                await read_stream.aclose()
    ```
  </Tab>
</Tabs>

## Error Handling

Transport implementations should handle various error scenarios:

1.  Connection errors
2.  Message parsing errors
3.  Protocol errors
4.  Network timeouts
5.  Resource cleanup

Example error handling:

<Tabs>
  <Tab title="TypeScript">
    ```typescript
    class ExampleTransport implements Transport {
      async start() {
        try {
          // Connection logic
        } catch (error) {
          this.onerror?.(new Error(`Failed to connect: ${error}`));
          throw error;
        }
      }

      async send(message: JSONRPCMessage) {
        try {
          // Sending logic
        } catch (error) {
          this.onerror?.(new Error(`Failed to send message: ${error}`));
          throw error;
        }
      }
    }
    ```
  </Tab>

  <Tab title="Python">
    Note that while MCP Servers are often implemented with asyncio, we recommend
    implementing low-level interfaces like transports with `anyio` for wider compatibility.

    ```python
    @contextmanager
    async def example_transport(scope: Scope, receive: Receive, send: Send):
        try:
            # Create streams for bidirectional communication
            read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
            write_stream, write_stream_reader = anyio.create_memory_object_stream(0)

            async def message_handler():
                try:
                    async with read_stream_writer:
                        # Message handling logic
                        pass
                except Exception as exc:
                    logger.error(f"Failed to handle message: {exc}")
                    raise exc

            async with anyio.create_task_group() as tg:
                tg.start_soon(message_handler)
                try:
                    # Yield streams for communication
                    yield read_stream, write_stream
                except Exception as exc:
                    logger.error(f"Transport error: {exc}")
                    raise exc
                finally:
                    tg.cancel_scope.cancel()
                    await write_stream.aclose()
                    await read_stream.aclose()
        except Exception as exc:
            logger.error(f"Failed to initialize transport: {exc}")
            raise exc
    ```
  </Tab>
</Tabs>

## Best Practices

When implementing or using MCP transport:

1.  Handle connection lifecycle properly
2.  Implement proper error handling
3.  Clean up resources on connection close
4.  Use appropriate timeouts
5.  Validate messages before sending
6.  Log transport events for debugging
7.  Implement reconnection logic when appropriate
8.  Handle backpressure in message queues
9.  Monitor connection health
10. Implement proper security measures

## Security Considerations

When implementing transport:

### Authentication and Authorization

*   Implement proper authentication mechanisms
*   Validate client credentials
*   Use secure token handling
*   Implement authorization checks

### Data Security

*   Use TLS for network transport
*   Encrypt sensitive data
*   Validate message integrity
*   Implement message size limits
*   Sanitize input data

### Network Security

*   Implement rate limiting
*   Use appropriate timeouts
*   Handle denial of service scenarios
*   Monitor for unusual patterns
*   Implement proper firewall rules

## Debugging Transport

Tips for debugging transport issues:

1.  Enable debug logging
2.  Monitor message flow
3.  Check connection states
4.  Validate message formats
5.  Test error scenarios
6.  Use network analysis tools
7.  Implement health checks
8.  Monitor resource usage
9.  Test edge cases
10. Use proper error tracking


# Debugging
Source: https://modelcontextprotocol.io/docs/tools/debugging

A comprehensive guide to debugging Model Context Protocol (MCP) integrations

Effective debugging is essential when developing MCP servers or integrating them with applications. This guide covers the debugging tools and approaches available in the MCP ecosystem.

<Info>
  This guide is for macOS. Guides for other platforms are coming soon.
</Info>

## Debugging tools overview

MCP provides several tools for debugging at different levels:

1.  **MCP Inspector**
    *   Interactive debugging interface
    *   Direct server testing
    *   See the [Inspector guide](/docs/tools/inspector) for details

2.  **Claude Desktop Developer Tools**
    *   Integration testing
    *   Log collection
    *   Chrome DevTools integration

3.  **Server Logging**
    *   Custom logging implementations
    *   Error tracking
    *   Performance monitoring

## Debugging in Claude Desktop

### Checking server status

The Claude.app interface provides basic server status information:

1.  Click the <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/claude-desktop-mcp-plug-icon.svg" style={{display: 'inline', margin: 0, height: '1.3em'}} /> icon to view:
    *   Connected servers
    *   Available prompts and resources

2.  Click the <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/claude-desktop-mcp-hammer-icon.svg" style={{display: 'inline', margin: 0, height: '1.3em'}} /> icon to view:
    *   Tools made available to the model

### Viewing logs

Review detailed MCP logs from Claude Desktop:

```bash
# Follow logs in real-time
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
```

The logs capture:

*   Server connection events
*   Configuration issues
*   Runtime errors
*   Message exchanges

### Using Chrome DevTools

Access Chrome's developer tools inside Claude Desktop to investigate client-side errors:

1.  Create a `developer_settings.json` file with `allowDevTools` set to true:

```bash
echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json
```

2.  Open DevTools: `Command-Option-Shift-i`

Note: You'll see two DevTools windows:

*   Main content window
*   App title bar window

Use the Console panel to inspect client-side errors.

Use the Network panel to inspect:

*   Message payloads
*   Connection timing

## Common issues

### Working directory

When using MCP servers with Claude Desktop:

*   The working directory for servers launched via `claude_desktop_config.json` may be undefined (like `/` on macOS) since Claude Desktop could be started from anywhere
*   Always use absolute paths in your configuration and `.env` files to ensure reliable operation
*   For testing servers directly via command line, the working directory will be where you run the command

For example in `claude_desktop_config.json`, use:

```json
{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/data"]
}
```

Instead of relative paths like `./data`

### Environment variables

MCP servers inherit only a subset of environment variables automatically, like `USER`, `HOME`, and `PATH`.

To override the default variables or provide your own, you can specify an `env` key in `claude_desktop_config.json`:

```json
{
  "myserver": {
    "command": "mcp-server-myapp",
    "env": {
      "MYAPP_API_KEY": "some_key",
    }
  }
}
```

### Server initialization

Common initialization problems:

1.  **Path Issues**
    *   Incorrect server executable path
    *   Missing required files
    *   Permission problems
    *   Try using an absolute path for `command`

2.  **Configuration Errors**
    *   Invalid JSON syntax
    *   Missing required fields
    *   Type mismatches

3.  **Environment Problems**
    *   Missing environment variables
    *   Incorrect variable values
    *   Permission restrictions

### Connection problems

When servers fail to connect:

1.  Check Claude Desktop logs
2.  Verify server process is running
3.  Test standalone with [Inspector](/docs/tools/inspector)
4.  Verify protocol compatibility

## Implementing logging

### Server-side logging

When building a server that uses the local stdio [transport](/docs/concepts/transports), all messages logged to stderr (standard error) will be captured by the host application (e.g., Claude Desktop) automatically.

<Warning>
  Local MCP servers should not log messages to stdout (standard out), as this will interfere with protocol operation.
</Warning>

For all [transports](/docs/concepts/transports), you can also provide logging to the client by sending a log message notification:

<Tabs>
  <Tab title="Python">
    ```python
    server.request_context.session.send_log_message(
      level="info",
      data="Server started successfully",
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    server.sendLoggingMessage({
      level: "info",
      data: "Server started successfully",
    });
    ```
  </Tab>
</Tabs>

Important events to log:

*   Initialization steps
*   Resource access
*   Tool execution
*   Error conditions
*   Performance metrics

### Client-side logging

In client applications:

1.  Enable debug logging
2.  Monitor network traffic
3.  Track message exchanges
4.  Record error states

## Debugging workflow

### Development cycle

1.  Initial Development
    *   Use [Inspector](/docs/tools/inspector) for basic testing
    *   Implement core functionality
    *   Add logging points

2.  Integration Testing
    *   Test in Claude Desktop
    *   Monitor logs
    *   Check error handling

### Testing changes

To test changes efficiently:

*   **Configuration changes**: Restart Claude Desktop
*   **Server code changes**: Use Command-R to reload
*   **Quick iteration**: Use [Inspector](/docs/tools/inspector) during development

## Best practices

### Logging strategy

1.  **Structured Logging**
    *   Use consistent formats
    *   Include context
    *   Add timestamps
    *   Track request IDs

2.  **Error Handling**
    *   Log stack traces
    *   Include error context
    *   Track error patterns
    *   Monitor recovery

3.  **Performance Tracking**
    *   Log operation timing
    *   Monitor resource usage
    *   Track message sizes
    *   Measure latency

### Security considerations

When debugging:

1.  **Sensitive Data**
    *   Sanitize logs
    *   Protect credentials
    *   Mask personal information

2.  **Access Control**
    *   Verify permissions
    *   Check authentication
    *   Monitor access patterns

## Getting help

When encountering issues:

1.  **First Steps**
    *   Check server logs
    *   Test with [Inspector](/docs/tools/inspector)
    *   Review configuration
    *   Verify environment

2.  **Support Channels**
    *   GitHub issues
    *   GitHub discussions

3.  **Providing Information**
    *   Log excerpts
    *   Configuration files
    *   Steps to reproduce
    *   Environment details

## Next steps

<CardGroup cols={2}>
  <Card title="MCP Inspector" icon="magnifying-glass" href="/docs/tools/inspector">
    Learn to use the MCP Inspector
  </Card>
</CardGroup>


# Inspector
Source: https://modelcontextprotocol.io/docs/tools/inspector

In-depth guide to using the MCP Inspector for testing and debugging Model Context Protocol servers

The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is an interactive developer tool for testing and debugging MCP servers. While the [Debugging Guide](/docs/tools/debugging) covers the Inspector as part of the overall debugging toolkit, this document provides a detailed exploration of the Inspector's features and capabilities.

## Getting started

### Installation and basic usage

The Inspector runs directly through `npx` without requiring installation:

```bash
npx @modelcontextprotocol/inspector <command>
```

```bash
npx @modelcontextprotocol/inspector <command> <arg1> <arg2>
```

#### Inspecting servers from NPM or PyPi

A common way to start server packages from [NPM](https://npmjs.com) or [PyPi](https://pypi.com).

<Tabs>
  <Tab title="NPM package">
    ```bash
    npx -y @modelcontextprotocol/inspector npx <package-name> <args>
    # For example
    npx -y @modelcontextprotocol/inspector npx server-postgres postgres://127.0.0.1/testdb
    ```
  </Tab>

  <Tab title="PyPi package">
    ```bash
    npx @modelcontextprotocol/inspector uvx <package-name> <args>
    # For example
    npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git
    ```
  </Tab>
</Tabs>

#### Inspecting locally developed servers

To inspect servers locally developed or downloaded as a repository, the most common
way is:

<Tabs>
  <Tab title="TypeScript">
    ```bash
    npx @modelcontextprotocol/inspector node path/to/server/index.js args...
    ```
  </Tab>

  <Tab title="Python">
    ```bash
    npx @modelcontextprotocol/inspector \
      uv \
      --directory path/to/server \
      run \
      package-name \
      args...
    ```
  </Tab>
</Tabs>

Please carefully read any attached README for the most accurate instructions.

## Feature overview

<Frame caption="The MCP Inspector interface">
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/mcp-inspector.png" />
</Frame>

The Inspector provides several features for interacting with your MCP server:

### Server connection pane

*   Allows selecting the [transport](/docs/concepts/transports) for connecting to the server
*   For local servers, supports customizing the command-line arguments and environment

### Resources tab

*   Lists all available resources
*   Shows resource metadata (MIME types, descriptions)
*   Allows resource content inspection
*   Supports subscription testing

### Prompts tab

*   Displays available prompt templates
*   Shows prompt arguments and descriptions
*   Enables prompt testing with custom arguments
*   Previews generated messages

### Tools tab

*   Lists available tools
*   Shows tool schemas and descriptions
*   Enables tool testing with custom inputs
*   Displays tool execution results

### Notifications pane

*   Presents all logs recorded from the server
*   Shows notifications received from the server

## Best practices

### Development workflow

1.  Start Development
    *   Launch Inspector with your server
    *   Verify basic connectivity
    *   Check capability negotiation

2.  Iterative testing
    *   Make server changes
    *   Rebuild the server
    *   Reconnect the Inspector
    *   Test affected features
    *   Monitor messages

3.  Test edge cases
    *   Invalid inputs
    *   Missing prompt arguments
    *   Concurrent operations
    *   Verify error handling and error responses

## Next steps

<CardGroup cols={2}>
  <Card title="Inspector Repository" icon="github" href="https://github.com/modelcontextprotocol/inspector">
    Check out the MCP Inspector source code
  </Card>

  <Card title="Debugging Guide" icon="bug" href="/docs/tools/debugging">
    Learn about broader debugging strategies
  </Card>
</CardGroup>


# Example Servers
Source: https://modelcontextprotocol.io/examples

A list of example servers and implementations

This page showcases various Model Context Protocol (MCP) servers that demonstrate the protocol's capabilities and versatility. These servers enable Large Language Models (LLMs) to securely access tools and data sources.

## Reference implementations

These official reference servers demonstrate core MCP features and SDK usage:

### Data and file systems

* **[Filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem)** - Secure file operations with configurable access controls
* **[PostgreSQL](https://github.com/modelcontextprotocol/servers/tree/main/src/postgres)** - Read-only database access with schema inspection capabilities
* **[SQLite](https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite)** - Database interaction and business intelligence features
* **[Google Drive](https://github.com/modelcontextprotocol/servers/tree/main/src/gdrive)** - File access and search capabilities for Google Drive

### Development tools

* **[Git](https://github.com/modelcontextprotocol/servers/tree/main/src/git)** - Tools to read, search, and manipulate Git repositories
* **[GitHub](https://github.com/modelcontextprotocol/servers/tree/main/src/github)** - Repository management, file operations, and GitHub API integration
* **[GitLab](https://github.com/modelcontextprotocol/servers/tree/main/src/gitlab)** - GitLab API integration enabling project management
* **[Sentry](https://github.com/modelcontextprotocol/servers/tree/main/src/sentry)** - Retrieving and analyzing issues from Sentry.io

### Web and browser automation

* **[Brave Search](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search)** - Web and local search using Brave's Search API
* **[Fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch)** - Web content fetching and conversion optimized for LLM usage
* **[Puppeteer](https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer)** - Browser automation and web scraping capabilities

### Productivity and communication

* **[Slack](https://github.com/modelcontextprotocol/servers/tree/main/src/slack)** - Channel management and messaging capabilities
* **[Google Maps](https://github.com/modelcontextprotocol/servers/tree/main/src/google-maps)** - Location services, directions, and place details
* **[Memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory)** - Knowledge graph-based persistent memory system

### AI and specialized tools

* **[EverArt](https://github.com/modelcontextprotocol/servers/tree/main/src/everart)** - AI image generation using various models
* **[Sequential Thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking)** - Dynamic problem-solving through thought sequences
* **[AWS KB Retrieval](https://github.com/modelcontextprotocol/servers/tree/main/src/aws-kb-retrieval-server)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime

## Official integrations

These MCP servers are maintained by companies for their platforms:

* **[Axiom](https://github.com/axiomhq/mcp-server-axiom)** - Query and analyze logs, traces, and event data using natural language
* **[Browserbase](https://github.com/browserbase/mcp-server-browserbase)** - Automate browser interactions in the cloud
* **[Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)** - Deploy and manage resources on the Cloudflare developer platform
* **[E2B](https://github.com/e2b-dev/mcp-server)** - Execute code in secure cloud sandboxes
* **[Neon](https://github.com/neondatabase/mcp-server-neon)** - Interact with the Neon serverless Postgres platform
* **[Obsidian Markdown Notes](https://github.com/calclavia/mcp-obsidian)** - Read and search through Markdown notes in Obsidian vaults
* **[Qdrant](https://github.com/qdrant/mcp-server-qdrant/)** - Implement semantic memory using the Qdrant vector search engine
* **[Raygun](https://github.com/MindscapeHQ/mcp-server-raygun)** - Access crash reporting and monitoring data
* **[Search1API](https://github.com/fatwang2/search1api-mcp)** - Unified API for search, crawling, and sitemaps
* **[Stripe](https://github.com/stripe/agent-toolkit)** - Interact with the Stripe API
* **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interface with the Tinybird serverless ClickHouse platform

## Community highlights

A growing ecosystem of community-developed servers extends MCP's capabilities:

* **[Docker](https://github.com/ckreiling/mcp-server-docker)** - Manage containers, images, volumes, and networks
* **[Kubernetes](https://github.com/Flux159/mcp-server-kubernetes)** - Manage pods, deployments, and services
* **[Linear](https://github.com/jerhadf/linear-mcp-server)** - Project management and issue tracking
* **[Snowflake](https://github.com/datawiz168/mcp-snowflake-service)** - Interact with Snowflake databases
* **[Spotify](https://github.com/varunneal/spotify-mcp)** - Control Spotify playback and manage playlists
* **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Task management integration

> **Note:** Community servers are untested and should be used at your own risk. They are not affiliated with or endorsed by Anthropic.

For a complete list of community servers, visit the [MCP Servers Repository](https://github.com/modelcontextprotocol/servers).

## Getting started

### Using reference servers

TypeScript-based servers can be used directly with `npx`:

```bash
npx -y @modelcontextprotocol/server-memory
```

Python-based servers can be used with `uvx` (recommended) or `pip`:

```bash
# Using uvx
uvx mcp-server-git

# Using pip
pip install mcp-server-git
python -m mcp_server_git
```

### Configuring with Claude

To use an MCP server with Claude, add it to your configuration:

```json
{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"]
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
      }
    }
  }
}
```

## Additional resources

* [MCP Servers Repository](https://github.com/modelcontextprotocol/servers) - Complete collection of reference implementations and community servers
* [Awesome MCP Servers](https://github.com/punkpeye/awesome-mcp-servers) - Curated list of MCP servers
* [MCP CLI](https://github.com/wong2/mcp-cli) - Command-line inspector for testing MCP servers
* [MCP Get](https://mcp-get.com) - Tool for installing and managing MCP servers
* [Supergateway](https://github.com/supercorp-ai/supergateway) - Run MCP stdio servers over SSE

Visit our [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions) to engage with the MCP community.


# Introduction
Source: https://modelcontextprotocol.io/introduction

Get started with the Model Context Protocol (MCP)

<Note>Java SDK released! Check out [what else is new.](/development/updates)</Note>

MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.

## Why MCP?

MCP helps you build agents and complex workflows on top of LLMs. LLMs frequently need to integrate with data and tools, and MCP provides:

* A growing list of pre-built integrations that your LLM can directly plug into
* The flexibility to switch between LLM providers and vendors
* Best practices for securing your data within your infrastructure

### General architecture

At its core, MCP follows a client-server architecture where a host application can connect to multiple servers:

```mermaid
flowchart LR
    subgraph "Your Computer"
        Host["Host with MCP Client\n(Claude, IDEs, Tools)"]
        S1["MCP Server A"]
        S2["MCP Server B"]
        S3["MCP Server C"]
        Host <-->|"MCP Protocol"| S1
        Host <-->|"MCP Protocol"| S2
        Host <-->|"MCP Protocol"| S3
        S1 <--> D1[("Local\nData Source A")]
        S2 <--> D2[("Local\nData Source B")]
    end
    subgraph "Internet"
        S3 <-->|"Web APIs"| D3[("Remote\nService C")]
    end
```

* **MCP Hosts**: Programs like Claude Desktop, IDEs, or AI tools that want to access data through MCP
* **MCP Clients**: Protocol clients that maintain 1:1 connections with servers
* **MCP Servers**: Lightweight programs that each expose specific capabilities through the standardized Model Context Protocol
* **Local Data Sources**: Your computer's files, databases, and services that MCP servers can securely access
* **Remote Services**: External systems available over the internet (e.g., through APIs) that MCP servers can connect to

## Get started

Choose the path that best fits your needs:

#### Quick Starts

<CardGroup cols={2}>
  <Card title="For Server Developers" icon="bolt" href="/quickstart/server">
    Get started building your own server to use in Claude for Desktop and other clients
  </Card>

  <Card title="For Client Developers" icon="bolt" href="/quickstart/client">
    Get started building your own client that can integrate with all MCP servers
  </Card>

  <Card title="For Claude Desktop Users" icon="bolt" href="/quickstart/user">
    Get started using pre-built servers in Claude for Desktop
  </Card>
</CardGroup>

#### Examples

<CardGroup cols={2}>
  <Card title="Example Servers" icon="grid" href="/examples">
    Check out our gallery of official MCP servers and implementations
  </Card>

  <Card title="Example Clients" icon="cubes" href="/clients">
    View the list of clients that support MCP integrations
  </Card>
</CardGroup>

## Tutorials

<CardGroup cols={2}>
  <Card title="Building MCP with LLMs" icon="comments" href="/tutorials/building-mcp-with-llms">
    Learn how to use LLMs like Claude to speed up your MCP development
  </Card>

  <Card title="Debugging Guide" icon="bug" href="/docs/tools/debugging">
    Learn how to effectively debug MCP servers and integrations
  </Card>

  <Card title="MCP Inspector" icon="magnifying-glass" href="/docs/tools/inspector">
    Test and inspect your MCP servers with our interactive debugging tool
  </Card>
</CardGroup>

## Explore MCP

Dive deeper into MCP's core concepts and capabilities:

<CardGroup cols={2}>
  <Card title="Core architecture" icon="sitemap" href="/docs/concepts/architecture">
    Understand how MCP connects clients, servers, and LLMs
  </Card>

  <Card title="Resources" icon="database" href="/docs/concepts/resources">
    Expose data and content from your servers to LLMs
  </Card>

  <Card title="Prompts" icon="message" href="/docs/concepts/prompts">
    Create reusable prompt templates and workflows
  </Card>

  <Card title="Tools" icon="wrench" href="/docs/concepts/tools">
    Enable LLMs to perform actions through your server
  </Card>

  <Card title="Sampling" icon="robot" href="/docs/concepts/sampling">
    Let your servers request completions from LLMs
  </Card>

  <Card title="Transports" icon="network-wired" href="/docs/concepts/transports">
    Learn about MCP's communication mechanism
  </Card>
</CardGroup>

## Contributing

Want to contribute? Check out our [Contributing Guide](/development/contributing) to learn how you can help improve MCP.

## Support and Feedback

Here's how to get help or provide feedback:

* For bug reports and feature requests related to the MCP specification, SDKs, or documentation (open source), please [create a GitHub issue](https://github.com/modelcontextprotocol)
* For discussions or Q\&A about the MCP specification, use the [specification discussions](https://github.com/modelcontextprotocol/specification/discussions)
* For discussions or Q\&A about other MCP open source components, use the [organization discussions](https://github.com/orgs/modelcontextprotocol/discussions)
* For bug reports, feature requests, and questions related to Claude.app and claude.ai's MCP integration, please email [mcp-support@anthropic.com](mailto:mcp-support@anthropic.com)


# For Client Developers
Source: https://modelcontextprotocol.io/quickstart/client

Get started building your own client that can integrate with all MCP servers.

In this tutorial, you'll learn how to build a LLM-powered chatbot client that connects to MCP servers. It helps to have gone through the [Server quickstart](/quickstart/server) that guides you through the basic of building your first server.

<Tabs>
  <Tab title="Python">
    [You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-python)

    ## System Requirements

    Before starting, ensure your system meets these requirements:

    * Mac or Windows computer
    * Latest Python version installed
    * Latest version of `uv` installed

    ## Setting Up Your Environment

    First, create a new Python project with `uv`:

    ```bash
    # Create project directory
    uv init mcp-client
    cd mcp-client

    # Create virtual environment
    uv venv

    # Activate virtual environment
    # On Windows:
    .venv\Scripts\activate
    # On Unix or MacOS:
    source .venv/bin/activate

    # Install required packages
    uv add mcp anthropic python-dotenv

    # Remove boilerplate files
    rm hello.py

    # Create our main file
    touch client.py
    ```

    ## Setting Up Your API Key

    You'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).

    Create a `.env` file to store it:

    ```bash
    # Create .env file
    touch .env
    ```

    Add your key to the `.env` file:

    ```bash
    ANTHROPIC_API_KEY=<your key here>
    ```

    Add `.env` to your `.gitignore`:

    ```bash
    echo ".env" >> .gitignore
    ```

    <Warning>
      Make sure you keep your `ANTHROPIC_API_KEY` secure!
    </Warning>

    ## Creating the Client

    ### Basic Client Structure

    First, let's set up our imports and create the basic client class:

    ```python
    import asyncio
    from typing import Optional
    from contextlib import AsyncExitStack

    from mcp import ClientSession, StdioServerParameters
    from mcp.client.stdio import stdio_client

    from anthropic import Anthropic
    from dotenv import load_dotenv

    load_dotenv()  # load environment variables from .env

    class MCPClient:
        def __init__(self):
            # Initialize session and client objects
            self.session: Optional[ClientSession] = None
            self.exit_stack = AsyncExitStack()
            self.anthropic = Anthropic()
        # methods will go here
    ```

    ### Server Connection Management

    Next, we'll implement the method to connect to an MCP server:

    ```python
    async def connect_to_server(self, server_script_path: str):
        """Connect to an MCP server

        Args:
            server_script_path: Path to the server script (.py or .js)
        """
        is_python = server_script_path.endswith('.py')
        is_js = server_script_path.endswith('.js')
        if not (is_python or is_js):
            raise ValueError("Server script must be a .py or .js file")

        command = "python" if is_python else "node"
        server_params = StdioServerParameters(
            command=command,
            args=[server_script_path],
            env=None
        )

        stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
        self.stdio, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

        await self.session.initialize()

        # List available tools
        response = await self.session.list_tools()
        tools = response.tools
        print("\nConnected to server with tools:", [tool.name for tool in tools])
    ```

    ### Query Processing Logic

    Now let's add the core functionality for processing queries and handling tool calls:

    ```python
    async def process_query(self, query: str) -> str:
        """Process a query using Claude and available tools"""
        messages = [
            {
                "role": "user",
                "content": query
            }
        ]

        response = await self.session.list_tools()
        available_tools = [{
            "name": tool.name,
            "description": tool.description,
            "input_schema": tool.inputSchema
        } for tool in response.tools]

        # Initial Claude API call
        response = self.anthropic.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=1000,
            messages=messages,
            tools=available_tools
        )

        # Process response and handle tool calls
        final_text = []

        assistant_message_content = []
        for content in response.content:
            if content.type == 'text':
                final_text.append(content.text)
                assistant_message_content.append(content)
            elif content.type == 'tool_use':
                tool_name = content.name
                tool_args = content.input

                # Execute tool call
                result = await self.session.call_tool(tool_name, tool_args)
                final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")

                assistant_message_content.append(content)
                messages.append({
                    "role": "assistant",
                    "content": assistant_message_content
                })
                messages.append({
                    "role": "user",
                    "content": [
                        {
                            "type": "tool_result",
                            "tool_use_id": content.id,
                            "content": result.content
                        }
                    ]
                })

                # Get next response from Claude
                response = self.anthropic.messages.create(
                    model="claude-3-5-sonnet-20241022",
                    max_tokens=1000,
                    messages=messages,
                    tools=available_tools
                )

                final_text.append(response.content[0].text)

        return "\n".join(final_text)
    ```

    ### Interactive Chat Interface

    Now we'll add the chat loop and cleanup functionality:

    ```python
    async def chat_loop(self):
        """Run an interactive chat loop"""
        print("\nMCP Client Started!")
        print("Type your queries or 'quit' to exit.")

        while True:
            try:
                query = input("\nQuery: ").strip()

                if query.lower() == 'quit':
                    break

                response = await self.process_query(query)
                print("\n" + response)

            except Exception as e:
                print(f"\nError: {str(e)}")

    async def cleanup(self):
        """Clean up resources"""
        await self.exit_stack.aclose()
    ```

    ### Main Entry Point

    Finally, we'll add the main execution logic:

    ```python
    async def main():
        if len(sys.argv) < 2:
            print("Usage: python client.py <path_to_server_script>")
            sys.exit(1)

        client = MCPClient()
        try:
            await client.connect_to_server(sys.argv[1])
            await client.chat_loop()
        finally:
            await client.cleanup()

    if __name__ == "__main__":
        import sys
        asyncio.run(main())
    ```

    You can find the complete `client.py` file [here.](https://gist.github.com/zckly/f3f28ea731e096e53b39b47bf0a2d4b1)

    ## Key Components Explained

    ### 1. Client Initialization

    * The `MCPClient` class initializes with session management and API clients
    * Uses `AsyncExitStack` for proper resource management
    * Configures the Anthropic client for Claude interactions

    ### 2. Server Connection

    * Supports both Python and Node.js servers
    * Validates server script type
    * Sets up proper communication channels
    * Initializes the session and lists available tools

    ### 3. Query Processing

    * Maintains conversation context
    * Handles Claude's responses and tool calls
    * Manages the message flow between Claude and tools
    * Combines results into a coherent response

    ### 4. Interactive Interface

    * Provides a simple command-line interface
    * Handles user input and displays responses
    * Includes basic error handling
    * Allows graceful exit

    ### 5. Resource Management

    * Proper cleanup of resources
    * Error handling for connection issues
    * Graceful shutdown procedures

    ## Common Customization Points

    1. **Tool Handling**
       * Modify `process_query()` to handle specific tool types
       * Add custom error handling for tool calls
       * Implement tool-specific response formatting

    2. **Response Processing**
       * Customize how tool results are formatted
       * Add response filtering or transformation
       * Implement custom logging

    3. **User Interface**
       * Add a GUI or web interface
       * Implement rich console output
       * Add command history or auto-completion

    ## Running the Client

    To run your client with any MCP server:

    ```bash
    uv run client.py path/to/server.py # python server
    uv run client.py path/to/build/index.js # node server
    ```

    <Note>
      If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `python client.py .../weather/src/weather/server.py`
    </Note>

    The client will:

    1. Connect to the specified server
    2. List available tools
    3. Start an interactive chat session where you can:
       * Enter queries
       * See tool executions
       * Get responses from Claude

    Here's an example of what it should look like if connected to the weather server from the server quickstart:

    <Frame>
      <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/client-claude-cli-python.png" />
    </Frame>

    ## How It Works

    When you submit a query:

    1. The client gets the list of available tools from the server
    2. Your query is sent to Claude along with tool descriptions
    3. Claude decides which tools (if any) to use
    4. The client executes any requested tool calls through the server
    5. Results are sent back to Claude
    6. Claude provides a natural language response
    7. The response is displayed to you

    ## Best practices

    1. **Error Handling**
       * Always wrap tool calls in try-catch blocks
       * Provide meaningful error messages
       * Gracefully handle connection issues

    2. **Resource Management**
       * Use `AsyncExitStack` for proper cleanup
       * Close connections when done
       * Handle server disconnections

    3. **Security**
       * Store API keys securely in `.env`
       * Validate server responses
       * Be cautious with tool permissions

    ## Troubleshooting

    ### Server Path Issues

    * Double-check the path to your server script is correct
    * Use the absolute path if the relative path isn't working
    * For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\) in the path
    * Verify the server file has the correct extension (.py for Python or .js for Node.js)

    Example of correct path usage:

    ```bash
    # Relative path
    uv run client.py ./server/weather.py

    # Absolute path
    uv run client.py /Users/username/projects/mcp-server/weather.py

    # Windows path (either format works)
    uv run client.py C:/projects/mcp-server/weather.py
    uv run client.py C:\\projects\\mcp-server\\weather.py
    ```

    ### Response Timing

    * The first response might take up to 30 seconds to return
    * This is normal and happens while:
      * The server initializes
      * Claude processes the query
      * Tools are being executed
    * Subsequent responses are typically faster
    * Don't interrupt the process during this initial waiting period

    ### Common Error Messages

    If you see:

    * `FileNotFoundError`: Check your server path
    * `Connection refused`: Ensure the server is running and the path is correct
    * `Tool execution failed`: Verify the tool's required environment variables are set
    * `Timeout error`: Consider increasing the timeout in your client configuration
  </Tab>

  <Tab title="Node">
    [You can find the complete code for this tutorial here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/mcp-client-typescript)

    ## System Requirements

    Before starting, ensure your system meets these requirements:

    * Mac or Windows computer
    * Node.js 16 or higher installed
    * Latest version of `npm` installed
    * Anthropic API key (Claude)

    ## Setting Up Your Environment

    First, let's create and set up our project:

    <CodeGroup>
      ```bash MacOS/Linux
      # Create project directory
      mkdir mcp-client-typescript
      cd mcp-client-typescript

      # Initialize npm project
      npm init -y

      # Install dependencies
      npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv

      # Install dev dependencies
      npm install -D @types/node typescript

      # Create source file
      touch index.ts
      ```

      ```powershell Windows
      # Create project directory
      md mcp-client-typescript
      cd mcp-client-typescript

      # Initialize npm project
      npm init -y

      # Install dependencies
      npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv

      # Install dev dependencies
      npm install -D @types/node typescript

      # Create source file
      new-item index.ts
      ```
    </CodeGroup>

    Update your `package.json` to set `type: "module"` and a build script:

    ```json package.json
    {
      "type": "module",
      "scripts": {
        "build": "tsc && chmod 755 build/index.js"
      }
    }
    ```

    Create a `tsconfig.json` in the root of your project:

    ```json tsconfig.json
    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./build",
        "rootDir": "./",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["index.ts"],
      "exclude": ["node_modules"]
    }
    ```

    ## Setting Up Your API Key

    You'll need an Anthropic API key from the [Anthropic Console](https://console.anthropic.com/settings/keys).

    Create a `.env` file to store it:

    ```bash
    echo "ANTHROPIC_API_KEY=<your key here>" > .env
    ```

    Add `.env` to your `.gitignore`:

    ```bash
    echo ".env" >> .gitignore
    ```

    <Warning>
      Make sure you keep your `ANTHROPIC_API_KEY` secure!
    </Warning>

    ## Creating the Client

    ### Basic Client Structure

    First, let's set up our imports and create the basic client class in `index.ts`:

    ```typescript
    import { Anthropic } from "@anthropic-ai/sdk";
    import {
      MessageParam,
      Tool,
    } from "@anthropic-ai/sdk/resources/messages/messages.mjs";
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
    import readline from "readline/promises";
    import dotenv from "dotenv";

    dotenv.config();

    const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
    if (!ANTHROPIC_API_KEY) {
      throw new Error("ANTHROPIC_API_KEY is not set");
    }

    class MCPClient {
      private mcp: Client;
      private anthropic: Anthropic;
      private transport: StdioClientTransport | null = null;
      private tools: Tool[] = [];

      constructor() {
        this.anthropic = new Anthropic({
          apiKey: ANTHROPIC_API_KEY,
        });
        this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" });
      }
      // methods will go here
    }
    ```

    ### Server Connection Management

    Next, we'll implement the method to connect to an MCP server:

    ```typescript
    async connectToServer(serverScriptPath: string) {
      try {
        const isJs = serverScriptPath.endsWith(".js");
        const isPy = serverScriptPath.endsWith(".py");
        if (!isJs && !isPy) {
          throw new Error("Server script must be a .js or .py file");
        }
        const command = isPy
          ? process.platform === "win32"
            ? "python"
            : "python3"
          : process.execPath;
        
        this.transport = new StdioClientTransport({
          command,
          args: [serverScriptPath],
        });
        this.mcp.connect(this.transport);
        
        const toolsResult = await this.mcp.listTools();
        this.tools = toolsResult.tools.map((tool) => {
          return {
            name: tool.name,
            description: tool.description,
            input_schema: tool.inputSchema,
          };
        });
        console.log(
          "Connected to server with tools:",
          this.tools.map(({ name }) => name)
        );
      } catch (e) {
        console.log("Failed to connect to MCP server: ", e);
        throw e;
      }
    }
    ```

    ### Query Processing Logic

    Now let's add the core functionality for processing queries and handling tool calls:

    ```typescript
    async processQuery(query: string) {
      const messages: MessageParam[] = [
        {
          role: "user",
          content: query,
        },
      ];

      const response = await this.anthropic.messages.create({
        model: "claude-3-5-sonnet-20241022",
        max_tokens: 1000,
        messages,
        tools: this.tools,
      });

      const finalText = [];
      const toolResults = [];

      for (const content of response.content) {
        if (content.type === "text") {
          finalText.push(content.text);
        } else if (content.type === "tool_use") {
          const toolName = content.name;
          const toolArgs = content.input as { [x: string]: unknown } | undefined;

          const result = await this.mcp.callTool({
            name: toolName,
            arguments: toolArgs,
          });
          toolResults.push(result);
          finalText.push(
            `[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`
          );

          messages.push({
            role: "user",
            content: result.content as string,
          });

          const response = await this.anthropic.messages.create({
            model: "claude-3-5-sonnet-20241022",
            max_tokens: 1000,
            messages,
          });

          finalText.push(
            response.content[0].type === "text" ? response.content[0].text : ""
          );
        }
      }

      return finalText.join("\n");
    }
    ```

    ### Interactive Chat Interface

    Now we'll add the chat loop and cleanup functionality:

    ```typescript
    async chatLoop() {
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });

      try {
        console.log("\nMCP Client Started!");
        console.log("Type your queries or 'quit' to exit.");

        while (true) {
          const message = await rl.question("\nQuery: ");
          if (message.toLowerCase() === "quit") {
            break;
          }
          const response = await this.processQuery(message);
          console.log("\n" + response);
        }
      } finally {
        rl.close();
      }
    }

    async cleanup() {
      await this.mcp.close();
    }
    ```

    ### Main Entry Point

    Finally, we'll add the main execution logic:

    ```typescript
    async function main() {
      if (process.argv.length < 3) {
        console.log("Usage: node index.ts <path_to_server_script>");
        return;
      }
      const mcpClient = new MCPClient();
      try {
        await mcpClient.connectToServer(process.argv[2]);
        await mcpClient.chatLoop();
      } finally {
        await mcpClient.cleanup();
        process.exit(0);
      }
    }

    main();
    ```

    ## Running the Client

    To run your client with any MCP server:

    ```bash
    # Build TypeScript
    npm run build

    # Run the client
    node build/index.js path/to/server.py # python server
    node build/index.js path/to/build/index.js # node server
    ```

    <Note>
      If you're continuing the weather tutorial from the server quickstart, your command might look something like this: `node build/index.js .../quickstart-resources/weather-server-typescript/build/index.js`
    </Note>

    **The client will:**

    1. Connect to the specified server
    2. List available tools
    3. Start an interactive chat session where you can:
       * Enter queries
       * See tool executions
       * Get responses from Claude

    ## How It Works

    When you submit a query:

    1. The client gets the list of available tools from the server
    2. Your query is sent to Claude along with tool descriptions
    3. Claude decides which tools (if any) to use
    4. The client executes any requested tool calls through the server
    5. Results are sent back to Claude
    6. Claude provides a natural language response
    7. The response is displayed to you

    ## Best practices

    1. **Error Handling**
       * Use TypeScript's type system for better error detection
       * Wrap tool calls in try-catch blocks
       * Provide meaningful error messages
       * Gracefully handle connection issues

    2. **Security**
       * Store API keys securely in `.env`
       * Validate server responses
       * Be cautious with tool permissions

    ## Troubleshooting

    ### Server Path Issues

    * Double-check the path to your server script is correct
    * Use the absolute path if the relative path isn't working
    * For Windows users, make sure to use forward slashes (/) or escaped backslashes (\\) in the path
    * Verify the server file has the correct extension (.js for Node.js or .py for Python)

    Example of correct path usage:

    ```bash
    # Relative path
    node build/index.js ./server/build/index.js

    # Absolute path
    node build/index.js /Users/username/projects/mcp-server/build/index.js

    # Windows path (either format works)
    node build/index.js C:/projects/mcp-server/build/index.js
    node build/index.js C:\\projects\\mcp-server\\build\\index.js
    ```

    ### Response Timing

    * The first response might take up to 30 seconds to return
    * This is normal and happens while:
      * The server initializes
      * Claude processes the query
      * Tools are being executed
    * Subsequent responses are typically faster
    * Don't interrupt the process during this initial waiting period

    ### Common Error Messages

    If you see:

    * `Error: Cannot find module`: Check your build folder and ensure TypeScript compilation succeeded
    * `Connection refused`: Ensure the server is running and the path is correct
    * `Tool execution failed`: Verify the tool's required environment variables are set
    * `ANTHROPIC_API_KEY is not set`: Check your .env file and environment variables
    * `TypeError`: Ensure you're using the correct types for tool arguments
  </Tab>

  <Tab title="Java">
    <Note>
      This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters.
      To learn how to create sync and async MCP Clients manually, consult the [Java SDK Client](/sdk/java/mcp-client) documentation
    </Note>

    This example demonstrates how to build an interactive chatbot that combines Spring AI's Model Context Protocol (MCP) with the [Brave Search MCP Server](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search). The application creates a conversational interface powered by Anthropic's Claude AI model that can perform internet searches through Brave Search, enabling natural language interactions with real-time web data.
    [You can find the complete code for this tutorial here.](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/web-search/brave-chatbot)

    ## System Requirements

    Before starting, ensure your system meets these requirements:

    * Java 17 or higher
    * Maven 3.6+
    * npx package manager
    * Anthropic API key (Claude)
    * Brave Search API key

    ## Setting Up Your Environment

    1. Install npx (Node Package eXecute):
       First, make sure to install [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
       and then run:
       ```bash
       npm install -g npx
       ```

    2. Clone the repository:
       ```bash
       git clone https://github.com/spring-projects/spring-ai-examples.git
       cd model-context-protocol/brave-chatbot
       ```

    3. Set up your API keys:
       ```bash
       export ANTHROPIC_API_KEY='your-anthropic-api-key-here'
       export BRAVE_API_KEY='your-brave-api-key-here'
       ```

    4. Build the application:
       ```bash
       ./mvnw clean install
       ```

    5. Run the application using Maven:
       ```bash
       ./mvnw spring-boot:run
       ```

    <Warning>
      Make sure you keep your `ANTHROPIC_API_KEY` and `BRAVE_API_KEY` keys secure!
    </Warning>

    ## How it Works

    The application integrates Spring AI with the Brave Search MCP server through several components:

    ### MCP Client Configuration

    1. Required dependencies in pom.xml:

    ```xml
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
    </dependency>
    ```

    2. Application properties (application.yml):

    ```yml
    spring:
      ai:
        mcp:
          client:
            enabled: true
            name: brave-search-client
            version: 1.0.0
            type: SYNC
            request-timeout: 20s
            stdio:
              root-change-notification: true
              servers-configuration: classpath:/mcp-servers-config.json
        anthropic:
          api-key: ${ANTHROPIC_API_KEY}
    ```

    This activates the `spring-ai-mcp-client-spring-boot-starter` to create one or more `McpClient`s based on the provided server configuration.

    3. MCP Server Configuration (`mcp-servers-config.json`):

    ```json
    {
      "mcpServers": {
        "brave-search": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-brave-search"
          ],
          "env": {
            "BRAVE_API_KEY": "<PUT YOUR BRAVE API KEY>"
          }
        }
      }
    }
    ```

    ### Chat Implementation

    The chatbot is implemented using Spring AI's ChatClient with MCP tool integration:

    ```java
    var chatClient = chatClientBuilder
        .defaultSystem("You are useful assistant, expert in AI and Java.")
        .defaultTools((Object[]) mcpToolAdapter.toolCallbacks())
        .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
        .build();
    ```

    Key features:

    * Uses Claude AI model for natural language understanding
    * Integrates Brave Search through MCP for real-time web search capabilities
    * Maintains conversation memory using InMemoryChatMemory
    * Runs as an interactive command-line application

    ### Build and run

    ```bash
    ./mvnw clean install
    java -jar ./target/ai-mcp-brave-chatbot-0.0.1-SNAPSHOT.jar
    ```

    or

    ```bash
    ./mvnw spring-boot:run
    ```

    The application will start an interactive chat session where you can ask questions. The chatbot will use Brave Search when it needs to find information from the internet to answer your queries.

    The chatbot can:

    * Answer questions using its built-in knowledge
    * Perform web searches when needed using Brave Search
    * Remember context from previous messages in the conversation
    * Combine information from multiple sources to provide comprehensive answers

    ### Advanced Configuration

    The MCP client supports additional configuration options:

    * Client customization through `McpSyncClientCustomizer` or `McpAsyncClientCustomizer`
    * Multiple clients with multiple transport types: `STDIO` and `SSE` (Server-Sent Events)
    * Integration with Spring AI's tool execution framework
    * Automatic client initialization and lifecycle management

    For WebFlux-based applications, you can use the WebFlux starter instead:

    ```xml
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
    </dependency>
    ```

    This provides similar functionality but uses a WebFlux-based SSE transport implementation, recommended for production deployments.
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Example servers" icon="grid" href="/examples">
    Check out our gallery of official MCP servers and implementations
  </Card>

  <Card title="Clients" icon="cubes" href="/clients">
    View the list of clients that support MCP integrations
  </Card>

  <Card title="Building MCP with LLMs" icon="comments" href="/tutorials/building-mcp-with-llms">
    Learn how to use LLMs like Claude to speed up your MCP development
  </Card>

  <Card title="Core architecture" icon="sitemap" href="/docs/concepts/architecture">
    Understand how MCP connects clients, servers, and LLMs
  </Card>
</CardGroup>


# For Server Developers
Source: https://modelcontextprotocol.io/quickstart/server

Get started building your own server to use in Claude for Desktop and other clients.

In this tutorial, we'll build a simple MCP weather server and connect it to a host, Claude for Desktop. We'll start with a basic setup, and then progress to more complex use cases.

### What we'll be building

Many LLMs (including Claude) do not currently have the ability to fetch the forecast and severe weather alerts. Let's use MCP to solve that!

We'll build a server that exposes two tools: `get-alerts` and `get-forecast`. Then we'll connect the server to an MCP host (in this case, Claude for Desktop):

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/weather-alerts.png" />
</Frame>

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/current-weather.png" />
</Frame>

<Note>
  Servers can connect to any client. We've chosen Claude for Desktop here for simplicity, but we also have guides on [building your own client](/quickstart/client) as well as a [list of other clients here](/clients).
</Note>

<Accordion title="Why Claude for Desktop and not Claude.ai?">
  Because servers are locally run, MCP currently only supports desktop hosts. Remote hosts are in active development.
</Accordion>

### Core MCP Concepts

MCP servers can provide three main types of capabilities:

1. **Resources**: File-like data that can be read by clients (like API responses or file contents)
2. **Tools**: Functions that can be called by the LLM (with user approval)
3. **Prompts**: Pre-written templates that help users accomplish specific tasks

This tutorial will primarily focus on tools.

<Tabs>
  <Tab title="Python">
    Let's get started with building our weather server! [You can find the complete code for what we'll be building here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-python)

    ### Prerequisite knowledge

    This quickstart assumes you have familiarity with:

    * Python
    * LLMs like Claude

    ### System requirements

    * Python 3.10 or higher installed.
    * You must use the Python MCP SDK 1.2.0 or higher.

    ### Set up your environment

    First, let's install `uv` and set up our Python project and environment:

    <CodeGroup>
      ```bash MacOS/Linux
      curl -LsSf https://astral.sh/uv/install.sh | sh
      ```

      ```powershell Windows
      powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
      ```
    </CodeGroup>

    Make sure to restart your terminal afterwards to ensure that the `uv` command gets picked up.

    Now, let's create and set up our project:

    <CodeGroup>
      ```bash MacOS/Linux
      # Create a new directory for our project
      uv init weather
      cd weather

      # Create virtual environment and activate it
      uv venv
      source .venv/bin/activate

      # Install dependencies
      uv add "mcp[cli]" httpx

      # Create our server file
      touch weather.py
      ```

      ```powershell Windows
      # Create a new directory for our project
      uv init weather
      cd weather

      # Create virtual environment and activate it
      uv venv
      .venv\Scripts\activate

      # Install dependencies
      uv add mcp[cli] httpx

      # Create our server file
      new-item weather.py
      ```
    </CodeGroup>

    Now let's dive into building your server.

    ## Building your server

    ### Importing packages and setting up the instance

    Add these to the top of your `weather.py`:

    ```python
    from typing import Any
    import httpx
    from mcp.server.fastmcp import FastMCP

    # Initialize FastMCP server
    mcp = FastMCP("weather")

    # Constants
    NWS_API_BASE = "https://api.weather.gov"
    USER_AGENT = "weather-app/1.0"
    ```

    The FastMCP class uses Python type hints and docstrings to automatically generate tool definitions, making it easy to create and maintain MCP tools.

    ### Helper functions

    Next, let's add our helper functions for querying and formatting the data from the National Weather Service API:

    ```python
    async def make_nws_request(url: str) -> dict[str, Any] | None:
        """Make a request to the NWS API with proper error handling."""
        headers = {
            "User-Agent": USER_AGENT,
            "Accept": "application/geo+json"
        }
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(url, headers=headers, timeout=30.0)
                response.raise_for_status()
                return response.json()
            except Exception:
                return None

    def format_alert(feature: dict) -> str:
        """Format an alert feature into a readable string."""
        props = feature["properties"]
        return f"""
    Event: {props.get('event', 'Unknown')}
    Area: {props.get('areaDesc', 'Unknown')}
    Severity: {props.get('severity', 'Unknown')}
    Description: {props.get('description', 'No description available')}
    Instructions: {props.get('instruction', 'No specific instructions provided')}
    """
    ```

    ### Implementing tool execution

    The tool execution handler is responsible for actually executing the logic of each tool. Let's add it:

    ```python
    @mcp.tool()
    async def get_alerts(state: str) -> str:
        """Get weather alerts for a US state.

        Args:
            state: Two-letter US state code (e.g. CA, NY)
        """
        url = f"{NWS_API_BASE}/alerts/active/area/{state}"
        data = await make_nws_request(url)

        if not data or "features" not in data:
            return "Unable to fetch alerts or no alerts found."

        if not data["features"]:
            return "No active alerts for this state."

        alerts = [format_alert(feature) for feature in data["features"]]
        return "\n---\n".join(alerts)

    @mcp.tool()
    async def get_forecast(latitude: float, longitude: float) -> str:
        """Get weather forecast for a location.

        Args:
            latitude: Latitude of the location
            longitude: Longitude of the location
        """
        # First get the forecast grid endpoint
        points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
        points_data = await make_nws_request(points_url)

        if not points_data:
            return "Unable to fetch forecast data for this location."

        # Get the forecast URL from the points response
        forecast_url = points_data["properties"]["forecast"]
        forecast_data = await make_nws_request(forecast_url)

        if not forecast_data:
            return "Unable to fetch detailed forecast."

        # Format the periods into a readable forecast
        periods = forecast_data["properties"]["periods"]
        forecasts = []
        for period in periods[:5]:  # Only show next 5 periods
            forecast = f"""
    {period['name']}:
    Temperature: {period['temperature']}°{period['temperatureUnit']}
    Wind: {period['windSpeed']} {period['windDirection']}
    Forecast: {period['detailedForecast']}
    """
            forecasts.append(forecast)

        return "\n---\n".join(forecasts)
    ```

    ### Running the server

    Finally, let's initialize and run the server:

    ```python
    if __name__ == "__main__":
        # Initialize and run the server
        mcp.run(transport='stdio')
    ```

    Your server is complete! Run `uv run weather.py` to confirm that everything's working.

    Let's now test your server from an existing MCP host, Claude for Desktop.

    ## Testing your server with Claude for Desktop

    <Note>
      Claude for Desktop is not yet available on Linux. Linux users can proceed to the [Building a client](/quickstart/client) tutorial to build an MCP client that connects to the server we just built.
    </Note>

    First, make sure you have Claude for Desktop installed. [You can install the latest version
    here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.**

    We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.

    For example, if you have [VS Code](https://code.visualstudio.com/) installed:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash
        code ~/Library/Application\ Support/Claude/claude_desktop_config.json
        ```
      </Tab>

      <Tab title="Windows">
        ```powershell
        code $env:AppData\Claude\claude_desktop_config.json
        ```
      </Tab>
    </Tabs>

    You'll then add your servers in the `mcpServers` key. The MCP UI elements will only show up in Claude for Desktop if at least one server is properly configured.

    In this case, we'll add our single weather server like so:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```json Python
        {
            "mcpServers": {
                "weather": {
                    "command": "uv",
                    "args": [
                        "--directory",
                        "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                        "run",
                        "weather.py"
                    ]
                }
            }
        }
        ```
      </Tab>

      <Tab title="Windows">
        ```json Python
        {
            "mcpServers": {
                "weather": {
                    "command": "uv",
                    "args": [
                        "--directory",
                        "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather",
                        "run",
                        "weather.py"
                    ]
                }
            }
        }
        ```
      </Tab>
    </Tabs>

    <Warning>
      You may need to put the full path to the `uv` executable in the `command` field. You can get this by running `which uv` on MacOS/Linux or `where uv` on Windows.
    </Warning>

    <Note>
      Make sure you pass in the absolute path to your server.
    </Note>

    This tells Claude for Desktop:

    1. There's an MCP server named "weather"
    2. To launch it by running `uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py`

    Save the file, and restart **Claude for Desktop**.
  </Tab>

  <Tab title="Node">
    Let's get started with building our weather server! [You can find the complete code for what we'll be building here.](https://github.com/modelcontextprotocol/quickstart-resources/tree/main/weather-server-typescript)

    ### Prerequisite knowledge

    This quickstart assumes you have familiarity with:

    * TypeScript
    * LLMs like Claude

    ### System requirements

    For TypeScript, make sure you have the latest version of Node installed.

    ### Set up your environment

    First, let's install Node.js and npm if you haven't already. You can download them from [nodejs.org](https://nodejs.org/).
    Verify your Node.js installation:

    ```bash
    node --version
    npm --version
    ```

    For this tutorial, you'll need Node.js version 16 or higher.

    Now, let's create and set up our project:

    <CodeGroup>
      ```bash MacOS/Linux
      # Create a new directory for our project
      mkdir weather
      cd weather

      # Initialize a new npm project
      npm init -y

      # Install dependencies
      npm install @modelcontextprotocol/sdk zod
      npm install -D @types/node typescript

      # Create our files
      mkdir src
      touch src/index.ts
      ```

      ```powershell Windows
      # Create a new directory for our project
      md weather
      cd weather

      # Initialize a new npm project
      npm init -y

      # Install dependencies
      npm install @modelcontextprotocol/sdk zod
      npm install -D @types/node typescript

      # Create our files
      md src
      new-item src\index.ts
      ```
    </CodeGroup>

    Update your package.json to add type: "module" and a build script:

    ```json package.json
    {
      "type": "module",
      "bin": {
        "weather": "./build/index.js"
      },
      "scripts": {
        "build": "tsc && chmod 755 build/index.js"
      },
      "files": [
        "build"
      ],
    }
    ```

    Create a `tsconfig.json` in the root of your project:

    ```json tsconfig.json
    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }
    ```

    Now let's dive into building your server.

    ## Building your server

    ### Importing packages and setting up the instance

    Add these to the top of your `src/index.ts`:

    ```typescript
    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import { z } from "zod";

    const NWS_API_BASE = "https://api.weather.gov";
    const USER_AGENT = "weather-app/1.0";

    // Create server instance
    const server = new McpServer({
      name: "weather",
      version: "1.0.0",
    });
    ```

    ### Helper functions

    Next, let's add our helper functions for querying and formatting the data from the National Weather Service API:

    ```typescript
    // Helper function for making NWS API requests
    async function makeNWSRequest<T>(url: string): Promise<T | null> {
      const headers = {
        "User-Agent": USER_AGENT,
        Accept: "application/geo+json",
      };

      try {
        const response = await fetch(url, { headers });
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return (await response.json()) as T;
      } catch (error) {
        console.error("Error making NWS request:", error);
        return null;
      }
    }

    interface AlertFeature {
      properties: {
        event?: string;
        areaDesc?: string;
        severity?: string;
        status?: string;
        headline?: string;
      };
    }

    // Format alert data
    function formatAlert(feature: AlertFeature): string {
      const props = feature.properties;
      return [
        `Event: ${props.event || "Unknown"}`,
        `Area: ${props.areaDesc || "Unknown"}`,
        `Severity: ${props.severity || "Unknown"}`,
        `Status: ${props.status || "Unknown"}`,
        `Headline: ${props.headline || "No headline"}`,
        "---",
      ].join("\n");
    }

    interface ForecastPeriod {
      name?: string;
      temperature?: number;
      temperatureUnit?: string;
      windSpeed?: string;
      windDirection?: string;
      shortForecast?: string;
    }

    interface AlertsResponse {
      features: AlertFeature[];
    }

    interface PointsResponse {
      properties: {
        forecast?: string;
      };
    }

    interface ForecastResponse {
      properties: {
        periods: ForecastPeriod[];
      };
    }
    ```

    ### Implementing tool execution

    The tool execution handler is responsible for actually executing the logic of each tool. Let's add it:

    ```typescript
    // Register weather tools
    server.tool(
      "get-alerts",
      "Get weather alerts for a state",
      {
        state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
      },
      async ({ state }) => {
        const stateCode = state.toUpperCase();
        const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
        const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);

        if (!alertsData) {
          return {
            content: [
              {
                type: "text",
                text: "Failed to retrieve alerts data",
              },
            ],
          };
        }

        const features = alertsData.features || [];
        if (features.length === 0) {
          return {
            content: [
              {
                type: "text",
                text: `No active alerts for ${stateCode}`,
              },
            ],
          };
        }

        const formattedAlerts = features.map(formatAlert);
        const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;

        return {
          content: [
            {
              type: "text",
              text: alertsText,
            },
          ],
        };
      },
    );

    server.tool(
      "get-forecast",
      "Get weather forecast for a location",
      {
        latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
        longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
      },
      async ({ latitude, longitude }) => {
        // Get grid point data
        const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
        const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);

        if (!pointsData) {
          return {
            content: [
              {
                type: "text",
                text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
              },
            ],
          };
        }

        const forecastUrl = pointsData.properties?.forecast;
        if (!forecastUrl) {
          return {
            content: [
              {
                type: "text",
                text: "Failed to get forecast URL from grid point data",
              },
            ],
          };
        }

        // Get forecast data
        const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
        if (!forecastData) {
          return {
            content: [
              {
                type: "text",
                text: "Failed to retrieve forecast data",
              },
            ],
          };
        }

        const periods = forecastData.properties?.periods || [];
        if (periods.length === 0) {
          return {
            content: [
              {
                type: "text",
                text: "No forecast periods available",
              },
            ],
          };
        }

        // Format forecast periods
        const formattedForecast = periods.map((period: ForecastPeriod) =>
          [
            `${period.name || "Unknown"}:`,
            `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
            `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
            `${period.shortForecast || "No forecast available"}`,
            "---",
          ].join("\n"),
        );

        const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;

        return {
          content: [
            {
              type: "text",
              text: forecastText,
            },
          ],
        };
      },
    );
    ```

    ### Running the server

    Finally, implement the main function to run the server:

    ```typescript
    async function main() {
      const transport = new StdioServerTransport();
      await server.connect(transport);
      console.error("Weather MCP Server running on stdio");
    }

    main().catch((error) => {
      console.error("Fatal error in main():", error);
      process.exit(1);
    });
    ```

    Make sure to run `npm run build` to build your server! This is a very important step in getting your server to connect.

    Let's now test your server from an existing MCP host, Claude for Desktop.

    ## Testing your server with Claude for Desktop

    <Note>
      Claude for Desktop is not yet available on Linux. Linux users can proceed to the [Building a client](/quickstart/client) tutorial to build an MCP client that connects to the server we just built.
    </Note>

    First, make sure you have Claude for Desktop installed. [You can install the latest version
    here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.**

    We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.

    For example, if you have [VS Code](https://code.visualstudio.com/) installed:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash
        code ~/Library/Application\ Support/Claude/claude_desktop_config.json
        ```
      </Tab>

      <Tab title="Windows">
        ```powershell
        code $env:AppData\Claude\claude_desktop_config.json
        ```
      </Tab>
    </Tabs>

    You'll then add your servers in the `mcpServers` key. The MCP UI elements will only show up in Claude for Desktop if at least one server is properly configured.

    In this case, we'll add our single weather server like so:

    <Tabs>
      <Tab title="MacOS/Linux">
        <CodeGroup>
          ```json Node
          {
              "mcpServers": {
                  "weather": {
                      "command": "node",
                      "args": [
                          "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js"
                      ]
                  }
              }
          }
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Windows">
        <CodeGroup>
          ```json Node
          {
              "mcpServers": {
                  "weather": {
                      "command": "node",
                      "args": [
                          "C:\\PATH\\TO\\PARENT\\FOLDER\\weather\\build\\index.js"
                      ]
                  }
              }
          }
          ```
        </CodeGroup>
      </Tab>
    </Tabs>

    This tells Claude for Desktop:

    1. There's an MCP server named "weather"
    2. Launch it by running `node /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js`

    Save the file, and restart **Claude for Desktop**.
  </Tab>

  <Tab title="Java">
    <Note>
      This is a quickstart demo based on Spring AI MCP auto-configuration and boot starters.
      To learn how to create sync and async MCP Servers, manually, consult the [Java SDK Server](/sdk/java/mcp-server) documentation.
    </Note>

    Let's get started with building our weather server!
    [You can find the complete code for what we'll be building here.](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-stdio-server)

    For more information, see the [MCP Server Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html) reference documentation.
    For manual MCP Server implementation, refer to the [MCP Server Java SDK documentation](/sdk/java/mcp-server).

    ### System requirements

    * Java 17 or higher installed.
    * [Spring Boot 3.3.x](https://docs.spring.io/spring-boot/installing.html) or higher

    ### Set up your environment

    Use the [Spring Initizer](https://start.spring.io/) to bootstrat the project.

    You will need to add the following dependencies:

    <Tabs>
      <Tab title="Maven">
        ```xml
        <dependencies>
              <dependency>
                  <groupId>org.springframework.ai</groupId>
                  <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
              </dependency>

              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-web</artifactId>
              </dependency>
        </dependencies>
        ```
      </Tab>

      <Tab title="Gradle">
        ```groovy
        dependencies {
          implementation platform("org.springframework.ai:spring-ai-mcp-server-spring-boot-starter")
          implementation platform("org.springframework:spring-web")   
        }
        ```
      </Tab>
    </Tabs>

    Then configure your application by setting the applicaiton properties:

    <CodeGroup>
      ```bash application.properties
      spring.main.bannerMode=off
      logging.pattern.console=
      ```

      ```yaml application.yml
      logging:
        pattern:
          console:
      spring:
        main:
          banner-mode: off
      ```
    </CodeGroup>

    The [Server Configuration Properties](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html#_configuration_properties) documents all available properties.

    Now let's dive into building your server.

    ## Building your server

    ### Weather Service

    Let's implement a [WeatheService.java](https://github.com/spring-projects/spring-ai-examples/blob/main/model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java) that uses a REST client to query the data from the National Weather Service API:

    ```java
    @Service
    public class WeatherService {

    	private final RestClient restClient;

    	public WeatherService() {
    		this.restClient = RestClient.builder()
    			.baseUrl("https://api.weather.gov")
    			.defaultHeader("Accept", "application/geo+json")
    			.defaultHeader("User-Agent", "WeatherApiClient/1.0 (your@email.com)")
    			.build();
    	}

      @Tool(description = "Get weather forecast for a specific latitude/longitude")
      public String getWeatherForecastByLocation(
          double latitude,   // Latitude coordinate
          double longitude   // Longitude coordinate
      ) {
          // Returns detailed forecast including:
          // - Temperature and unit
          // - Wind speed and direction
          // - Detailed forecast description
      }
    	
      @Tool(description = "Get weather alerts for a US state")
      public String getAlerts(
          @ToolParam(description = "Two-letter US state code (e.g. CA, NY") String state)
      ) {
          // Returns active alerts including:
          // - Event type
          // - Affected area
          // - Severity
          // - Description
          // - Safety instructions
      }

      // ......
    }
    ```

    The `@Service` annotation with auto-register the service in your applicaiton context.
    The Spring AI `@Tool` annotation, making it easy to create and maintain MCP tools.

    The auto-configuration will automatically register these tools with the MCP server.

    ### Create your Boot Applicaiton

    ```java
    @SpringBootApplication
    public class McpServerApplication {

    	public static void main(String[] args) {
    		SpringApplication.run(McpServerApplication.class, args);
    	}

    	@Bean
    	public ToolCallbackProvider weatherTools(WeatherService weatherService) {
    		return  MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
    	}
    }
    ```

    Uses the the `MethodToolCallbackProvider` utils to convert the `@Tools` into actionalble callbackes used by the MCP server.

    ### Running the server

    Finally, let's build the server:

    ```bash
    ./mvnw clean install
    ```

    This will generate a `mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar` file within the `target` folder.

    Let's now test your server from an existing MCP host, Claude for Desktop.

    ## Testing your server with Claude for Desktop

    <Note>
      Claude for Desktop is not yet available on Linux.
    </Note>

    First, make sure you have Claude for Desktop installed.
    [You can install the latest version here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.**

    We'll need to configure Claude for Desktop for whichever MCP servers you want to use.
    To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor.
    Make sure to create the file if it doesn't exist.

    For example, if you have [VS Code](https://code.visualstudio.com/) installed:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash
        code ~/Library/Application\ Support/Claude/claude_desktop_config.json
        ```
      </Tab>

      <Tab title="Windows">
        ```powershell
        code $env:AppData\Claude\claude_desktop_config.json
        ```
      </Tab>
    </Tabs>

    You'll then add your servers in the `mcpServers` key.
    The MCP UI elements will only show up in Claude for Desktop if at least one server is properly configured.

    In this case, we'll add our single weather server like so:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```json java
        {
          "mcpServers": {
            "spring-ai-mcp-weather": {
              "command": "java",
              "args": [
                "-Dspring.ai.mcp.server.stdio=true",
                "-jar",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
              ]
            }
          }
        }
        ```
      </Tab>

      <Tab title="Windows">
        ```json java
        {
          "mcpServers": {
            "spring-ai-mcp-weather": {
              "command": "java",
              "args": [
                "-Dspring.ai.mcp.server.transport=STDIO",
                "-jar",
                "C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather\\mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar"
              ]
            }
          }
        }
        ```
      </Tab>
    </Tabs>

    <Note>
      Make sure you pass in the absolute path to your server.
    </Note>

    This tells Claude for Desktop:

    1. There's an MCP server named "my-weather-server"
    2. To launch it by running `java -jar /ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar`

    Save the file, and restart **Claude for Desktop**.

    ## Testing your server with Java client

    ### Create a MCP Client manually

    Use the `McpClient` to connect to the server:

    ```java
    var stdioParams = ServerParameters.builder("java")
      .args("-jar", "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar")
      .build();

    var stdioTransport = new StdioClientTransport(stdioParams);

    var mcpClient = McpClient.sync(stdioTransport).build();

    mcpClient.initialize();

    ListToolsResult toolsList = mcpClient.listTools();

    CallToolResult weather = mcpClient.callTool(
      new CallToolRequest("getWeatherForecastByLocation",
          Map.of("latitude", "47.6062", "longitude", "-122.3321")));

    CallToolResult alert = mcpClient.callTool(
      new CallToolRequest("getAlerts", Map.of("state", "NY")));

    mcpClient.closeGracefully();
    ```

    ### Use MCP Client Boot Starter

    Create a new boot starter applicaiton using the `spring-ai-mcp-client-spring-boot-starter` dependency:

    ```xml
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
    </dependency>
    ```

    and set the `spring.ai.mcp.client.stdio.servers-configuration` property to point to your `claude_desktop_config.json`.
    You can re-use the existing Anthropic Destop configuration:

    ```properties
    spring.ai.mcp.client.stdio.servers-configuration=file:PATH/TO/claude_desktop_config.json
    ```

    When you stasrt your client applicaiton, the auto-configuration will create, automatically MCP clients from the claude\_desktop\_config.json.

    For more information, see the [MCP Client Boot Starters](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-client-docs.html) reference documentation.

    ## More Java MCP Server examples

    The [starter-webflux-server](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-webflux-server) demonstrates how to create a MCP server using SSE transport.
    It showcases how to define and register MCP Tools, Resources, and Prompts, using the Spring Boot's auto-configuration capabilities.
  </Tab>
</Tabs>

### Test with commands

Let's make sure Claude for Desktop is picking up the two tools we've exposed in our `weather` server. You can do this by looking for the hammer <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/claude-desktop-mcp-hammer-icon.svg" style={{display: 'inline', margin: 0, height: '1.3em'}} /> icon:

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/visual-indicator-mcp-tools.png" />
</Frame>

After clicking on the hammer icon, you should see two tools listed:

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/available-mcp-tools.png" />
</Frame>

If your server isn't being picked up by Claude for Desktop, proceed to the [Troubleshooting](#troubleshooting) section for debugging tips.

If the hammer icon has shown up, you can now test your server by running the following commands in Claude for Desktop:

* What's the weather in Sacramento?
* What are the active weather alerts in Texas?

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/current-weather.png" />
</Frame>

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/weather-alerts.png" />
</Frame>

<Note>
  Since this is the US National Weather service, the queries will only work for US locations.
</Note>

## What's happening under the hood

When you ask a question:

1. The client sends your question to Claude
2. Claude analyzes the available tools and decides which one(s) to use
3. The client executes the chosen tool(s) through the MCP server
4. The results are sent back to Claude
5. Claude formulates a natural language response
6. The response is displayed to you!

## Troubleshooting

<AccordionGroup>
  <Accordion title="Claude for Desktop Integration Issues">
    **Getting logs from Claude for Desktop**

    Claude.app logging related to MCP is written to log files in `~/Library/Logs/Claude`:

    * `mcp.log` will contain general logging about MCP connections and connection failures.
    * Files named `mcp-server-SERVERNAME.log` will contain error (stderr) logging from the named server.

    You can run the following command to list recent logs and follow along with any new ones:

    ```bash
    # Check Claude's logs for errors
    tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
    ```

    **Server not showing up in Claude**

    1. Check your `claude_desktop_config.json` file syntax
    2. Make sure the path to your project is absolute and not relative
    3. Restart Claude for Desktop completely

    **Tool calls failing silently**

    If Claude attempts to use the tools but they fail:

    1. Check Claude's logs for errors
    2. Verify your server builds and runs without errors
    3. Try restarting Claude for Desktop

    **None of this is working. What do I do?**

    Please refer to our [debugging guide](/docs/tools/debugging) for better debugging tools and more detailed guidance.
  </Accordion>

  <Accordion title="Weather API Issues">
    **Error: Failed to retrieve grid point data**

    This usually means either:

    1. The coordinates are outside the US
    2. The NWS API is having issues
    3. You're being rate limited

    Fix:

    * Verify you're using US coordinates
    * Add a small delay between requests
    * Check the NWS API status page

    **Error: No active alerts for \[STATE]**

    This isn't an error - it just means there are no current weather alerts for that state. Try a different state or check during severe weather.
  </Accordion>
</AccordionGroup>

<Note>
  For more advanced troubleshooting, check out our guide on [Debugging MCP](/docs/tools/debugging)
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Building a client" icon="outlet" href="/quickstart/client">
    Learn how to build your own MCP client that can connect to your server
  </Card>

  <Card title="Example servers" icon="grid" href="/examples">
    Check out our gallery of official MCP servers and implementations
  </Card>

  <Card title="Debugging Guide" icon="bug" href="/docs/tools/debugging">
    Learn how to effectively debug MCP servers and integrations
  </Card>

  <Card title="Building MCP with LLMs" icon="comments" href="/tutorials/building-mcp-with-llms">
    Learn how to use LLMs like Claude to speed up your MCP development
  </Card>
</CardGroup>


# For Claude Desktop Users
Source: https://modelcontextprotocol.io/quickstart/user

Get started using pre-built servers in Claude for Desktop.

In this tutorial, you will extend [Claude for Desktop](https://claude.ai/download) so that it can read from your computer's file system, write new files, move files, and even search files.

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-filesystem.png" />
</Frame>

Don't worry — it will ask you for your permission before executing these actions!

## 1. Download Claude for Desktop

Start by downloading [Claude for Desktop](https://claude.ai/download), choosing either macOS or Windows. (Linux is not yet supported for Claude for Desktop.)

Follow the installation instructions.

If you already have Claude for Desktop, make sure it's on the latest version by clicking on the Claude menu on your computer and selecting "Check for Updates..."

<Accordion title="Why Claude for Desktop and not Claude.ai?">
  Because servers are locally run, MCP currently only supports desktop hosts. Remote hosts are in active development.
</Accordion>

## 2. Add the Filesystem MCP Server

To add this filesystem functionality, we will be installing a pre-built [Filesystem MCP Server](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem) to Claude for Desktop. This is one of dozens of [servers](https://github.com/modelcontextprotocol/servers/tree/main) created by Anthropic and the community.

Get started by opening up the Claude menu on your computer and select "Settings..." Please note that these are not the Claude Account Settings found in the app window itself.

This is what it should look like on a Mac:

<Frame style={{ textAlign: 'center' }}>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-menu.png" width="400" />
</Frame>

Click on "Developer" in the lefthand bar of the Settings pane, and then click on "Edit Config":

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-developer.png" />
</Frame>

This will create a configuration file at:

* macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
* Windows: `%APPDATA%\Claude\claude_desktop_config.json`

if you don't already have one, and will display the file in your file system.

Open up the configuration file in any text editor. Replace the file contents with this:

<Tabs>
  <Tab title="MacOS/Linux">
    ```json
    {
      "mcpServers": {
        "filesystem": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "/Users/username/Desktop",
            "/Users/username/Downloads"
          ]
        }
      }
    }
    ```
  </Tab>

  <Tab title="Windows">
    ```json
    {
      "mcpServers": {
        "filesystem": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "C:\\Users\\username\\Desktop",
            "C:\\Users\\username\\Downloads"
          ]
        }
      }
    }
    ```
  </Tab>
</Tabs>

Make sure to replace `username` with your computer's username. The paths should point to valid directories that you want Claude to be able to access and modify. It's set up to work for Desktop and Downloads, but you can add more paths as well.

You will also need [Node.js](https://nodejs.org) on your computer for this to run properly. To verify you have Node installed, open the command line on your computer.

* On macOS, open the Terminal from your Applications folder
* On Windows, press Windows + R, type "cmd", and press Enter

Once in the command line, verify you have Node installed by entering in the following command:

```bash
node --version
```

If you get an error saying "command not found" or "node is not recognized", download Node from [nodejs.org](https://nodejs.org/).

<Tip>
  **How does the configuration file work?**

  This configuration file tells Claude for Desktop which MCP servers to start up every time you start the application. In this case, we have added one server called "filesystem" that will use the Node `npx` command to install and run `@modelcontextprotocol/server-filesystem`. This server, described [here](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem), will let you access your file system in Claude for Desktop.
</Tip>

<Warning>
  **Command Privileges**

  Claude for Desktop will run the commands in the configuration file with the permissions of your user account, and access to your local files. Only add commands if you understand and trust the source.
</Warning>

## 3. Restart Claude

After updating your configuration file, you need to restart Claude for Desktop.

Upon restarting, you should see a hammer <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/claude-desktop-mcp-hammer-icon.svg" style={{display: 'inline', margin: 0, height: '1.3em'}} /> icon in the bottom right corner of the input box:

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-hammer.png" />
</Frame>

After clicking on the hammer icon, you should see the tools that come with the Filesystem MCP Server:

<Frame style={{ textAlign: 'center' }}>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-tools.png" width="400" />
</Frame>

If your server isn't being picked up by Claude for Desktop, proceed to the [Troubleshooting](#troubleshooting) section for debugging tips.

## 4. Try it out!

You can now talk to Claude and ask it about your filesystem. It should know when to call the relevant tools.

Things you might try asking Claude:

* Can you write a poem and save it to my desktop?
* What are some work-related files in my downloads folder?
* Can you take all the images on my desktop and move them to a new folder called "Images"?

As needed, Claude will call the relevant tools and seek your approval before taking an action:

<Frame style={{ textAlign: 'center' }}>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/quickstart-approve.png" width="500" />
</Frame>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Server not showing up in Claude / hammer icon missing">
    1. Restart Claude for Desktop completely
    2. Check your `claude_desktop_config.json` file syntax
    3. Make sure the file paths included in `claude_desktop_config.json` are valid and that they are absolute and not relative
    4. Look at [logs](#getting-logs-from-claude-for-desktop) to see why the server is not connecting
    5. In your command line, try manually running the server (replacing `username` as you did in `claude_desktop_config.json`) to see if you get any errors:

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash
        npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop /Users/username/Downloads
        ```
      </Tab>

      <Tab title="Windows">
        ```bash
        npx -y @modelcontextprotocol/server-filesystem C:\Users\username\Desktop C:\Users\username\Downloads
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Getting logs from Claude for Desktop">
    Claude.app logging related to MCP is written to log files in:

    * macOS: `~/Library/Logs/Claude`

    * Windows: `%APPDATA%\Claude\logs`

    * `mcp.log` will contain general logging about MCP connections and connection failures.

    * Files named `mcp-server-SERVERNAME.log` will contain error (stderr) logging from the named server.

    You can run the following command to list recent logs and follow along with any new ones (on Windows, it will only show recent logs):

    <Tabs>
      <Tab title="MacOS/Linux">
        ```bash
        # Check Claude's logs for errors
        tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
        ```
      </Tab>

      <Tab title="Windows">
        ```bash
        type "%APPDATA%\Claude\logs\mcp*.log"
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Tool calls failing silently">
    If Claude attempts to use the tools but they fail:

    1. Check Claude's logs for errors
    2. Verify your server builds and runs without errors
    3. Try restarting Claude for Desktop
  </Accordion>

  <Accordion title="None of this is working. What do I do?">
    Please refer to our [debugging guide](/docs/tools/debugging) for better debugging tools and more detailed guidance.
  </Accordion>

  <Accordion title="ENOENT error and `${APPDATA}` in paths on Windows">
    If your configured server fails to load, and you see within its logs an error referring to `${APPDATA}` within a path, you may need to add the expanded value of `%APPDATA%` to your `env` key in `claude_desktop_config.json`:

    ```json
    {
      "brave-search": {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-brave-search"],
        "env": {
          "APPDATA": "C:\\Users\\user\\AppData\\Roaming\\",
          "BRAVE_API_KEY": "..."
        }
      }
    }
    ```

    With this change in place, launch Claude Desktop once again.

    <Warning>
      **NPM should be installed globally**

      The `npx` command may continue to fail if you have not installed NPM globally. If NPM is already installed globally, you will find `%APPDATA%\npm` exists on your system. If not, you can install NPM globally by running the following command:

      ```bash
      npm install -g npm
      ```
    </Warning>
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Explore other servers" icon="grid" href="/examples">
    Check out our gallery of official MCP servers and implementations
  </Card>

  <Card title="Build your own server" icon="code" href="/quickstart/server">
    Now build your own custom server to use in Claude for Desktop and other clients
  </Card>
</CardGroup>


# MCP Client
Source: https://modelcontextprotocol.io/sdk/java/mcp-client

Learn how to use the Model Context Protocol (MCP) client to interact with MCP servers

# Model Context Protocol Client

The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers. It implements the client-side of the protocol, handling:

* Protocol version negotiation to ensure compatibility with servers
* Capability negotiation to determine available features
* Message transport and JSON-RPC communication
* Tool discovery and execution
* Resource access and management
* Prompt system interactions
* Optional features like roots management and sampling support

The client provides both synchronous and asynchronous APIs for flexibility in different application contexts.

<Tabs>
  <Tab title="Sync API">
    ```java
    // Create a sync client with custom configuration
    McpSyncClient client = McpClient.sync(transport)
        .requestTimeout(Duration.ofSeconds(10))
        .capabilities(ClientCapabilities.builder()
            .roots(true)      // Enable roots capability
            .sampling()       // Enable sampling capability
            .build())
        .sampling(request -> new CreateMessageResult(response))
        .build();

    // Initialize connection
    client.initialize();

    // List available tools
    ListToolsResult tools = client.listTools();

    // Call a tool
    CallToolResult result = client.callTool(
        new CallToolRequest("calculator", 
            Map.of("operation", "add", "a", 2, "b", 3))
    );

    // List and read resources
    ListResourcesResult resources = client.listResources();
    ReadResourceResult resource = client.readResource(
        new ReadResourceRequest("resource://uri")
    );

    // List and use prompts
    ListPromptsResult prompts = client.listPrompts();
    GetPromptResult prompt = client.getPrompt(
        new GetPromptRequest("greeting", Map.of("name", "Spring"))
    );

    // Add/remove roots
    client.addRoot(new Root("file:///path", "description"));
    client.removeRoot("file:///path");

    // Close client
    client.closeGracefully();
    ```
  </Tab>

  <Tab title="Async API">
    ```java
    // Create an async client with custom configuration
    McpAsyncClient client = McpClient.async(transport)
        .requestTimeout(Duration.ofSeconds(10))
        .capabilities(ClientCapabilities.builder()
            .roots(true)      // Enable roots capability
            .sampling()       // Enable sampling capability
            .build())
        .sampling(request -> Mono.just(new CreateMessageResult(response)))
        .toolsChangeConsumer(tools -> Mono.fromRunnable(() -> {
            logger.info("Tools updated: {}", tools);
        }))
        .resourcesChangeConsumer(resources -> Mono.fromRunnable(() -> {
            logger.info("Resources updated: {}", resources);
        }))
        .promptsChangeConsumer(prompts -> Mono.fromRunnable(() -> {
            logger.info("Prompts updated: {}", prompts);
        }))
        .build();

    // Initialize connection and use features
    client.initialize()
        .flatMap(initResult -> client.listTools())
        .flatMap(tools -> {
            return client.callTool(new CallToolRequest(
                "calculator", 
                Map.of("operation", "add", "a", 2, "b", 3)
            ));
        })
        .flatMap(result -> {
            return client.listResources()
                .flatMap(resources -> 
                    client.readResource(new ReadResourceRequest("resource://uri"))
                );
        })
        .flatMap(resource -> {
            return client.listPrompts()
                .flatMap(prompts ->
                    client.getPrompt(new GetPromptRequest(
                        "greeting", 
                        Map.of("name", "Spring")
                    ))
                );
        })
        .flatMap(prompt -> {
            return client.addRoot(new Root("file:///path", "description"))
                .then(client.removeRoot("file:///path"));            
        })
        .doFinally(signalType -> {
            client.closeGracefully().subscribe();
        })
        .subscribe();
    ```
  </Tab>
</Tabs>

## Client Transport

The transport layer handles the communication between MCP clients and servers, providing different implementations for various use cases. The client transport manages message serialization, connection establishment, and protocol-specific communication patterns.

<Tabs>
  <Tab title="STDIO">
    Creates transport for in-process based communication

    ```java
    ServerParameters params = ServerParameters.builder("npx")
        .args("-y", "@modelcontextprotocol/server-everything", "dir")
        .build();
    McpTransport transport = new StdioClientTransport(params);
    ```
  </Tab>

  <Tab title="SSE (HttpClient)">
    Creates a framework agnostic (pure Java API) SSE client transport. Included in the core mcp module.

    ```java
    McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server");
    ```
  </Tab>

  <Tab title="SSE (WebFlux)">
    Creates WebFlux-based SSE client transport. Requires the mcp-webflux-sse-transport dependency.

    ```java
    WebClient.Builder webClientBuilder = WebClient.builder()
        .baseUrl("http://your-mcp-server");
    McpTransport transport = new WebFluxSseClientTransport(webClientBuilder);
    ```
  </Tab>
</Tabs>

## Client Capabilities

The client can be configured with various capabilities:

```java
var capabilities = ClientCapabilities.builder()
    .roots(true)      // Enable filesystem roots support with list changes notifications
    .sampling()       // Enable LLM sampling support
    .build();
```

### Roots Support

Roots define the boundaries of where servers can operate within the filesystem:

```java
// Add a root dynamically
client.addRoot(new Root("file:///path", "description"));

// Remove a root
client.removeRoot("file:///path");

// Notify server of roots changes
client.rootsListChangedNotification();
```

The roots capability allows servers to:

* Request the list of accessible filesystem roots
* Receive notifications when the roots list changes
* Understand which directories and files they have access to

### Sampling Support

Sampling enables servers to request LLM interactions ("completions" or "generations") through the client:

```java
// Configure sampling handler
Function<CreateMessageRequest, CreateMessageResult> samplingHandler = request -> {
    // Sampling implementation that interfaces with LLM
    return new CreateMessageResult(response);
};

// Create client with sampling support
var client = McpClient.sync(transport)
    .capabilities(ClientCapabilities.builder()
        .sampling()
        .build())
    .sampling(samplingHandler)
    .build();
```

This capability allows:

* Servers to leverage AI capabilities without requiring API keys
* Clients to maintain control over model access and permissions
* Support for both text and image-based interactions
* Optional inclusion of MCP server context in prompts

## Using MCP Clients

### Tool Execution

Tools are server-side functions that clients can discover and execute. The MCP client provides methods to list available tools and execute them with specific parameters. Each tool has a unique name and accepts a map of parameters.

<Tabs>
  <Tab title="Sync API">
    ```java
    // List available tools and their names
    var tools = client.listTools();
    tools.forEach(tool -> System.out.println(tool.getName()));

    // Execute a tool with parameters
    var result = client.callTool("calculator", Map.of(
        "operation", "add",
        "a", 1,
        "b", 2
    ));
    ```
  </Tab>

  <Tab title="Async API">
    ```java
    // List available tools asynchronously
    client.listTools()
        .doOnNext(tools -> tools.forEach(tool -> 
            System.out.println(tool.getName())))
        .subscribe();

    // Execute a tool asynchronously
    client.callTool("calculator", Map.of(
            "operation", "add",
            "a", 1,
            "b", 2
        ))
        .subscribe();
    ```
  </Tab>
</Tabs>

### Resource Access

Resources represent server-side data sources that clients can access using URI templates. The MCP client provides methods to discover available resources and retrieve their contents through a standardized interface.

<Tabs>
  <Tab title="Sync API">
    ```java
    // List available resources and their names
    var resources = client.listResources();
    resources.forEach(resource -> System.out.println(resource.getName()));

    // Retrieve resource content using a URI template
    var content = client.getResource("file", Map.of(
        "path", "/path/to/file.txt"
    ));
    ```
  </Tab>

  <Tab title="Async API">
    ```java
    // List available resources asynchronously
    client.listResources()
        .doOnNext(resources -> resources.forEach(resource -> 
            System.out.println(resource.getName())))
        .subscribe();

    // Retrieve resource content asynchronously
    client.getResource("file", Map.of(
            "path", "/path/to/file.txt"
        ))
        .subscribe();
    ```
  </Tab>
</Tabs>

### Prompt System

The prompt system enables interaction with server-side prompt templates. These templates can be discovered and executed with custom parameters, allowing for dynamic text generation based on predefined patterns.

<Tabs>
  <Tab title="Sync API">
    ```java
    // List available prompt templates
    var prompts = client.listPrompts();
    prompts.forEach(prompt -> System.out.println(prompt.getName()));

    // Execute a prompt template with parameters
    var response = client.executePrompt("echo", Map.of(
        "text", "Hello, World!"
    ));
    ```
  </Tab>

  <Tab title="Async API">
    ```java
    // List available prompt templates asynchronously
    client.listPrompts()
        .doOnNext(prompts -> prompts.forEach(prompt -> 
            System.out.println(prompt.getName())))
        .subscribe();

    // Execute a prompt template asynchronously
    client.executePrompt("echo", Map.of(
            "text", "Hello, World!"
        ))
        .subscribe();
    ```
  </Tab>
</Tabs>


# Overview
Source: https://modelcontextprotocol.io/sdk/java/mcp-overview

Introduction to the Model Context Protocol (MCP) Java SDK

Java SDK for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture)
enables standardized integration between AI models and tools.

## Features

* MCP Client and MCP Server implementations supporting:
  * Protocol [version compatibility negotiation](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/#initialization)
  * [Tool](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) discovery, execution, list change notifications
  * [Resource](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/) management with URI templates
  * [Roots](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/roots/) list management and notifications
  * [Prompt](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/) handling and management
  * [Sampling](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/sampling/) support for AI model interactions
* Multiple transport implementations:
  * Default transports:
    * Stdio-based transport for process-based communication
    * Java HttpClient-based SSE client transport for HTTP SSE Client-side streaming
    * Servlet-based SSE server transport for HTTP SSE Server streaming
  * Spring-based transports:
    * WebFlux SSE client and server transports for reactive HTTP streaming
    * WebMVC SSE transport for servlet-based HTTP streaming
* Supports Synchronous and Asynchronous programming paradigms

## Architecture

The SDK follows a layered architecture with clear separation of concerns:

![MCP Stack Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/mcp-stack.svg)

* **Client/Server Layer (McpClient/McpServer)**: Both use McpSession for sync/async operations,
  with McpClient handling client-side protocol operations and McpServer managing server-side protocol operations.
* **Session Layer (McpSession)**: Manages communication patterns and state using DefaultMcpSession implementation.
* **Transport Layer (McpTransport)**: Handles JSON-RPC message serialization/deserialization via:
  * StdioTransport (stdin/stdout) in the core module
  * HTTP SSE transports in dedicated transport modules (Java HttpClient, Spring WebFlux, Spring WebMVC)

The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers.
It implements the client-side of the protocol.

![Java MCP Client Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/java-mcp-client-architecture.jpg)

The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients.
It implements the server-side of the protocol.

![Java MCP Server Architecture](https://mintlify.s3.us-west-1.amazonaws.com/mcp/images/java/java-mcp-server-architecture.jpg)

Key Interactions:

* **Client/Server Initialization**: Transport setup, protocol compatibility check, capability negotiation, and implementation details exchange.
* **Message Flow**: JSON-RPC message handling with validation, type-safe response processing, and error handling.
* **Resource Management**: Resource discovery, URI template-based access, subscription system, and content retrieval.

## Dependencies

Add the following Maven dependency to your project:

<Tabs>
  <Tab title="Maven">
    The core MCP functionality:

    ```xml
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp</artifactId>
    </dependency>
    ```

    For HTTP SSE transport implementations, add one of the following dependencies:

    ```xml
    <!-- Spring WebFlux-based SSE client and server transport -->
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp-spring-webflux</artifactId>
    </dependency>

    <!-- Spring WebMVC-based SSE server transport -->
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp-spring-webmvc</artifactId>
    </dependency>
    ```
  </Tab>

  <Tab title="Gradle">
    The core MCP functionality:

    ```groovy
    dependencies {
      implementation platform("io.modelcontextprotocol.sdk:mcp")
      //...
    }
    ```

    For HTTP SSE transport implementations, add one of the following dependencies:

    ```groovy
    // Spring WebFlux-based SSE client and server transport
    dependencies {
      implementation platform("io.modelcontextprotocol.sdk:mcp-spring-webflux")
    }

    // Spring WebMVC-based SSE server transport
    dependencies {
      implementation platform("io.modelcontextprotocol.sdk:mcp-spring-webmvc")
    }
    ```
  </Tab>
</Tabs>

### Bill of Materials (BOM)

The Bill of Materials (BOM) declares the recommended versions of all the dependencies used by a given release.
Using the BOM from your application's build script avoids the need for you to specify and maintain the dependency versions yourself.
Instead, the version of the BOM you're using determines the utilized dependency versions.
It also ensures that you're using supported and tested versions of the dependencies by default, unless you choose to override them.

Add the BOM to your project:

<Tabs>
  <Tab title="Maven">
    ```xml
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp-bom</artifactId>
                <version>0.7.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    ```
  </Tab>

  <Tab title="Gradle">
    ```groovy
    dependencies {
      implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.7.0")
      //...
    }
    ```

    Gradle users can also use the Spring AI MCP BOM by leveraging Gradle (5.0+) native support for declaring dependency constraints using a Maven BOM.
    This is implemented by adding a 'platform' dependency handler method to the dependencies section of your Gradle build script.
    As shown in the snippet above this can then be followed by version-less declarations of the Starter Dependencies for the one or more spring-ai modules you wish to use, e.g. spring-ai-openai.
  </Tab>
</Tabs>

Replace the version number with the version of the BOM you want to use.

### Available Dependencies

The following dependencies are available and managed by the BOM:

* Core Dependencies
  * `io.modelcontextprotocol.sdk:mcp` - Core MCP library providing the base functionality and APIs for Model Context Protocol implementation.
* Transport Dependencies
  * `io.modelcontextprotocol.sdk:mcp-spring-webflux` - WebFlux-based Server-Sent Events (SSE) transport implementation for reactive applications.
  * `io.modelcontextprotocol.sdk:mcp-spring-webmvc` - WebMVC-based Server-Sent Events (SSE) transport implementation for servlet-based applications.
* Testing Dependencies
  * `io.modelcontextprotocol.sdk:mcp-test` - Testing utilities and support for MCP-based applications.


# MCP Server
Source: https://modelcontextprotocol.io/sdk/java/mcp-server

Learn how to implement and configure a Model Context Protocol (MCP) server

## Overview

The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients. It implements the server-side of the protocol, responsible for:

* Exposing tools that clients can discover and execute
* Managing resources with URI-based access patterns
* Providing prompt templates and handling prompt requests
* Supporting capability negotiation with clients
* Implementing server-side protocol operations
* Managing concurrent client connections
* Providing structured logging and notifications

The server supports both synchronous and asynchronous APIs, allowing for flexible integration in different application contexts.

<Tabs>
  <Tab title="Sync API">
    ```java
    // Create a server with custom configuration
    McpSyncServer syncServer = McpServer.sync(transport)
        .serverInfo("my-server", "1.0.0")
        .capabilities(ServerCapabilities.builder()
            .resources(true)     // Enable resource support
            .tools(true)         // Enable tool support
            .prompts(true)       // Enable prompt support
            .logging()           // Enable logging support
            .build())
        .build();

    // Register tools, resources, and prompts
    syncServer.addTool(syncToolRegistration);
    syncServer.addResource(syncResourceRegistration);
    syncServer.addPrompt(syncPromptRegistration);

    // Send logging notifications
    syncServer.loggingNotification(LoggingMessageNotification.builder()
        .level(LoggingLevel.INFO)
        .logger("custom-logger")
        .data("Server initialized")
        .build());

    // Close the server when done
    syncServer.close();
    ```
  </Tab>

  <Tab title="Async API">
    ```java
    // Create an async server with custom configuration
    McpAsyncServer asyncServer = McpServer.async(transport)
        .serverInfo("my-server", "1.0.0")
        .capabilities(ServerCapabilities.builder()
            .resources(true)     // Enable resource support
            .tools(true)         // Enable tool support
            .prompts(true)       // Enable prompt support
            .logging()           // Enable logging support
            .build())
        .build();

    // Register tools, resources, and prompts
    asyncServer.addTool(asyncToolRegistration)
        .doOnSuccess(v -> logger.info("Tool registered"))
        .subscribe();

    asyncServer.addResource(asyncResourceRegistration)
        .doOnSuccess(v -> logger.info("Resource registered"))
        .subscribe();

    asyncServer.addPrompt(asyncPromptRegistration)
        .doOnSuccess(v -> logger.info("Prompt registered"))
        .subscribe();

    // Send logging notifications
    asyncServer.loggingNotification(LoggingMessageNotification.builder()
        .level(LoggingLevel.INFO)
        .logger("custom-logger")
        .data("Server initialized")
        .build());

    // Close the server when done
    asyncServer.close()
        .doOnSuccess(v -> logger.info("Server closed"))
        .subscribe();
    ```
  </Tab>
</Tabs>

## Server Transport

The transport layer in the MCP SDK is responsible for handling the communication between clients and servers. It provides different implementations to support various communication protocols and patterns. The SDK includes several built-in transport implementations:

<Tabs>
  <Tab title="STDIO">
    <>
      Create in-process based transport:

      ```java
      StdioServerTransport transport = new StdioServerTransport(new ObjectMapper());
      ```

      Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support.

      Key features:

      <ul>
        <li>Bidirectional communication through stdin/stdout</li>
        <li>Process-based integration support</li>
        <li>Simple setup and configuration</li>
        <li>Lightweight implementation</li>
      </ul>
    </>
  </Tab>

  <Tab title="SSE (WebFlux)">
    <>
      <p>Creates WebFlux-based SSE server transport.<br />Requires the <code>mcp-spring-webflux</code> dependency.</p>

      ```java
      @Configuration
      class McpConfig {
          @Bean
          WebFluxSseServerTransport webFluxSseServerTransport(ObjectMapper mapper) {
              return new WebFluxSseServerTransport(mapper, "/mcp/message");
          }

          @Bean
          RouterFunction<?> mcpRouterFunction(WebFluxSseServerTransport transport) {
              return transport.getRouterFunction();
          }
      }
      ```

      <p>Implements the MCP HTTP with SSE transport specification, providing:</p>

      <ul>
        <li>Reactive HTTP streaming with WebFlux</li>
        <li>Concurrent client connections through SSE endpoints</li>
        <li>Message routing and session management</li>
        <li>Graceful shutdown capabilities</li>
      </ul>
    </>
  </Tab>

  <Tab title="SSE (WebMvc)">
    <>
      <p>Creates WebMvc-based SSE server transport.<br />Requires the <code>mcp-spring-webmvc</code> dependency.</p>

      ```java
      @Configuration
      @EnableWebMvc
      class McpConfig {
          @Bean
          WebMvcSseServerTransport webMvcSseServerTransport(ObjectMapper mapper) {
              return new WebMvcSseServerTransport(mapper, "/mcp/message");
          }

          @Bean
          RouterFunction<ServerResponse> mcpRouterFunction(WebMvcSseServerTransport transport) {
              return transport.getRouterFunction();
          }
      }
      ```

      <p>Implements the MCP HTTP with SSE transport specification, providing:</p>

      <ul>
        <li>Server-side event streaming</li>
        <li>Integration with Spring WebMVC</li>
        <li>Support for traditional web applications</li>
        <li>Synchronous operation handling</li>
      </ul>
    </>
  </Tab>

  <Tab title="SSE (Servlet)">
    <>
      <p>
        Creates a Servlet-based SSE server transport. It is included in the core <code>mcp</code> module.<br />
        The <code>HttpServletSseServerTransport</code> can be used with any Servlet container.<br />
        To use it with a Spring Web application, you can register it as a Servlet bean:
      </p>

      ```java
      @Configuration
      @EnableWebMvc
      public class McpServerConfig implements WebMvcConfigurer {

          @Bean
          public HttpServletSseServerTransport servletSseServerTransport() {
              return new HttpServletSseServerTransport(new ObjectMapper(), "/mcp/message");
          }

          @Bean
          public ServletRegistrationBean customServletBean(HttpServletSseServerTransport servlet) {
              return new ServletRegistrationBean(servlet);
          }
      }
      ```

      <p>
        Implements the MCP HTTP with SSE transport specification using the traditional Servlet API, providing:
      </p>

      <ul>
        <li>Asynchronous message handling using Servlet 6.0 async support</li>
        <li>Session management for multiple client connections</li>

        <li>
          Two types of endpoints:

          <ul>
            <li>SSE endpoint (<code>/sse</code>) for server-to-client events</li>
            <li>Message endpoint (configurable) for client-to-server requests</li>
          </ul>
        </li>

        <li>Error handling and response formatting</li>
        <li>Graceful shutdown support</li>
      </ul>
    </>
  </Tab>
</Tabs>

## Server Capabilities

The server can be configured with various capabilities:

```java
var capabilities = ServerCapabilities.builder()
    .resources(false, true)  // Resource support with list changes notifications
    .tools(true)            // Tool support with list changes notifications
    .prompts(true)          // Prompt support with list changes notifications
    .logging()              // Enable logging support (enabled by default with loging level INFO)
    .build();
```

### Logging Support

The server provides structured logging capabilities that allow sending log messages to clients with different severity levels:

```java
// Send a log message to clients
server.loggingNotification(LoggingMessageNotification.builder()
    .level(LoggingLevel.INFO)
    .logger("custom-logger")
    .data("Custom log message")
    .build());
```

Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out.
Supported logging levels (in order of increasing severity): DEBUG (0), INFO (1), NOTICE (2), WARNING (3), ERROR (4), CRITICAL (5), ALERT (6), EMERGENCY (7)

### Tool Registration

<Tabs>
  <Tab title="Sync">
    ```java
    // Sync tool registration
    var schema = """
                {
                  "type" : "object",
                  "id" : "urn:jsonschema:Operation",
                  "properties" : {
                    "operation" : {
                      "type" : "string"
                    },
                    "a" : {
                      "type" : "number"
                    },
                    "b" : {
                      "type" : "number"
                    }
                  }
                }
                """;
    var syncToolRegistration = new McpServerFeatures.SyncToolRegistration(
        new Tool("calculator", "Basic calculator", schema),
        arguments -> {
            // Tool implementation
            return new CallToolResult(result, false);
        }
    );
    ```
  </Tab>

  <Tab title="Async">
    ```java
    // Async tool registration
    var schema = """
                {
                  "type" : "object",
                  "id" : "urn:jsonschema:Operation",
                  "properties" : {
                    "operation" : {
                      "type" : "string"
                    },
                    "a" : {
                      "type" : "number"
                    },
                    "b" : {
                      "type" : "number"
                    }
                  }
                }
                """;
    var asyncToolRegistration = new McpServerFeatures.AsyncToolRegistration(
        new Tool("calculator", "Basic calculator", schema),
        arguments -> {
            // Tool implementation
            return Mono.just(new CallToolResult(result, false));
        }
    );
    ```
  </Tab>
</Tabs>

### Resource Registration

<Tabs>
  <Tab title="Sync">
    ```java
    // Sync resource registration
    var syncResourceRegistration = new McpServerFeatures.SyncResourceRegistration(
        new Resource("custom://resource", "name", "description", "mime-type", null),
        request -> {
            // Resource read implementation
            return new ReadResourceResult(contents);
        }
    );
    ```
  </Tab>

  <Tab title="Async">
    ```java
    // Async resource registration
    var asyncResourceRegistration = new McpServerFeatures.AsyncResourceRegistration(
        new Resource("custom://resource", "name", "description", "mime-type", null),
        request -> {
            // Resource read implementation
            return Mono.just(new ReadResourceResult(contents));
        }
    );
    ```
  </Tab>
</Tabs>

### Prompt Registration

<Tabs>
  <Tab title="Sync">
    ```java
    // Sync prompt registration
    var syncPromptRegistration = new McpServerFeatures.SyncPromptRegistration(
        new Prompt("greeting", "description", List.of(
            new PromptArgument("name", "description", true)
        )),
        request -> {
            // Prompt implementation
            return new GetPromptResult(description, messages);
        }
    );
    ```
  </Tab>

  <Tab title="Async">
    ```java
    // Async prompt registration
    var asyncPromptRegistration = new McpServerFeatures.AsyncPromptRegistration(
        new Prompt("greeting", "description", List.of(
            new PromptArgument("name", "description", true)
        )),
        request -> {
            // Prompt implementation
            return Mono.just(new GetPromptResult(description, messages));
        }
    );
    ```
  </Tab>
</Tabs>

## Error Handling

The SDK provides comprehensive error handling through the McpError class, covering protocol compatibility, transport communication, JSON-RPC messaging, tool execution, resource management, prompt handling, timeouts, and connection issues. This unified error handling approach ensures consistent and reliable error management across both synchronous and asynchronous operations.


# Building MCP with LLMs
Source: https://modelcontextprotocol.io/tutorials/building-mcp-with-llms

Speed up your MCP development using LLMs such as Claude!

This guide will help you use LLMs to help you build custom Model Context Protocol (MCP) servers and clients. We'll be focusing on Claude for this tutorial, but you can do this with any frontier LLM.

## Preparing the documentation

Before starting, gather the necessary documentation to help Claude understand MCP:

1.  Visit [https://modelcontextprotocol.io/llms-full.txt](https://modelcontextprotocol.io/llms-full.txt) and copy the full documentation text
2.  Navigate to either the [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) or [Python SDK repository](https://github.com/modelcontextprotocol/python-sdk)
3.  Copy the README files and other relevant documentation
4.  Paste these documents into your conversation with Claude

## Describing your server

Once you've provided the documentation, clearly describe to Claude what kind of server you want to build. Be specific about:

*   What resources your server will expose
*   What tools it will provide
*   Any prompts it should offer
*   What external systems it needs to interact with

For example:

```
Build an MCP server that:
- Connects to my company's PostgreSQL database
- Exposes table schemas as resources
- Provides tools for running read-only SQL queries
- Includes prompts for common data analysis tasks
```

## Working with Claude

When working with Claude on MCP servers:

1.  Start with the core functionality first, then iterate to add more features
2.  Ask Claude to explain any parts of the code you don't understand
3.  Request modifications or improvements as needed
4.  Have Claude help you test the server and handle edge cases

Claude can help implement all the key MCP features:

*   Resource management and exposure
*   Tool definitions and implementations
*   Prompt templates and handlers
*   Error handling and logging
*   Connection and transport setup

## Best practices

When building MCP servers with Claude:

*   Break down complex servers into smaller pieces
*   Test each component thoroughly before moving on
*   Keep security in mind - validate inputs and limit access appropriately
*   Document your code well for future maintenance
*   Follow MCP protocol specifications carefully

## Next steps

After Claude helps you build your server:

1.  Review the generated code carefully
2.  Test the server with the MCP Inspector tool
3.  Connect it to Claude.app or other MCP clients
4.  Iterate based on real usage and feedback

Remember that Claude can help you modify and improve your server as requirements change over time.

Need more guidance? Just ask Claude specific questions about implementing MCP features or troubleshooting issues that arise.



## Links discovered
- [5ire](https://github.com/nanbingxyz/5ire)
- [BeeAI Framework](https://i-am-bee.github.io/beeai-framework)
- [Example of using MCP tools in agentic workflow](https://i-am-bee.github.io/beeai-framework/#/typescript/tools?id=using-the-mcptool-class)
- [Cline](https://github.com/cline/cline)
- [Continue](https://github.com/continuedev/continue)
- [Cursor](https://docs.cursor.com/advanced/model-context-protocol)
- [Emacs Mcp](https://github.com/lizqwerscott/mcp.el)
- [gptel](https://github.com/karthink/gptel)
- [llm](https://github.com/ahyatt/llm)
- [Genkit](https://github.com/firebase/genkit)
- [genkitx-mcp](https://github.com/firebase/genkit/tree/main/js/plugins/mcp)
- [GenAIScript](https://microsoft.github.io/genaiscript/)
- [Goose](https://github.com/block/goose)
- [extensions directory](https://block.github.io/goose/v1/extensions/)
- [building your own MCP servers](https://block.github.io/goose/docs/tutorials/custom-extensions)
- [LibreChat](https://github.com/danny-avila/LibreChat)
- [Code Interpreter](https://www.librechat.ai/docs/features/code_interpreter)
- [Agents](https://www.librechat.ai/docs/features/agents)
- [Building Effective Agents](https://www.anthropic.com/research/building-effective-agents)
- [Roo Code](https://roocode.com)
- [Cody](https://openctx.org/docs/providers/modelcontextprotocol)
- [SpinAI](https://spinai.dev)
- [Superinterface](https://superinterface.ai)
- [Theia AI](https://eclipsesource.com/blogs/2024/10/07/introducing-theia-ai/)
- [AI-powered Theia IDE](https://eclipsesource.com/blogs/2024/10/08/introducting-ai-theia-ide/)
- [Theia IDE and Theia AI MCP Announcement](https://eclipsesource.com/blogs/2024/12/19/theia-ide-and-theia-ai-support-mcp/)
- [Download the AI-powered Theia IDE](https://theia-ide.org/)
- [Windsurf Editor](https://codeium.com/windsurf)
- [Zed](https://zed.dev/docs/assistant/model-context-protocol)
- [OpenSumi](https://github.com/opensumi/core)
- [Daydreams](https://github.com/daydreamsai/daydreams)
- [Python](https://github.com/modelcontextprotocol/python-sdk)
- [TypeScript SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
- [open an issue in our documentation repository](https://github.com/modelcontextprotocol/docs/issues)
- [contributing guidelines](https://github.com/modelcontextprotocol/.github/blob/main/CONTRIBUTING.md)
- [Code of Conduct](https://github.com/modelcontextprotocol/.github/blob/main/CODE_OF_CONDUCT.md)
- [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions)
- [remote MCP connections](https://github.com/modelcontextprotocol/specification/discussions/102)
- [**Authentication & Authorization**](https://github.com/modelcontextprotocol/specification/discussions/64)
- [**Service Discovery**](https://github.com/modelcontextprotocol/specification/discussions/69)
- [**Stateless Operations**](https://github.com/modelcontextprotocol/specification/discussions/102)
- [complex agentic workflows](https://github.com/modelcontextprotocol/specification/discussions/111)
- [**Hierarchical Agent Systems**](https://github.com/modelcontextprotocol/specification/discussions/94)
- [**Interactive Workflows**](https://github.com/modelcontextprotocol/specification/issues/97)
- [**Streaming Results**](https://github.com/modelcontextprotocol/specification/issues/117)
- [**Additional Modalities**](https://github.com/modelcontextprotocol/specification/discussions/88)
- [Java SDK](https://github.com/modelcontextprotocol/java-sdk)
- [1.2.1](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.2.1)
- [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [clients page](https://modelcontextprotocol.io/clients)
- [Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [servers repo](https://github.com/modelcontextprotocol/servers)
- [this repository](https://github.com/modelcontextprotocol/kotlin-sdk/tree/main/samples/kotlin-mcp-server)
- [JSON-RPC](https://www.jsonrpc.org/)
- [specification](https://spec.modelcontextprotocol.io)
- [Tools](https://github.com/eyaltoledano/claude-task-master/blob/main/context/tools.md)
- [URI templates](https://datatracker.ietf.org/doc/html/rfc6570)
- [resources](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/concepts/resources.md)
- [Inspector guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/tools/inspector.md)
- [Inspector](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/tools/inspector.md)
- [transport](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/concepts/transports.md)
- [transports](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/concepts/transports.md)
- [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
- [Debugging Guide](https://github.com/eyaltoledano/claude-task-master/blob/main/docs/tools/debugging.md)
- [NPM](https://npmjs.com)
- [PyPi](https://pypi.com)
- [Filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem)
- [PostgreSQL](https://github.com/modelcontextprotocol/servers/tree/main/src/postgres)
- [SQLite](https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite)
- [Google Drive](https://github.com/modelcontextprotocol/servers/tree/main/src/gdrive)
- [Git](https://github.com/modelcontextprotocol/servers/tree/main/src/git)
- [GitHub](https://github.com/modelcontextprotocol/servers/tree/main/src/github)
- [GitLab](https://github.com/modelcontextprotocol/servers/tree/main/src/gitlab)
- [Sentry](https://github.com/modelcontextprotocol/servers/tree/main/src/sentry)
- [Brave Search](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search)
- [Fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch)
- [Puppeteer](https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer)
- [Slack](https://github.com/modelcontextprotocol/servers/tree/main/src/slack)
- [Google Maps](https://github.com/modelcontextprotocol/servers/tree/main/src/google-maps)
- [Memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory)
- [EverArt](https://github.com/modelcontextprotocol/servers/tree/main/src/everart)
- [Sequential Thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking)
- [AWS KB Retrieval](https://github.com/modelcontextprotocol/servers/tree/main/src/aws-kb-retrieval-server)
- [Axiom](https://github.com/axiomhq/mcp-server-axiom)
- [Browserbase](https://github.com/browserbase/mcp-server-browserbase)
- [Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)
- [E2B](https://github.com/e2b-dev/mcp-server)
- [Neon](https://github.com/neondatabase/mcp-server-neon)
- [Obsidian Markdown Notes](https://github.com/calclavia/mcp-obsidian)
- [Qdrant](https://github.com/qdrant/mcp-server-qdrant/)
- [Raygun](https://github.com/MindscapeHQ/mcp-server-raygun)
- [Search1API](https://github.com/fatwang2/search1api-mcp)
- [Stripe](https://github.com/stripe/agent-toolkit)
- [Tinybird](https://github.com/tinybirdco/mcp-tinybird)
- [Docker](https://github.com/ckreiling/mcp-server-docker)
- [Kubernetes](https://github.com/Flux159/mcp-server-kubernetes)
- [Linear](https://github.com/jerhadf/linear-mcp-server)
- [Snowflake](https://github.com/datawiz168/mcp-snowflake-service)
- [Spotify](https://github.com/varunneal/spotify-mcp)
- [Todoist](https://github.com/abhiz123/todoist-mcp-server)

--- context/mcp-protocol-spec.txt ---
Directory Structure:

└── ./
    ├── docs
    │   ├── resources
    │   │   └── _index.md
    │   └── specification
    │       ├── 2024-11-05
    │       │   ├── architecture
    │       │   │   └── _index.md
    │       │   ├── basic
    │       │   │   ├── utilities
    │       │   │   │   ├── _index.md
    │       │   │   │   ├── cancellation.md
    │       │   │   │   ├── ping.md
    │       │   │   │   └── progress.md
    │       │   │   ├── _index.md
    │       │   │   ├── lifecycle.md
    │       │   │   ├── messages.md
    │       │   │   └── transports.md
    │       │   ├── client
    │       │   │   ├── _index.md
    │       │   │   ├── roots.md
    │       │   │   └── sampling.md
    │       │   ├── server
    │       │   │   ├── utilities
    │       │   │   │   ├── _index.md
    │       │   │   │   ├── completion.md
    │       │   │   │   ├── logging.md
    │       │   │   │   └── pagination.md
    │       │   │   ├── _index.md
    │       │   │   ├── prompts.md
    │       │   │   ├── resource-picker.png
    │       │   │   ├── resources.md
    │       │   │   ├── slash-command.png
    │       │   │   └── tools.md
    │       │   └── _index.md
    │       ├── 2025-03-26
    │       │   ├── architecture
    │       │   │   └── _index.md
    │       │   ├── basic
    │       │   │   ├── utilities
    │       │   │   │   ├── _index.md
    │       │   │   │   ├── cancellation.md
    │       │   │   │   ├── ping.md
    │       │   │   │   └── progress.md
    │       │   │   ├── _index.md
    │       │   │   ├── authorization.md
    │       │   │   ├── lifecycle.md
    │       │   │   └── transports.md
    │       │   ├── client
    │       │   │   ├── _index.md
    │       │   │   ├── roots.md
    │       │   │   └── sampling.md
    │       │   ├── server
    │       │   │   ├── utilities
    │       │   │   │   ├── _index.md
    │       │   │   │   ├── completion.md
    │       │   │   │   ├── logging.md
    │       │   │   │   └── pagination.md
    │       │   │   ├── _index.md
    │       │   │   ├── prompts.md
    │       │   │   ├── resource-picker.png
    │       │   │   ├── resources.md
    │       │   │   ├── slash-command.png
    │       │   │   └── tools.md
    │       │   ├── _index.md
    │       │   └── changelog.md
    │       ├── _index.md
    │       ├── contributing.md
    │       └── versioning.md
    ├── schema
    │   ├── 2024-11-05
    │   │   └── schema.ts
    │   └── 2025-03-26
    │       └── schema.ts
    ├── scripts
    │   └── validate_examples.ts
    ├── site
    │   └── layouts
    │       └── index.html
    └── README.md



---
File: /docs/resources/_index.md
---

---
title: "Additional Resources"
weight: 20
breadcrumbs: false
sidebar:
  exclude: true
---

The Model Context Protocol (MCP) provides multiple resources for documentation and
implementation:

- **User Documentation**: Visit
  [modelcontextprotocol.io](https://modelcontextprotocol.io) for comprehensive
  user-facing documentation
- **Python SDK**: The Python implementation is available at
  [github.com/modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk) -
  [Issues](https://github.com/modelcontextprotocol/python-sdk/issues)
- **Specification**: The core specification is available at
  [github.com/modelcontextprotocol/specification](https://github.com/modelcontextprotocol/specification) -
  [Discussions](https://github.com/modelcontextprotocol/specification/discussions)
- **TypeScript SDK**: The TypeScript implementation can be found at
  [github.com/modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk) -
  [Issues](https://github.com/modelcontextprotocol/typescript-sdk/issues)

For questions or discussions, please open a discussion in the appropriate GitHub
repository based on your implementation or use case. You can also visit the
[Model Context Protocol organization on GitHub](https://github.com/modelcontextprotocol)
to see all repositories and ongoing development.



---
File: /docs/specification/2024-11-05/architecture/_index.md
---

---
title: Architecture
cascade:
  type: docs
weight: 1
---

The Model Context Protocol (MCP) follows a client-host-server architecture where each
host can run multiple client instances. This architecture enables users to integrate AI
capabilities across applications while maintaining clear security boundaries and
isolating concerns. Built on JSON-RPC, MCP provides a stateful session protocol focused
on context exchange and sampling coordination between clients and servers.

## Core Components

```mermaid
graph LR
    subgraph "Application Host Process"
        H[Host]
        C1[Client 1]
        C2[Client 2]
        C3[Client 3]
        H --> C1
        H --> C2
        H --> C3
    end

    subgraph "Local machine"
        S1[Server 1<br>Files & Git]
        S2[Server 2<br>Database]
        R1[("Local<br>Resource A")]
        R2[("Local<br>Resource B")]

        C1 --> S1
        C2 --> S2
        S1 <--> R1
        S2 <--> R2
    end

    subgraph "Internet"
        S3[Server 3<br>External APIs]
        R3[("Remote<br>Resource C")]

        C3 --> S3
        S3 <--> R3
    end
```

### Host

The host process acts as the container and coordinator:

- Creates and manages multiple client instances
- Controls client connection permissions and lifecycle
- Enforces security policies and consent requirements
- Handles user authorization decisions
- Coordinates AI/LLM integration and sampling
- Manages context aggregation across clients

### Clients

Each client is created by the host and maintains an isolated server connection:

- Establishes one stateful session per server
- Handles protocol negotiation and capability exchange
- Routes protocol messages bidirectionally
- Manages subscriptions and notifications
- Maintains security boundaries between servers

A host application creates and manages multiple clients, with each client having a 1:1
relationship with a particular server.

### Servers

Servers provide specialized context and capabilities:

- Expose resources, tools and prompts via MCP primitives
- Operate independently with focused responsibilities
- Request sampling through client interfaces
- Must respect security constraints
- Can be local processes or remote services

## Design Principles

MCP is built on several key design principles that inform its architecture and
implementation:

1. **Servers should be extremely easy to build**

   - Host applications handle complex orchestration responsibilities
   - Servers focus on specific, well-defined capabilities
   - Simple interfaces minimize implementation overhead
   - Clear separation enables maintainable code

2. **Servers should be highly composable**

   - Each server provides focused functionality in isolation
   - Multiple servers can be combined seamlessly
   - Shared protocol enables interoperability
   - Modular design supports extensibility

3. **Servers should not be able to read the whole conversation, nor "see into" other
   servers**

   - Servers receive only necessary contextual information
   - Full conversation history stays with the host
   - Each server connection maintains isolation
   - Cross-server interactions are controlled by the host
   - Host process enforces security boundaries

4. **Features can be added to servers and clients progressively**
   - Core protocol provides minimal required functionality
   - Additional capabilities can be negotiated as needed
   - Servers and clients evolve independently
   - Protocol designed for future extensibility
   - Backwards compatibility is maintained

## Message Types

MCP defines three core message types based on
[JSON-RPC 2.0](https://www.jsonrpc.org/specification):

- **Requests**: Bidirectional messages with method and parameters expecting a response
- **Responses**: Successful results or errors matching specific request IDs
- **Notifications**: One-way messages requiring no response

Each message type follows the JSON-RPC 2.0 specification for structure and delivery
semantics.

## Capability Negotiation

The Model Context Protocol uses a capability-based negotiation system where clients and
servers explicitly declare their supported features during initialization. Capabilities
determine which protocol features and primitives are available during a session.

- Servers declare capabilities like resource subscriptions, tool support, and prompt
  templates
- Clients declare capabilities like sampling support and notification handling
- Both parties must respect declared capabilities throughout the session
- Additional capabilities can be negotiated through extensions to the protocol

```mermaid
sequenceDiagram
    participant Host
    participant Client
    participant Server

    Host->>+Client: Initialize client
    Client->>+Server: Initialize session with capabilities
    Server-->>Client: Respond with supported capabilities

    Note over Host,Server: Active Session with Negotiated Features

    loop Client Requests
        Host->>Client: User- or model-initiated action
        Client->>Server: Request (tools/resources)
        Server-->>Client: Response
        Client-->>Host: Update UI or respond to model
    end

    loop Server Requests
        Server->>Client: Request (sampling)
        Client->>Host: Forward to AI
        Host-->>Client: AI response
        Client-->>Server: Response
    end

    loop Notifications
        Server--)Client: Resource updates
        Client--)Server: Status changes
    end

    Host->>Client: Terminate
    Client->>-Server: End session
    deactivate Server
```

Each capability unlocks specific protocol features for use during the session. For
example:

- Implemented [server features]({{< ref "/specification/2024-11-05/server" >}}) must be
  advertised in the server's capabilities
- Emitting resource subscription notifications requires the server to declare
  subscription support
- Tool invocation requires the server to declare tool capabilities
- [Sampling]({{< ref "/specification/2024-11-05/client" >}}) requires the client to
  declare support in its capabilities

This capability negotiation ensures clients and servers have a clear understanding of
supported functionality while maintaining protocol extensibility.



---
File: /docs/specification/2024-11-05/basic/utilities/_index.md
---

---
title: Utilities
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

These optional features enhance the base protocol functionality with various utilities.

{{< cards >}} {{< card link="ping" title="Ping" icon="status-online" >}}
{{< card link="cancellation" title="Cancellation" icon="x" >}}
{{< card link="progress" title="Progress" icon="clock" >}} {{< /cards >}}



---
File: /docs/specification/2024-11-05/basic/utilities/cancellation.md
---

---
title: Cancellation
weight: 10
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) supports optional cancellation of in-progress requests
through notification messages. Either side can send a cancellation notification to
indicate that a previously-issued request should be terminated.

## Cancellation Flow

When a party wants to cancel an in-progress request, it sends a `notifications/cancelled`
notification containing:

- The ID of the request to cancel
- An optional reason string that can be logged or displayed

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": "123",
    "reason": "User requested cancellation"
  }
}
```

## Behavior Requirements

1. Cancellation notifications **MUST** only reference requests that:
   - Were previously issued in the same direction
   - Are believed to still be in-progress
2. The `initialize` request **MUST NOT** be cancelled by clients
3. Receivers of cancellation notifications **SHOULD**:
   - Stop processing the cancelled request
   - Free associated resources
   - Not send a response for the cancelled request
4. Receivers **MAY** ignore cancellation notifications if:
   - The referenced request is unknown
   - Processing has already completed
   - The request cannot be cancelled
5. The sender of the cancellation notification **SHOULD** ignore any response to the
   request that arrives afterward

## Timing Considerations

Due to network latency, cancellation notifications may arrive after request processing
has completed, and potentially after a response has already been sent.

Both parties **MUST** handle these race conditions gracefully:

```mermaid
sequenceDiagram
   participant Client
   participant Server

   Client->>Server: Request (ID: 123)
   Note over Server: Processing starts
   Client--)Server: notifications/cancelled (ID: 123)
   alt
      Note over Server: Processing may have<br/>completed before<br/>cancellation arrives
   else If not completed
      Note over Server: Stop processing
   end
```

## Implementation Notes

- Both parties **SHOULD** log cancellation reasons for debugging
- Application UIs **SHOULD** indicate when cancellation is requested

## Error Handling

Invalid cancellation notifications **SHOULD** be ignored:

- Unknown request IDs
- Already completed requests
- Malformed notifications

This maintains the "fire and forget" nature of notifications while allowing for race
conditions in asynchronous communication.



---
File: /docs/specification/2024-11-05/basic/utilities/ping.md
---

---
title: Ping
weight: 5
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol includes an optional ping mechanism that allows either party
to verify that their counterpart is still responsive and the connection is alive.

## Overview

The ping functionality is implemented through a simple request/response pattern. Either
the client or server can initiate a ping by sending a `ping` request.

## Message Format

A ping request is a standard JSON-RPC request with no parameters:

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "method": "ping"
}
```

## Behavior Requirements

1. The receiver **MUST** respond promptly with an empty response:

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "result": {}
}
```

2. If no response is received within a reasonable timeout period, the sender **MAY**:
   - Consider the connection stale
   - Terminate the connection
   - Attempt reconnection procedures

## Usage Patterns

```mermaid
sequenceDiagram
    participant Sender
    participant Receiver

    Sender->>Receiver: ping request
    Receiver->>Sender: empty response
```

## Implementation Considerations

- Implementations **SHOULD** periodically issue pings to detect connection health
- The frequency of pings **SHOULD** be configurable
- Timeouts **SHOULD** be appropriate for the network environment
- Excessive pinging **SHOULD** be avoided to reduce network overhead

## Error Handling

- Timeouts **SHOULD** be treated as connection failures
- Multiple failed pings **MAY** trigger connection reset
- Implementations **SHOULD** log ping failures for diagnostics



---
File: /docs/specification/2024-11-05/basic/utilities/progress.md
---

---
title: Progress
weight: 30
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) supports optional progress tracking for long-running
operations through notification messages. Either side can send progress notifications to
provide updates about operation status.

## Progress Flow

When a party wants to _receive_ progress updates for a request, it includes a
`progressToken` in the request metadata.

- Progress tokens **MUST** be a string or integer value
- Progress tokens can be chosen by the sender using any means, but **MUST** be unique
  across all active requests.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "some_method",
  "params": {
    "_meta": {
      "progressToken": "abc123"
    }
  }
}
```

The receiver **MAY** then send progress notifications containing:

- The original progress token
- The current progress value so far
- An optional "total" value

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/progress",
  "params": {
    "progressToken": "abc123",
    "progress": 50,
    "total": 100
  }
}
```

- The `progress` value **MUST** increase with each notification, even if the total is
  unknown.
- The `progress` and the `total` values **MAY** be floating point.

## Behavior Requirements

1. Progress notifications **MUST** only reference tokens that:

   - Were provided in an active request
   - Are associated with an in-progress operation

2. Receivers of progress requests **MAY**:
   - Choose not to send any progress notifications
   - Send notifications at whatever frequency they deem appropriate
   - Omit the total value if unknown

```mermaid
sequenceDiagram
    participant Sender
    participant Receiver

    Note over Sender,Receiver: Request with progress token
    Sender->>Receiver: Method request with progressToken

    Note over Sender,Receiver: Progress updates
    loop Progress Updates
        Receiver-->>Sender: Progress notification (0.2/1.0)
        Receiver-->>Sender: Progress notification (0.6/1.0)
        Receiver-->>Sender: Progress notification (1.0/1.0)
    end

    Note over Sender,Receiver: Operation complete
    Receiver->>Sender: Method response
```

## Implementation Notes

- Senders and receivers **SHOULD** track active progress tokens
- Both parties **SHOULD** implement rate limiting to prevent flooding
- Progress notifications **MUST** stop after completion



---
File: /docs/specification/2024-11-05/basic/_index.md
---

---
title: Base Protocol
cascade:
  type: docs
weight: 2
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

All messages between MCP clients and servers **MUST** follow the
[JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. The protocol defines
three fundamental types of messages:

| Type            | Description                            | Requirements                           |
| --------------- | -------------------------------------- | -------------------------------------- |
| `Requests`      | Messages sent to initiate an operation | Must include unique ID and method name |
| `Responses`     | Messages sent in reply to requests     | Must include same ID as request        |
| `Notifications` | One-way messages with no reply         | Must not include an ID                 |

**Responses** are further sub-categorized as either **successful results** or **errors**.
Results can follow any JSON object structure, while errors must include an error code and
message at minimum.

## Protocol Layers

The Model Context Protocol consists of several key components that work together:

- **Base Protocol**: Core JSON-RPC message types
- **Lifecycle Management**: Connection initialization, capability negotiation, and
  session control
- **Server Features**: Resources, prompts, and tools exposed by servers
- **Client Features**: Sampling and root directory lists provided by clients
- **Utilities**: Cross-cutting concerns like logging and argument completion

All implementations **MUST** support the base protocol and lifecycle management
components. Other components **MAY** be implemented based on the specific needs of the
application.

These protocol layers establish clear separation of concerns while enabling rich
interactions between clients and servers. The modular design allows implementations to
support exactly the features they need.

See the following pages for more details on the different components:

{{< cards >}}
{{< card link="/specification/2024-11-05/basic/lifecycle" title="Lifecycle" icon="refresh" >}}
{{< card link="/specification/2024-11-05/server/resources" title="Resources" icon="document" >}}
{{< card link="/specification/2024-11-05/server/prompts" title="Prompts" icon="chat-alt-2" >}}
{{< card link="/specification/2024-11-05/server/tools" title="Tools" icon="adjustments" >}}
{{< card link="/specification/2024-11-05/server/utilities/logging" title="Logging" icon="annotation" >}}
{{< card link="/specification/2024-11-05/client/sampling" title="Sampling" icon="code" >}}
{{< /cards >}}

## Auth

Authentication and authorization are not currently part of the core MCP specification,
but we are considering ways to introduce them in future. Join us in
[GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions)
to help shape the future of the protocol!

Clients and servers **MAY** negotiate their own custom authentication and authorization
strategies.

## Schema

The full specification of the protocol is defined as a
[TypeScript schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.ts).
This is the source of truth for all protocol messages and structures.

There is also a
[JSON Schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.json),
which is automatically generated from the TypeScript source of truth, for use with
various automated tooling.



---
File: /docs/specification/2024-11-05/basic/lifecycle.md
---

---
title: Lifecycle
type: docs
weight: 30
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) defines a rigorous lifecycle for client-server
connections that ensures proper capability negotiation and state management.

1. **Initialization**: Capability negotiation and protocol version agreement
2. **Operation**: Normal protocol communication
3. **Shutdown**: Graceful termination of the connection

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Initialization Phase
    activate Client
    Client->>+Server: initialize request
    Server-->>Client: initialize response
    Client--)Server: initialized notification

    Note over Client,Server: Operation Phase
    rect rgb(200, 220, 250)
        note over Client,Server: Normal protocol operations
    end

    Note over Client,Server: Shutdown
    Client--)-Server: Disconnect
    deactivate Server
    Note over Client,Server: Connection closed
```

## Lifecycle Phases

### Initialization

The initialization phase **MUST** be the first interaction between client and server.
During this phase, the client and server:

- Establish protocol version compatibility
- Exchange and negotiate capabilities
- Share implementation details

The client **MUST** initiate this phase by sending an `initialize` request containing:

- Protocol version supported
- Client capabilities
- Client implementation information

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "roots": {
        "listChanged": true
      },
      "sampling": {}
    },
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

The server **MUST** respond with its own capabilities and information:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "logging": {},
      "prompts": {
        "listChanged": true
      },
      "resources": {
        "subscribe": true,
        "listChanged": true
      },
      "tools": {
        "listChanged": true
      }
    },
    "serverInfo": {
      "name": "ExampleServer",
      "version": "1.0.0"
    }
  }
}
```

After successful initialization, the client **MUST** send an `initialized` notification
to indicate it is ready to begin normal operations:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
```

- The client **SHOULD NOT** send requests other than
  [pings]({{< ref "/specification/2024-11-05/basic/utilities/ping" >}}) before the server
  has responded to the `initialize` request.
- The server **SHOULD NOT** send requests other than
  [pings]({{< ref "/specification/2024-11-05/basic/utilities/ping" >}}) and
  [logging]({{< ref "/specification/2024-11-05/server/utilities/logging" >}}) before
  receiving the `initialized` notification.

#### Version Negotiation

In the `initialize` request, the client **MUST** send a protocol version it supports.
This **SHOULD** be the _latest_ version supported by the client.

If the server supports the requested protocol version, it **MUST** respond with the same
version. Otherwise, the server **MUST** respond with another protocol version it
supports. This **SHOULD** be the _latest_ version supported by the server.

If the client does not support the version in the server's response, it **SHOULD**
disconnect.

#### Capability Negotiation

Client and server capabilities establish which optional protocol features will be
available during the session.

Key capabilities include:

| Category | Capability     | Description                                                                                       |
| -------- | -------------- | ------------------------------------------------------------------------------------------------- |
| Client   | `roots`        | Ability to provide filesystem [roots]({{< ref "/specification/2024-11-05/client/roots" >}})       |
| Client   | `sampling`     | Support for LLM [sampling]({{< ref "/specification/2024-11-05/client/sampling" >}}) requests      |
| Client   | `experimental` | Describes support for non-standard experimental features                                          |
| Server   | `prompts`      | Offers [prompt templates]({{< ref "/specification/2024-11-05/server/prompts" >}})                 |
| Server   | `resources`    | Provides readable [resources]({{< ref "/specification/2024-11-05/server/resources" >}})           |
| Server   | `tools`        | Exposes callable [tools]({{< ref "/specification/2024-11-05/server/tools" >}})                    |
| Server   | `logging`      | Emits structured [log messages]({{< ref "/specification/2024-11-05/server/utilities/logging" >}}) |
| Server   | `experimental` | Describes support for non-standard experimental features                                          |

Capability objects can describe sub-capabilities like:

- `listChanged`: Support for list change notifications (for prompts, resources, and
  tools)
- `subscribe`: Support for subscribing to individual items' changes (resources only)

### Operation

During the operation phase, the client and server exchange messages according to the
negotiated capabilities.

Both parties **SHOULD**:

- Respect the negotiated protocol version
- Only use capabilities that were successfully negotiated

### Shutdown

During the shutdown phase, one side (usually the client) cleanly terminates the protocol
connection. No specific shutdown messages are defined—instead, the underlying transport
mechanism should be used to signal connection termination:

#### stdio

For the stdio [transport]({{< ref "/specification/2024-11-05/basic/transports" >}}), the
client **SHOULD** initiate shutdown by:

1. First, closing the input stream to the child process (the server)
2. Waiting for the server to exit, or sending `SIGTERM` if the server does not exit
   within a reasonable time
3. Sending `SIGKILL` if the server does not exit within a reasonable time after `SIGTERM`

The server **MAY** initiate shutdown by closing its output stream to the client and
exiting.

#### HTTP

For HTTP [transports]({{< ref "/specification/2024-11-05/basic/transports" >}}), shutdown
is indicated by closing the associated HTTP connection(s).

## Error Handling

Implementations **SHOULD** be prepared to handle these error cases:

- Protocol version mismatch
- Failure to negotiate required capabilities
- Initialize request timeout
- Shutdown timeout

Implementations **SHOULD** implement appropriate timeouts for all requests, to prevent
hung connections and resource exhaustion.

Example initialization error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Unsupported protocol version",
    "data": {
      "supported": ["2024-11-05"],
      "requested": "1.0.0"
    }
  }
}
```



---
File: /docs/specification/2024-11-05/basic/messages.md
---

---
title: Messages
type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

All messages in MCP **MUST** follow the
[JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. The protocol defines
three types of messages:

## Requests

Requests are sent from the client to the server or vice versa.

```typescript
{
  jsonrpc: "2.0";
  id: string | number;
  method: string;
  params?: {
    [key: string]: unknown;
  };
}
```

- Requests **MUST** include a string or integer ID.
- Unlike base JSON-RPC, the ID **MUST NOT** be `null`.
- The request ID **MUST NOT** have been previously used by the requestor within the same
  session.

## Responses

Responses are sent in reply to requests.

```typescript
{
  jsonrpc: "2.0";
  id: string | number;
  result?: {
    [key: string]: unknown;
  }
  error?: {
    code: number;
    message: string;
    data?: unknown;
  }
}
```

- Responses **MUST** include the same ID as the request they correspond to.
- Either a `result` or an `error` **MUST** be set. A response **MUST NOT** set both.
- Error codes **MUST** be integers.

## Notifications

Notifications are sent from the client to the server or vice versa. They do not expect a
response.

```typescript
{
  jsonrpc: "2.0";
  method: string;
  params?: {
    [key: string]: unknown;
  };
}
```

- Notifications **MUST NOT** include an ID.



---
File: /docs/specification/2024-11-05/basic/transports.md
---

---
title: Transports
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

MCP currently defines two standard transport mechanisms for client-server communication:

1. [stdio](#stdio), communication over standard in and standard out
2. [HTTP with Server-Sent Events](#http-with-sse) (SSE)

Clients **SHOULD** support stdio whenever possible.

It is also possible for clients and servers to implement
[custom transports](#custom-transports) in a pluggable fashion.

## stdio

In the **stdio** transport:

- The client launches the MCP server as a subprocess.
- The server receives JSON-RPC messages on its standard input (`stdin`) and writes
  responses to its standard output (`stdout`).
- Messages are delimited by newlines, and **MUST NOT** contain embedded newlines.
- The server **MAY** write UTF-8 strings to its standard error (`stderr`) for logging
  purposes. Clients **MAY** capture, forward, or ignore this logging.
- The server **MUST NOT** write anything to its `stdout` that is not a valid MCP message.
- The client **MUST NOT** write anything to the server's `stdin` that is not a valid MCP
  message.

```mermaid
sequenceDiagram
    participant Client
    participant Server Process

    Client->>+Server Process: Launch subprocess
    loop Message Exchange
        Client->>Server Process: Write to stdin
        Server Process->>Client: Write to stdout
        Server Process--)Client: Optional logs on stderr
    end
    Client->>Server Process: Close stdin, terminate subprocess
    deactivate Server Process
```

## HTTP with SSE

In the **SSE** transport, the server operates as an independent process that can handle
multiple client connections.

The server **MUST** provide two endpoints:

1. An SSE endpoint, for clients to establish a connection and receive messages from the
   server
2. A regular HTTP POST endpoint for clients to send messages to the server

When a client connects, the server **MUST** send an `endpoint` event containing a URI for
the client to use for sending messages. All subsequent client messages **MUST** be sent
as HTTP POST requests to this endpoint.

Server messages are sent as SSE `message` events, with the message content encoded as
JSON in the event data.

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Open SSE connection
    Server->>Client: endpoint event
    loop Message Exchange
        Client->>Server: HTTP POST messages
        Server->>Client: SSE message events
    end
    Client->>Server: Close SSE connection
```

## Custom Transports

Clients and servers **MAY** implement additional custom transport mechanisms to suit
their specific needs. The protocol is transport-agnostic and can be implemented over any
communication channel that supports bidirectional message exchange.

Implementers who choose to support custom transports **MUST** ensure they preserve the
JSON-RPC message format and lifecycle requirements defined by MCP. Custom transports
**SHOULD** document their specific connection establishment and message exchange patterns
to aid interoperability.



---
File: /docs/specification/2024-11-05/client/_index.md
---

---
title: Client Features
cascade:
  type: docs
weight: 4
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

Clients can implement additional features to enrich connected MCP servers:

{{< cards >}} {{< card link="roots" title="Roots" icon="folder" >}}
{{< card link="sampling" title="Sampling" icon="annotation" >}} {{< /cards >}}



---
File: /docs/specification/2024-11-05/client/roots.md
---

---
title: Roots
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for clients to expose
filesystem "roots" to servers. Roots define the boundaries of where servers can operate
within the filesystem, allowing them to understand which directories and files they have
access to. Servers can request the list of roots from supporting clients and receive
notifications when that list changes.

## User Interaction Model

Roots in MCP are typically exposed through workspace or project configuration interfaces.

For example, implementations could offer a workspace/project picker that allows users to
select directories and files the server should have access to. This can be combined with
automatic workspace detection from version control systems or project files.

However, implementations are free to expose roots through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Capabilities

Clients that support roots **MUST** declare the `roots` capability during
[initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):

```json
{
  "capabilities": {
    "roots": {
      "listChanged": true
    }
  }
}
```

`listChanged` indicates whether the client will emit notifications when the list of roots
changes.

## Protocol Messages

### Listing Roots

To retrieve roots, servers send a `roots/list` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "roots/list"
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "roots": [
      {
        "uri": "file:///home/user/projects/myproject",
        "name": "My Project"
      }
    ]
  }
}
```

### Root List Changes

When roots change, clients that support `listChanged` **MUST** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/roots/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Server
    participant Client

    Note over Server,Client: Discovery
    Server->>Client: roots/list
    Client-->>Server: Available roots

    Note over Server,Client: Changes
    Client--)Server: notifications/roots/list_changed
    Server->>Client: roots/list
    Client-->>Server: Updated roots
```

## Data Types

### Root

A root definition includes:

- `uri`: Unique identifier for the root. This **MUST** be a `file://` URI in the current
  specification.
- `name`: Optional human-readable name for display purposes.

Example roots for different use cases:

#### Project Directory

```json
{
  "uri": "file:///home/user/projects/myproject",
  "name": "My Project"
}
```

#### Multiple Repositories

```json
[
  {
    "uri": "file:///home/user/repos/frontend",
    "name": "Frontend Repository"
  },
  {
    "uri": "file:///home/user/repos/backend",
    "name": "Backend Repository"
  }
]
```

## Error Handling

Clients **SHOULD** return standard JSON-RPC errors for common failure cases:

- Client does not support roots: `-32601` (Method not found)
- Internal errors: `-32603`

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Roots not supported",
    "data": {
      "reason": "Client does not have roots capability"
    }
  }
}
```

## Security Considerations

1. Clients **MUST**:

   - Only expose roots with appropriate permissions
   - Validate all root URIs to prevent path traversal
   - Implement proper access controls
   - Monitor root accessibility

2. Servers **SHOULD**:
   - Handle cases where roots become unavailable
   - Respect root boundaries during operations
   - Validate all paths against provided roots

## Implementation Guidelines

1. Clients **SHOULD**:

   - Prompt users for consent before exposing roots to servers
   - Provide clear user interfaces for root management
   - Validate root accessibility before exposing
   - Monitor for root changes

2. Servers **SHOULD**:
   - Check for roots capability before usage
   - Handle root list changes gracefully
   - Respect root boundaries in operations
   - Cache root information appropriately



---
File: /docs/specification/2024-11-05/client/sampling.md
---

---
title: Sampling
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to request LLM
sampling ("completions" or "generations") from language models via clients. This flow
allows clients to maintain control over model access, selection, and permissions while
enabling servers to leverage AI capabilities&mdash;with no server API keys necessary.
Servers can request text or image-based interactions and optionally include context from
MCP servers in their prompts.

## User Interaction Model

Sampling in MCP allows servers to implement agentic behaviors, by enabling LLM calls to
occur _nested_ inside other MCP server features.

Implementations are free to expose sampling through any interface pattern that suits
their needs&mdash;the protocol itself does not mandate any specific user interaction
model.

{{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
be a human in the loop with the ability to deny sampling requests.

Applications **SHOULD**:

- Provide UI that makes it easy and intuitive to review sampling requests
- Allow users to view and edit prompts before sending
- Present generated responses for review before delivery {{< /callout >}}

## Capabilities

Clients that support sampling **MUST** declare the `sampling` capability during
[initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):

```json
{
  "capabilities": {
    "sampling": {}
  }
}
```

## Protocol Messages

### Creating Messages

To request a language model generation, servers send a `sampling/createMessage` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "What is the capital of France?"
        }
      }
    ],
    "modelPreferences": {
      "hints": [
        {
          "name": "claude-3-sonnet"
        }
      ],
      "intelligencePriority": 0.8,
      "speedPriority": 0.5
    },
    "systemPrompt": "You are a helpful assistant.",
    "maxTokens": 100
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "role": "assistant",
    "content": {
      "type": "text",
      "text": "The capital of France is Paris."
    },
    "model": "claude-3-sonnet-20240307",
    "stopReason": "endTurn"
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Server
    participant Client
    participant User
    participant LLM

    Note over Server,Client: Server initiates sampling
    Server->>Client: sampling/createMessage

    Note over Client,User: Human-in-the-loop review
    Client->>User: Present request for approval
    User-->>Client: Review and approve/modify

    Note over Client,LLM: Model interaction
    Client->>LLM: Forward approved request
    LLM-->>Client: Return generation

    Note over Client,User: Response review
    Client->>User: Present response for approval
    User-->>Client: Review and approve/modify

    Note over Server,Client: Complete request
    Client-->>Server: Return approved response
```

## Data Types

### Messages

Sampling messages can contain:

#### Text Content

```json
{
  "type": "text",
  "text": "The message content"
}
```

#### Image Content

```json
{
  "type": "image",
  "data": "base64-encoded-image-data",
  "mimeType": "image/jpeg"
}
```

### Model Preferences

Model selection in MCP requires careful abstraction since servers and clients may use
different AI providers with distinct model offerings. A server cannot simply request a
specific model by name since the client may not have access to that exact model or may
prefer to use a different provider's equivalent model.

To solve this, MCP implements a preference system that combines abstract capability
priorities with optional model hints:

#### Capability Priorities

Servers express their needs through three normalized priority values (0-1):

- `costPriority`: How important is minimizing costs? Higher values prefer cheaper models.
- `speedPriority`: How important is low latency? Higher values prefer faster models.
- `intelligencePriority`: How important are advanced capabilities? Higher values prefer
  more capable models.

#### Model Hints

While priorities help select models based on characteristics, `hints` allow servers to
suggest specific models or model families:

- Hints are treated as substrings that can match model names flexibly
- Multiple hints are evaluated in order of preference
- Clients **MAY** map hints to equivalent models from different providers
- Hints are advisory&mdash;clients make final model selection

For example:

```json
{
  "hints": [
    { "name": "claude-3-sonnet" }, // Prefer Sonnet-class models
    { "name": "claude" } // Fall back to any Claude model
  ],
  "costPriority": 0.3, // Cost is less important
  "speedPriority": 0.8, // Speed is very important
  "intelligencePriority": 0.5 // Moderate capability needs
}
```

The client processes these preferences to select an appropriate model from its available
options. For instance, if the client doesn't have access to Claude models but has Gemini,
it might map the sonnet hint to `gemini-1.5-pro` based on similar capabilities.

## Error Handling

Clients **SHOULD** return errors for common failure cases:

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -1,
    "message": "User rejected sampling request"
  }
}
```

## Security Considerations

1. Clients **SHOULD** implement user approval controls
2. Both parties **SHOULD** validate message content
3. Clients **SHOULD** respect model preference hints
4. Clients **SHOULD** implement rate limiting
5. Both parties **MUST** handle sensitive data appropriately



---
File: /docs/specification/2024-11-05/server/utilities/_index.md
---

---
title: Utilities
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

These optional features can be used to enhance server functionality.

{{< cards >}} {{< card link="completion" title="Completion" icon="at-symbol" >}}
{{< card link="logging" title="Logging" icon="terminal" >}}
{{< card link="pagination" title="Pagination" icon="collection" >}} {{< /cards >}}



---
File: /docs/specification/2024-11-05/server/utilities/completion.md
---

---
title: Completion
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to offer
argument autocompletion suggestions for prompts and resource URIs. This enables rich,
IDE-like experiences where users receive contextual suggestions while entering argument
values.

## User Interaction Model

Completion in MCP is designed to support interactive user experiences similar to IDE code
completion.

For example, applications may show completion suggestions in a dropdown or popup menu as
users type, with the ability to filter and select from available options.

However, implementations are free to expose completion through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Protocol Messages

### Requesting Completions

To get completion suggestions, clients send a `completion/complete` request specifying
what is being completed through a reference type:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/prompt",
      "name": "code_review"
    },
    "argument": {
      "name": "language",
      "value": "py"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "completion": {
      "values": ["python", "pytorch", "pyside"],
      "total": 10,
      "hasMore": true
    }
  }
}
```

### Reference Types

The protocol supports two types of completion references:

| Type           | Description                 | Example                                             |
| -------------- | --------------------------- | --------------------------------------------------- |
| `ref/prompt`   | References a prompt by name | `{"type": "ref/prompt", "name": "code_review"}`     |
| `ref/resource` | References a resource URI   | `{"type": "ref/resource", "uri": "file:///{path}"}` |

### Completion Results

Servers return an array of completion values ranked by relevance, with:

- Maximum 100 items per response
- Optional total number of available matches
- Boolean indicating if additional results exist

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client: User types argument
    Client->>Server: completion/complete
    Server-->>Client: Completion suggestions

    Note over Client: User continues typing
    Client->>Server: completion/complete
    Server-->>Client: Refined suggestions
```

## Data Types

### CompleteRequest

- `ref`: A `PromptReference` or `ResourceReference`
- `argument`: Object containing:
  - `name`: Argument name
  - `value`: Current value

### CompleteResult

- `completion`: Object containing:
  - `values`: Array of suggestions (max 100)
  - `total`: Optional total matches
  - `hasMore`: Additional results flag

## Implementation Considerations

1. Servers **SHOULD**:

   - Return suggestions sorted by relevance
   - Implement fuzzy matching where appropriate
   - Rate limit completion requests
   - Validate all inputs

2. Clients **SHOULD**:
   - Debounce rapid completion requests
   - Cache completion results where appropriate
   - Handle missing or partial results gracefully

## Security

Implementations **MUST**:

- Validate all completion inputs
- Implement appropriate rate limiting
- Control access to sensitive suggestions
- Prevent completion-based information disclosure



---
File: /docs/specification/2024-11-05/server/utilities/logging.md
---

---
title: Logging
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to send
structured log messages to clients. Clients can control logging verbosity by setting
minimum log levels, with servers sending notifications containing severity levels,
optional logger names, and arbitrary JSON-serializable data.

## User Interaction Model

Implementations are free to expose logging through any interface pattern that suits their
needs&mdash;the protocol itself does not mandate any specific user interaction model.

## Capabilities

Servers that emit log message notifications **MUST** declare the `logging` capability:

```json
{
  "capabilities": {
    "logging": {}
  }
}
```

## Log Levels

The protocol follows the standard syslog severity levels specified in
[RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1):

| Level     | Description                      | Example Use Case           |
| --------- | -------------------------------- | -------------------------- |
| debug     | Detailed debugging information   | Function entry/exit points |
| info      | General informational messages   | Operation progress updates |
| notice    | Normal but significant events    | Configuration changes      |
| warning   | Warning conditions               | Deprecated feature usage   |
| error     | Error conditions                 | Operation failures         |
| critical  | Critical conditions              | System component failures  |
| alert     | Action must be taken immediately | Data corruption detected   |
| emergency | System is unusable               | Complete system failure    |

## Protocol Messages

### Setting Log Level

To configure the minimum log level, clients **MAY** send a `logging/setLevel` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logging/setLevel",
  "params": {
    "level": "info"
  }
}
```

### Log Message Notifications

Servers send log messages using `notifications/message` notifications:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/message",
  "params": {
    "level": "error",
    "logger": "database",
    "data": {
      "error": "Connection failed",
      "details": {
        "host": "localhost",
        "port": 5432
      }
    }
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Configure Logging
    Client->>Server: logging/setLevel (info)
    Server-->>Client: Empty Result

    Note over Client,Server: Server Activity
    Server--)Client: notifications/message (info)
    Server--)Client: notifications/message (warning)
    Server--)Client: notifications/message (error)

    Note over Client,Server: Level Change
    Client->>Server: logging/setLevel (error)
    Server-->>Client: Empty Result
    Note over Server: Only sends error level<br/>and above
```

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Invalid log level: `-32602` (Invalid params)
- Configuration errors: `-32603` (Internal error)

## Implementation Considerations

1. Servers **SHOULD**:

   - Rate limit log messages
   - Include relevant context in data field
   - Use consistent logger names
   - Remove sensitive information

2. Clients **MAY**:
   - Present log messages in the UI
   - Implement log filtering/search
   - Display severity visually
   - Persist log messages

## Security

1. Log messages **MUST NOT** contain:

   - Credentials or secrets
   - Personal identifying information
   - Internal system details that could aid attacks

2. Implementations **SHOULD**:
   - Rate limit messages
   - Validate all data fields
   - Control log access
   - Monitor for sensitive content



---
File: /docs/specification/2024-11-05/server/utilities/pagination.md
---

---
title: Pagination
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) supports paginating list operations that may return
large result sets. Pagination allows servers to yield results in smaller chunks rather
than all at once.

Pagination is especially important when connecting to external services over the
internet, but also useful for local integrations to avoid performance issues with large
data sets.

## Pagination Model

Pagination in MCP uses an opaque cursor-based approach, instead of numbered pages.

- The **cursor** is an opaque string token, representing a position in the result set
- **Page size** is determined by the server, and **MAY NOT** be fixed

## Response Format

Pagination starts when the server sends a **response** that includes:

- The current page of results
- An optional `nextCursor` field if more results exist

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "result": {
    "resources": [...],
    "nextCursor": "eyJwYWdlIjogM30="
  }
}
```

## Request Format

After receiving a cursor, the client can _continue_ paginating by issuing a request
including that cursor:

```json
{
  "jsonrpc": "2.0",
  "method": "resources/list",
  "params": {
    "cursor": "eyJwYWdlIjogMn0="
  }
}
```

## Pagination Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: List Request (no cursor)
    loop Pagination Loop
      Server-->>Client: Page of results + nextCursor
      Client->>Server: List Request (with cursor)
    end
```

## Operations Supporting Pagination

The following MCP operations support pagination:

- `resources/list` - List available resources
- `resources/templates/list` - List resource templates
- `prompts/list` - List available prompts
- `tools/list` - List available tools

## Implementation Guidelines

1. Servers **SHOULD**:

   - Provide stable cursors
   - Handle invalid cursors gracefully

2. Clients **SHOULD**:

   - Treat a missing `nextCursor` as the end of results
   - Support both paginated and non-paginated flows

3. Clients **MUST** treat cursors as opaque tokens:
   - Don't make assumptions about cursor format
   - Don't attempt to parse or modify cursors
   - Don't persist cursors across sessions

## Error Handling

Invalid cursors **SHOULD** result in an error with code -32602 (Invalid params).



---
File: /docs/specification/2024-11-05/server/_index.md
---

---
title: Server Features
cascade:
  type: docs
weight: 3
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

Servers provide the fundamental building blocks for adding context to language models via
MCP. These primitives enable rich interactions between clients, servers, and language
models:

- **Prompts**: Pre-defined templates or instructions that guide language model
  interactions
- **Resources**: Structured data or content that provides additional context to the model
- **Tools**: Executable functions that allow models to perform actions or retrieve
  information

Each primitive can be summarized in the following control hierarchy:

| Primitive | Control                | Description                                        | Example                         |
| --------- | ---------------------- | -------------------------------------------------- | ------------------------------- |
| Prompts   | User-controlled        | Interactive templates invoked by user choice       | Slash commands, menu options    |
| Resources | Application-controlled | Contextual data attached and managed by the client | File contents, git history      |
| Tools     | Model-controlled       | Functions exposed to the LLM to take actions       | API POST requests, file writing |

Explore these key primitives in more detail below:

{{< cards >}} {{< card link="prompts" title="Prompts" icon="chat-alt-2" >}}
{{< card link="resources" title="Resources" icon="document" >}}
{{< card link="tools" title="Tools" icon="adjustments" >}} {{< /cards >}}



---
File: /docs/specification/2024-11-05/server/prompts.md
---

---
title: Prompts
weight: 10
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose prompt
templates to clients. Prompts allow servers to provide structured messages and
instructions for interacting with language models. Clients can discover available
prompts, retrieve their contents, and provide arguments to customize them.

## User Interaction Model

Prompts are designed to be **user-controlled**, meaning they are exposed from servers to
clients with the intention of the user being able to explicitly select them for use.

Typically, prompts would be triggered through user-initiated commands in the user
interface, which allows users to naturally discover and invoke available prompts.

For example, as slash commands:

![Example of prompt exposed as slash command](slash-command.png)

However, implementors are free to expose prompts through any interface pattern that suits
their needs&mdash;the protocol itself does not mandate any specific user interaction
model.

## Capabilities

Servers that support prompts **MUST** declare the `prompts` capability during
[initialization]({{< ref "/specification/2024-11-05/basic/lifecycle#initialization" >}}):

```json
{
  "capabilities": {
    "prompts": {
      "listChanged": true
    }
  }
}
```

`listChanged` indicates whether the server will emit notifications when the list of
available prompts changes.

## Protocol Messages

### Listing Prompts

To retrieve available prompts, clients send a `prompts/list` request. This operation
supports
[pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "prompts/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "prompts": [
      {
        "name": "code_review",
        "description": "Asks the LLM to analyze code quality and suggest improvements",
        "arguments": [
          {
            "name": "code",
            "description": "The code to review",
            "required": true
          }
        ]
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Getting a Prompt

To retrieve a specific prompt, clients send a `prompts/get` request. Arguments may be
auto-completed through [the completion
API]({{< ref "/specification/2024-11-05/server/utilities/completion" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "code": "def hello():\n    print('world')"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "description": "Code review prompt",
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Please review this Python code:\ndef hello():\n    print('world')"
        }
      }
    ]
  }
}
```

### List Changed Notification

When the list of available prompts changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/prompts/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: prompts/list
    Server-->>Client: List of prompts

    Note over Client,Server: Usage
    Client->>Server: prompts/get
    Server-->>Client: Prompt content

    opt listChanged
      Note over Client,Server: Changes
      Server--)Client: prompts/list_changed
      Client->>Server: prompts/list
      Server-->>Client: Updated prompts
    end
```

## Data Types

### Prompt

A prompt definition includes:

- `name`: Unique identifier for the prompt
- `description`: Optional human-readable description
- `arguments`: Optional list of arguments for customization

### PromptMessage

Messages in a prompt can contain:

- `role`: Either "user" or "assistant" to indicate the speaker
- `content`: One of the following content types:

#### Text Content

Text content represents plain text messages:

```json
{
  "type": "text",
  "text": "The text content of the message"
}
```

This is the most common content type used for natural language interactions.

#### Image Content

Image content allows including visual information in messages:

```json
{
  "type": "image",
  "data": "base64-encoded-image-data",
  "mimeType": "image/png"
}
```

The image data **MUST** be base64-encoded and include a valid MIME type. This enables
multi-modal interactions where visual context is important.

#### Embedded Resources

Embedded resources allow referencing server-side resources directly in messages:

```json
{
  "type": "resource",
  "resource": {
    "uri": "resource://example",
    "mimeType": "text/plain",
    "text": "Resource content"
  }
}
```

Resources can contain either text or binary (blob) data and **MUST** include:

- A valid resource URI
- The appropriate MIME type
- Either text content or base64-encoded blob data

Embedded resources enable prompts to seamlessly incorporate server-managed content like
documentation, code samples, or other reference materials directly into the conversation
flow.

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Invalid prompt name: `-32602` (Invalid params)
- Missing required arguments: `-32602` (Invalid params)
- Internal errors: `-32603` (Internal error)

## Implementation Considerations

1. Servers **SHOULD** validate prompt arguments before processing
2. Clients **SHOULD** handle pagination for large prompt lists
3. Both parties **SHOULD** respect capability negotiation

## Security

Implementations **MUST** carefully validate all prompt inputs and outputs to prevent
injection attacks or unauthorized access to resources.



---
File: /docs/specification/2024-11-05/server/resource-picker.png
---

�PNG

   
IHDR   �   �   �Ķ  `iCCPICC Profile  (�u�;HA��h$D��H!Q�*���rF,� XQ��K��d�w������6bci��B҉��"��B4���z�������0��3� �%�g�	ium]�!
?n���.P	�����z7&fͤcR�rp68$o��?����x�����~P�t�m���;6|H��`����-�5k�2I�{�^�r��đl�o�q��ֿv���E�0�0R�ä��
�P ӟ"�?}J�/�2�����	�¤��Q��qD�eLR*�޿��zG������%P��׮7z\7L���u=u���[�@ϛ㼎 �K�����q�@�#P�|.La�vY'   beXIfMM *           �i       &     ��       P�       ��       �    ASCII   Screenshot9UD  =iTXtXML:com.adobe.xmp     <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:exif="http://ns.adobe.com/exif/1.0/"
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
         <exif:PixelYDimension>181</exif:PixelYDimension>
         <exif:UserComment>Screenshot</exif:UserComment>
         <exif:PixelXDimension>174</exif:PixelXDimension>
         <tiff:Orientation>1</tiff:Orientation>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
oP�=  3HIDATx�}�ՑnMM�fA(�0BFH"�dl����omd���9�. �k�g>{�k�
�Ȁ�������m�EAH��r�H3�h�h�����ܾ}c���#���Vש:u�ԩS]}�oߢ��S�Q�r�X�e��1��ޑ�ED�,�_�RQ� ���W�Hzd�L,P,N+�?2����x"���i%�f
��P�^]]M���
�������B�w�*%+��f�L�� w��i:]}�Uq�oXO�>�;���[iz�4���w��C@��;��.�[�>k�����O���h��IT\TL}�i�կ~� ����������6嗿�5=��v9眳隫��;v��I��7��-����6۠cA���
Z�N���k���E���
�暫h������~''��UW�O�s�R�-i�%���!���XW\~-�Ń��~��w�����|9mݶ=��1c�ҋ/�H+V����ڽ�=��ȑ#�c[L_������>!���]K睷� w̘1��֛�/~��=��@!�n��Ϊ�*8�)=D��pЛn��+�N#z�
"<�z.�.��Wn�5k�ҵ<�C��uz0n�XZ��
zs��J��G��]D]]�B�|,�����r
}��R�?����N+J�+.���K�������4o�\ڶm��� ;w���=W��w�Fw��}���o�)�N��o�I<���%�L�:E���H;/�����������/|������8p��m JF�l�9.�ٹnΚ(^SSM�����d�-r�WG������b֑�D�_��ujDeԟw޹�U��A�m`���ӧ�/���x�v[���aÆ���_K����y��s�Cs�̦q��q���z0�����.����|{��}������	/�8Ϗ|/=������>��O�m�1�A��4o�<q�W^y��{�o4��VUEXTp�9s���ɓ%y���i5/�k�����hϞ�4f�h�����{~(i����yA\�����`>n��K��3�R'�;ХX�)��c��xH"ڦ+�~|pz8
"3rT�!��O��)?����Z���A�~�C���|�
G���4����O[�DWg-�?�>��%t���"Q�bagjg��G�*��K_���8���}ｒ�x�
ڷo��!Ү]�V�#��������}��~{mٲ�^}M�6U�Q�Z�����#nٺ��0�y�fB�EyGd8<���_�	N�h-|̜ٔ���&�eBH���M%W`ĆJ��d#
�~��BM/� t�u�c��h���N�o_��:�`���Q>]#����K�����-{���ɷ���/���.ਸ��.�����f��ߡ/�k4��s��.��|����>"�|��I�"���ΦM�h�"�*��JKJ��HwO�fc�ĉt�I'�%l��Ŵu�6�%�}���qMP��9Xja师�,�7ǵ��T�������:/�׭[*��Q4Sm��p|��9��D?ɑc��䰛�wtt�i��~���i,粋���� ���bp¦3�Z��#䊽���^|�%z�����q�x�ɿP
絼-�Q��?��ښZz�h�����>v���ڵ�Q�v^uZЂwWsXd��s� �%��%+��~FBJ�
N�M�#k�v���3�ſ��/��n��tE�)w��E��+n\��?��*++]�]�v'��r�g�R���ߖS	_��WH�0~�I�446����� 4�i��/��ظ�˦�A]�a9-����l ��,�=F��g�u
^8N�p�d�#"2����ԡ�tੜ�6]��.*���I�N�Yg��N*Ҁ3N�h��;��u�2�Tj�s\�O�۽8mF�ZerRGOw7����d�@�fϞ�g�9�=§��謳Β(б�>�,�ӓO
;��Q���b�t�x�'j�����q:����i��y�mh�oWK���2�~�@�7UQ�i�wW�DZ�����]����	mW�pP@���-�ַ�{�q�%�б"Z������<���s�%�!���U�ptе�қ�7��Q�r
>w��W�����|��v~9..~&L�@��=���k���/�V��|>u�:�����g-_P������r�f�F�pn����0o�!ո��2i�Dzoo���H
�td7����>��X�҅.�?>�ȯ���?B�G�f�C6l���z/�u�8y����@�nlh���p.��R:�ǈvm�?Ҙ��r��wH�{�<�S��g��}�f�~8+\v��4m�T�����ڪ�����PGGx�EMM�tl'MM�%���apX��ξ!�Ӣw����|	�t�S��#���M�L��c����U��m���(�U:���QT"[]�<I��>���$nAba�p ik��,�ZQQɻ�O��#G����N����o]m$]`�����F�*�� Y�}V���q�����W�FL�?��}6��%�P�L���#Y��luN���o#�)��r�`���?~��Q>R�ĵ@B����r\l�`��?
�'����=9���FV�\�;k�@�Mf�4r����W��� N���틻s�.�`Z 7�8��33�gqq0*���r�Qn.������w0g,�[,P�h+NčǙǢ��?�x�8��i�A�i�49.TK�};�A��r\�YWo�9����츩s[?zo�Q�h��/�O8�E.��<��O'��DZ���c��?ŏ��ѷ�Dh�W#k6�0?N��+g�T�@2�����q�r�d��&�=F���hKK�\���D(d��������8��}��^?��*++�������b�]�@D^��o^��&m���NpG�σܧ�D��$��ǋ�䆅�_�(����T�[S�~���e�xy���<�$yBY��y\�7��f!9D�p�
�e���Z�;W���>ŮC��V0�
��D���Y���]�����N��B CP�a됻l����d#e";��S(9��>�a��d����`d��� i�'t��i�TtD\�����&�D8��g����Oz;X���,�N�Qm7!#�����qZs!fG\G�����ZtE��F0SX��܄C"���A��-���;��,_��k~̫�4
��Q�-Ǖ�Df$��]L�E���� �Ԩ7%�7�Q��⢠S�uʥx&<ٴ�����������LxT����]n�W̥zf�sjct��X�$�������ǤaA�X�x|�Kn
6�9r�d/7�>.{B'�r�?��t	�֐|�
0��.�C Hqګ��99'-^�^e6ӂ�xTF&<f����r���MR�,Ƥ2��7�>��x���&�ѹ89>DyŅb>�
9�IWk�?����JJ�0�G�L:�f�/ Q	b�R���M�Dlؠ0���R�&�h����
���ܛ���?�h��+'������[�����渐e���KPbA�JCnB����$��J�x,��a�09.7:���L@�����E����������<!+T�!'�����ar\g|�8�@6x�sS��9�~�|o��GWKh�T�ɵ�!#׾O�vy�qu�`�xW�H�.�B��,Y,:�0d�Ԩ� 0}<2��/�H�%���+2�4a���������,z��JMCF�Nh����L��q3���"���3Xx�	=����ͳ
���Gs7Vр�������!˲3-?E��(=���uţ�d�o�9���B� �8~�e�
��Hן΍/�ƺڼLJG}:�dt��������D�\��g�Q�-�o���g�,Nׯ�{n�B8�Q$O::�O�8_�}W�N���Ul���&��Qv��g��__B�^r)-�����/�I�C�2��3�I�GT���'��B�y��;�ivXr���[L���gM�E?˖-������aGC��?��A:�p��Œ�z��ҥK%£%.�uN^}��E���}\���8t1���|�!���y�v�9s���e���l�Q7����
�����]��2����z�QC��>��
��������{6\�i"L9����t4�����#��촜�"� �"ǽ�����9?)$C�Cy��5�����y5���i莣�QOZp����EZ8�uѝ8-緈���D�0�}X�A�	���;�b $H���z��<�}9�;���NΘ����W�5g�ۑv�㴈�ϝiﻟ�s�k�t��'����Y��>S\��q�mm>�}9�V{['G�4߀0}�-�f�1�r ��JN�M8��ϑv�w�ҪU��8#��s�tcJ��(�����{qm��K����Ǚ����j�#�#.Jl�6(.aP�50 ���V� �E���i���-���q����^c����:"��@�}\]&�dM��Vh�����\N0QW�Z��n�]�:i���KgȱKظ-�=����z��m�s`��6v�W���_���Xe��Oև���J&C�Q�9n�X�� �w� !;>�rziy���������@�ȑ�������P�&G<Ž�K�+����S����:��s�﷿�mN~�]������6a����+^N	��AE�k/�+����EMM�8F!L���aMu5�w�Y�& ҢHf<�=�%�z\B��*�n`r56���)Kw<ru\َ)��>r�f����À5�U�;.ƅ"�.CI�&��"��q�YC����F���1TQ5���o�:���<.��.�|a�an8쓯�æTN-�L�{a0��V���ε�p�$�8�HQ����A�ʲ�Ök��~���o���Ǖ�گ��`S�T|X�0��d�ʬ+&>�*�B�[u4��gz��ϱ��z�y��Q���&N_[�}̼��kZɳ�cP(�X�L�5���s��<��� 
��u��W�C���ぐk���8��NNd
B_w�8+� q��z+���$�"*A,`�,���<�͌.���'Ӭ@��N���@�8����]��j:]D��<�+�mV�(��6�(�x���f*W�i_^\�>��Q�d}{r\g@�Z�s�4Pq/L�K���U�A�W"��ޚ0q�65��O�]ω3B|�b1��H)1'1r
�P�x��*��Im��%�X�����jx�i�*��mk��sf�*U%w��AP�����Ag-�$�鎡��;V>?�J�� �Wl~�m\����ܯ���۸걗8J&<�3������Ǔ�7��
c�a��.͘	ax6�R�����K��<������*�p�>���8���yp��t2��3�#S�X&��v2i�� �
C�ĲL��1�x)�x&|���K���,��
ۙV�q���v�n.��v C!X ��qӍ*vN��l��VQm�Y@��E|5��� ��z�����G��~��������Ǖ�V�+ɽ�h���K{���;U%b��#�7����j�j��j�WTp��G�R?.���Im�������3^nW��n,��а�g�D\�}C9#qx
��m�
�13���@#F�Soo��wRwO���rc"<�[^VFUê��!���Ct����Xf�ŗe ��Сk�Пǭ�����r;v4�tj�8�:+�5i��%�Ŵg�>v|���@��9�ϒ5[N+�+h��qt�����a7¦3���i���,#�~#~�z��K���|�ϡ�� ���q��8l�KW\����c8�vw�1ۂ6h;v�(G#[��Pk���<����=L��S�Ú���Y�u�A�@�]�8����ќ�V��yG����Wr^!���m�hcX�={��<.b��=�5���-��ؾ}|���B�ZZZ�݆�B��myVA#n���g>s��"n�
��j���+��5�^�ڵ{/�x��8��sΤ�ƍ�G{"�s؉��V�m���o�Yq�d��bv�L�*������7�C�5"r��
���pڹg��:/�u+^]�ӂd7bѢ��m7��G��Y@����S��~p7�ͣΟw^(z��QC��e���2������V(����(��6�2�Y�uZ���[��o�������,, ������gS1��=?�ۑ`��g�?z�9n���,�#�j�Vԍ�i��o ��%x��'�D����___o3�ӿ�|3N�t�=�g3p�X�/��"���@��s\^���d1��H������8�y�9n
��-7�_ޣ΋��n~�Lw#��y.�ZQ��h�����[�������Mu�9�y=l��5bD��`8.�G�8/G^L(�����T�n���%����,� 8h�+��G�9���t'�Mk;���r^<�0e��us� �֯x#�'<x��o~M���Bw#.�Չ�� ����g"�F���k��:߈�-/��N�Ǡ%+g�uN2RT���T�n���8罛�#/����?6�3x��J��q�0�jV�F^ŽЗ�M5�*lE���ڎ��Q
��w�V��Ϋ�
k���/����<X�D�[0ɒ6�G^3ϩ�ߨ��^?I�^���q��B\N��+�
�g��#�j9x���y?7`��b��
T[[PR�<h�����Y���u�Mk����9P��	����q|��}g�6zyyi�����sR!]@X�R:;;�nWYi)����n
%�O8-��x�m_μQę�H����apR������wŊ���Ͽi��9��|A�Fq\,���ERWW������Ћ���
�TR\����i'L<���۩�~8K�JPd��G�w��?�O/����3�Rͷw�s�%�"���b`��y#9�9�Ñ2t�����i���W�Ϛ5K�v����3��q\3����G�+^��Ἑο���?��Ï��Tq�p<�x��a�ӏ9B����(�f�x����#�D�V��G�����"/;�D\xn��_���2ǎN�u¹8�|�F}����������DN�iV�\�>-���{]�ʧ��p�=�3je9��O�Q����>�Y���q��q�1���8���7�G���n�y�]wG͈A�Ü�q�W�˼o�m����C~��w�SϿ8�o;�Jw�qU9KYq<OEW��PՊ��Z@�;��O��g�g��?�#�\���O{�Ι�n���(Wz��OJ7�F�C�p�Rޢ�ve/oSb{��{#2pD\\�`g���W�C�q;4�21��L�-�G�JkuFu�
~!�j;�� �-������'�7��6YN��
M����v�ce��4+(^hKHE���ǀZ N����f�h�?D^L�w��t����<�`�d���$#3�iiV�i[������� �N
�Q=�s\�=ֈ��;8(�F\㜈���P#��^�HW�ԕ�����.�gu:�G�:��=V�l�;S�<���mV� W�k�8`�r�S-������q�Gܓ�"��+IO9��j�Md;ߙ�;����QqR�r��ڊ�"-w\�EC��6�x��r\�l��IqI�%(>dg,R\,t���yTFw��� <��!m�8��\�?��8������T�69ᬤ�ur['��H�,��7�����x�q���?I��s\�,.r5���k0:�Ee�Z �?������縺��F\'v����z���=��;o'����7��&��g���}s\^'�Z�yaJ�Qu栴�<�e���-�g;ߙ�{r\d��Eq/T.o=:EQ��9����$��:2MQ�jF3ah̛��1��;�*8ΠNaC5�c�+�GG�҃B�B�v�p��m���}b����
����cSu�@ץ* ru:o���;g~L�S����Z7���q��C��?� �
�Ÿ���8� ����ן��>�z��MCB_qԐ�+��$��4�5��x����Q��H<��K�T&i���:�B
��;CV3����F���������Z���w>\�<==ր;u�x�\������;�QGW�w�Zںiˮ6���~�jHv�k��f��w�^��7-x�Qgwu���|<��/��<��Gڐ���N�����H�st�S�O�q��x4�����ϡ1�ɐ.��Th����Ap凾�����VӺ��,�e~�E��-9�ڏ��?{��_���'�V&�W.�(8>^Y�L?|x
:�C#�W��[ϣ)'�S[g}�g�ѳ��ފ����x}𲩴|����^��t���|���#W6��t�����^�0��e!�zR��v�n��
ں�|�����_�D�f�+�1��/_�6Hޒ��{�
�w"���&ƚO�
q3��vfW�
&	]ze
���ы��x�{���}p����.�?�>{��3}$;q�^����ⴥ%��`�C����k�y�aw4~i;ճ��[���?�#z����g�E�`��d��?�@^{�Y��H����������>���+�k1E��`'=��&^�E���,N;w�h�����Vӽ�YK+�5}0짱�5�d1��$:��W�^������-�+WQ�O�Ŋ�`��}�)|ͦ�8����h2�=sUU�ѿ�������\�����5��0Gֲ2^Q�j�\0�>�x=��V���_�g^�E���l��Kۤ���
ǟ�Qs��fzb�6��qB��?x��T_SF�-��8�'�W��l��߶q�~��zu�������zs�A��o�<��ӗôz��=�qP쇈�y	2�0c���r��p�k(�JW�e�G�։�����DUfvS�dߠ~/�:�z�˞��f�w�_I;�!D0��������4v>D����NK���]�̜2\�o�d^ȇ�v��.7�}������Ά��4�F����`�O���u�4}B�țz�y�*ro��?�[IX�U��|�i�1亃e?�C�����U�;^j�偮B��K8+Ѷ��zM�s�6���_&9�m���'6�)y������b��Z�a?]:b<=��nj=�-N=�x�o_H5��W�9���������|ч2�|��&
�oAt������N|�D�︄&���/��胋�����3��_���0�[��L���\pcit��� ��F>1������g>�r�3g�t�,�r��賛�?y�~��z�Ļ�=��ފn6��l ����ΟD�<�����iG����/��ǯ>�f8�"��L&�8�]{�����y�w$~a�^��=�(����b/U"6?�Q��!�źP�7+.W��ر�"
'��p0 �Wo:��}�kre��{�sg��]�@�:�{�//����)�����W3��"3��4Sw�>��������/+v����M���4ze�q:��h)�M.�����m���8��B�F���?�d����`��������l?�i��
���F��+n�.?uz�P��Zɹ�_��a:c���T����G:�ҁC�PWE�U��K�N�����}4zD�DHIJ-z*�~����Ө�՜&�B���r��F���Y9��\��
\�����>�A�$��J��}�;[����CMm�c�qD��ي�b�-�ǫ*�y'�F���{��F��Mt�F?��eLC��0���%����J���H��~�Y&�������r\6]v�]�Z��XIJ��$0爣w�VsQ1�cs ��=�V��X���r\�$r(��[i�t6Xc�B���W�
��WKX��8���'��lL��
��'�����y��
����x"'Kx��PMRH���M��=��GO5#I�o .���/l{��
1y	9�BY�ŵ]}K���±q0��Q
�>q'Jg����qC�P�0�؈��2�~��Z�ܨ��F6�x�⹩����Y�p����j�^�ZŜ�lhn+y/�'(����,q�1�۟�n,Y��p�|��iO:���מ���B��H?��".`�S��C�+	�,��+��>�d��H�k
9fxB��O�7�>.k):�ޟ��f*.(��Y-���;��C��{���VB"Nb�u��!]��`�Å.,
�j�Gp(ف�
3h�Q�3<�q���Y*��a�I��-s��q�3��a���U����C�EW�}�����/v����N`QrP�����820������l{
�}x�d�B��e|@�yr\�spF�r��toč�<��
��ja�/�Зnx`Dw&�cr����E�U6�����r\�4g� �E��Ņb>�Nq�ˊ�c�"��R�q��u���3��\�_���>���N�9�nąs�%Mua��rL���"݇7�a�m��*B���$벢�
Y
�4�W�v��A�<�2O��eb»��9�ܐ[�{P��dW�� U���M�I�/��>T�gf$6>�]��O�ޓ�c����s�p��s�h�n������6�Ѿ�����y5R�d������P�o�)��r*-����R���1^q2�'���[h~`�f�Q�9.\�%��0��2ǡ��ء 1�^v��#���F��TRZB��m`*�W*�,Ǩ�������N\F�U5�W��[�Ca���g�~����s�|�45���BÏ�纺:�P�~~c���Ruu
���qDMW����]���!�_:��J=�T];�e��S����ޙ�XN�
��q��].�9[����θ��h���p��QL���A������i[쥺�j1�����V��&��r����n��ʨ�� �۳�F�Oe⼅1�ب��yC�
0��#Y���9��0	f�Ŏ���8�Mc�Zh8Vfoo'�4�����ШQch��1���C�[[WǲFӰ�rڷ{;Ga�F�B��>p:Pr��T�݈�����D�\q�(;Ī���2���&�PH�Qv��{wSͰa4r�(����yn<�4���F��]�wQgG�
�n�I�'4?H�_\�+�l�E�3����JI�,��ݬh��&����*x�A���C�|�-�ӻ;��loo/߲�WH��x**L�
zG{;�3�u.'���DcC#m߹�y�=c�?�9��'�3O�̹�	����bH�H�+��Υ���ZK�����>�KK=5���8PQ�} ��|A�s�Vj^G���dЎz�����c;^�+xf��1��/���~�6l�@---TSSM3f�Fg�9�,N�	���j�d���n��a^�WE�=� �0��1~�u���3��=��<B7�� ��+��kĕ��s��eRz��}r����D�E�A�5�
�KG�����B������[i�[o����fjhl������A�g͢�~��ny�N7�֬y�֯[O�9�=��mQ�K��s���N���g�lg~Ǘ����n��s�8�p�M�������iB�<(���Ӥ���)x]o�_�v
͚}6�>9��\�:�9w�\�� �<�_����k��͸YS-���]@3gΤu��ѓO>Is�Υ3�<�w�����6mz��O�Ns�=��vp�-� �p�۾c�7��Ga�P�,ؘ����x����:��?�帆�p_�x1<#:4���8 W|�����W��G�����pG9�C:S0�t��8���\�J<�����)S��)���3~ؤ�&N� ��Iݽ{7Mc�mim��W�����=����"����!�~����+uȃ0~���?��r� a�b��0)o���W��(�8f8|�����?���kjiܸSX��^�S�[�|��ù0Q�Z��xX��͟T�W]w�u�6�{؉�*���kr�b޼y>��}���[��߉s�!�-q� �w���s�8mܸA�2��a��A����>.[�W�>��_��z�٧8:��L��[��x0;��� NGN��?����.�6o�$<��>�����G۷mK����n�{9o�����gϮ��sOѲ�~�h|����quq�E�p�	���6N�i6�,�&r�w~�[��_vŕ|:E5�u���bWEUu !�uh㼴���/�pєX�#;�&�c���҆�%ڎ;��S襉�&�ԩSyPbIW�Ѿ>v�4~©�9�a�(�@C<H��#m������$��P(�|gҾh��
��q��
/�ޱ�Ƈ>��2�o@�8ܯ��755�E]D��~:���$<M5�[?��L�y�`�xNg|JGם;wҪ�+Y�Yt꩓��z+v֮������qq1����ሎ�oQ1~��X�|��*ly�ݻ��|�Mz���4��A���EM��%!
�
��Ώ���R^�`�L�r*}��_�S}հ���CD��ZRR*�^HZ[[y[m
}�/�����D���be���ꮝ�h��-t�y?�:���v�9��	�Y��xZl׮�����ü�r��5����a:���:����~z/縷H�ll)[_�a>�]]������uo��իN(��t��dԨ��Ż��>^�?��=K�y����`|'l떭t������JX�]���D��
�={v��U��'��_ ��v��OJo�ڪ)���&�|���<�
�����l�L�|�#����K��{qA���f��"8p���ٴ�}����#���_�L'�D���U`��*�������Sg쉨d�������Orag��/�'�e;��뼯�W.���o�m۶�3|������Ԟ8ǩ�\K3>wW!,�)�G�I�ÿs���JH�1���!���'�r���������s�=������
���;sHR�D+���c:��&�ʠ�u��������b���Ώ�EŘԜ�2��y�+S����Up���*�9�ǽ�rN̣�ncz�A\�Z�����>.ŝ��
�[�f�bs�f.���#'{����0�Gd'�����AbDq�t�=��qq� �  A���h6�0��:�u�8e�����$�Fv`��ną�aH��8\곣��'l

�����E\�Fxd��y������A3h0    IEND�B`�


---
File: /docs/specification/2024-11-05/server/resources.md
---

---
title: Resources
type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose
resources to clients. Resources allow servers to share data that provides context to
language models, such as files, database schemas, or application-specific information.
Each resource is uniquely identified by a
[URI](https://datatracker.ietf.org/doc/html/rfc3986).

## User Interaction Model

Resources in MCP are designed to be **application-driven**, with host applications
determining how to incorporate context based on their needs.

For example, applications could:

- Expose resources through UI elements for explicit selection, in a tree or list view
- Allow the user to search through and filter available resources
- Implement automatic context inclusion, based on heuristics or the AI model's selection

![Example of resource context picker](resource-picker.png)

However, implementations are free to expose resources through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Capabilities

Servers that support resources **MUST** declare the `resources` capability:

```json
{
  "capabilities": {
    "resources": {
      "subscribe": true,
      "listChanged": true
    }
  }
}
```

The capability supports two optional features:

- `subscribe`: whether the client can subscribe to be notified of changes to individual
  resources.
- `listChanged`: whether the server will emit notifications when the list of available
  resources changes.

Both `subscribe` and `listChanged` are optional&mdash;servers can support neither,
either, or both:

```json
{
  "capabilities": {
    "resources": {} // Neither feature supported
  }
}
```

```json
{
  "capabilities": {
    "resources": {
      "subscribe": true // Only subscriptions supported
    }
  }
}
```

```json
{
  "capabilities": {
    "resources": {
      "listChanged": true // Only list change notifications supported
    }
  }
}
```

## Protocol Messages

### Listing Resources

To discover available resources, clients send a `resources/list` request. This operation
supports
[pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resources": [
      {
        "uri": "file:///project/src/main.rs",
        "name": "main.rs",
        "description": "Primary application entry point",
        "mimeType": "text/x-rust"
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Reading Resources

To retrieve resource contents, clients send a `resources/read` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "contents": [
      {
        "uri": "file:///project/src/main.rs",
        "mimeType": "text/x-rust",
        "text": "fn main() {\n    println!(\"Hello world!\");\n}"
      }
    ]
  }
}
```

### Resource Templates

Resource templates allow servers to expose parameterized resources using
[URI templates](https://datatracker.ietf.org/doc/html/rfc6570). Arguments may be
auto-completed through [the completion
API]({{< ref "/specification/2024-11-05/server/utilities/completion" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list"
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "resourceTemplates": [
      {
        "uriTemplate": "file:///{path}",
        "name": "Project Files",
        "description": "Access files in the project directory",
        "mimeType": "application/octet-stream"
      }
    ]
  }
}
```

### List Changed Notification

When the list of available resources changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/list_changed"
}
```

### Subscriptions

The protocol supports optional subscriptions to resource changes. Clients can subscribe
to specific resources and receive notifications when they change:

**Subscribe Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "resources/subscribe",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

**Update Notification:**

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Resource Discovery
    Client->>Server: resources/list
    Server-->>Client: List of resources

    Note over Client,Server: Resource Access
    Client->>Server: resources/read
    Server-->>Client: Resource contents

    Note over Client,Server: Subscriptions
    Client->>Server: resources/subscribe
    Server-->>Client: Subscription confirmed

    Note over Client,Server: Updates
    Server--)Client: notifications/resources/updated
    Client->>Server: resources/read
    Server-->>Client: Updated contents
```

## Data Types

### Resource

A resource definition includes:

- `uri`: Unique identifier for the resource
- `name`: Human-readable name
- `description`: Optional description
- `mimeType`: Optional MIME type

### Resource Contents

Resources can contain either text or binary data:

#### Text Content

```json
{
  "uri": "file:///example.txt",
  "mimeType": "text/plain",
  "text": "Resource content"
}
```

#### Binary Content

```json
{
  "uri": "file:///example.png",
  "mimeType": "image/png",
  "blob": "base64-encoded-data"
}
```

## Common URI Schemes

The protocol defines several standard URI schemes. This list not
exhaustive&mdash;implementations are always free to use additional, custom URI schemes.

### https://

Used to represent a resource available on the web.

Servers **SHOULD** use this scheme only when the client is able to fetch and load the
resource directly from the web on its own—that is, it doesn’t need to read the resource
via the MCP server.

For other use cases, servers **SHOULD** prefer to use another URI scheme, or define a
custom one, even if the server will itself be downloading resource contents over the
internet.

### file://

Used to identify resources that behave like a filesystem. However, the resources do not
need to map to an actual physical filesystem.

MCP servers **MAY** identify file:// resources with an
[XDG MIME type](https://specifications.freedesktop.org/shared-mime-info-spec/0.14/ar01s02.html#id-1.3.14),
like `inode/directory`, to represent non-regular files (such as directories) that don’t
otherwise have a standard MIME type.

### git://

Git version control integration.

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Resource not found: `-32002`
- Internal errors: `-32603`

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32002,
    "message": "Resource not found",
    "data": {
      "uri": "file:///nonexistent.txt"
    }
  }
}
```

## Security Considerations

1. Servers **MUST** validate all resource URIs
2. Access controls **SHOULD** be implemented for sensitive resources
3. Binary data **MUST** be properly encoded
4. Resource permissions **SHOULD** be checked before operations



---
File: /docs/specification/2024-11-05/server/slash-command.png
---

�PNG

   
IHDR  %   j   �Gz  ^iCCPICC Profile  (�u�;HA���h0�"����b$�6"�"XQ��es^�K\7'b���66������+E�O��
��EM������33��u�-�B��٤�������!��Og%�дy*�����#<R�G����i��W^��;#���-/�3J��r�qa�X۵��∠���%�u����s٭Y̤���,��+��l�o6q��a_;��Fqi����i�($��8T��O�>��Ka{؄�<lw��h��9�0�(q㔪���;6��;`f�`��%9p�t�4��# t
܎q]�?��T}��x��A��9�k/�j�q�O�vx����'�9aj�J�   DeXIfMM *           �i       &     �      %�       j    oI��  iTXtXML:com.adobe.xmp     <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
            xmlns:exif="http://ns.adobe.com/exif/1.0/">
         <tiff:Orientation>1</tiff:Orientation>
         <exif:PixelXDimension>293</exif:PixelXDimension>
         <exif:PixelYDimension>106</exif:PixelYDimension>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
l0�5  lIDATx�]	xUE�>Y YH����HXH�DDdw�Glhm�lu�F���vz>��v�[g[wT�%HXd�%a'+	[ !�Ad�_�.���Gܼ֗w���Wu�֭[�׽�=uN�[^W�^�N"��  Xo��C�!��B@HI.A@�BJ����  )�5 �B@H�R�!�!%�A�R)Y�;�2��  �$׀  X
!%Ku�TF���K! �d�������\�� `)��,�RA@���+��]��������^i� �PM�����[pS��ܴc�Y�@CE@H�����[pS��ܴc�Y�@CE@H�����[pS��ܴc�Y�@CE�头n�zJKK�1>�Ν�����#���p))���ӛo�C.�����YN��C�,���r���(.n��\p�Gv���p))�Z��Z�jE�^#$��5%/oo
n��i9�h��7����N��A@�>���bAA>�ر��1���n�}EE���l�¢+4tH�nm;�zܸ�4f�h���qZ��$��9Gv
��҆������Ə���G�PjJ7������5k��ˋ�B[)R�p�ĉ�c;v�@���F�իW())Emo���
��3(((��ޑ���m����p)�]������÷PJ��濼���m���Kt�:���G��Ggy���wc�y��*�K'�g��y�E���%��f����ѐ!�m�dC���KH)99�RSSi��+���VҼy��iS'Sn�eE>�>��&M�H�o؍���>�@�ɞ���_-WV���F���[o�KO>��h�
3��#�RZ�z�f�9|X9�O�F���)���ǗBBB�^t/���q�3H��w�k׮���_�FF�3gΪ]�Ut���������u-))���[i�ȑ��[���3� Oz�M{Qrr�:S�V-�qF9D�	��Q���m�F��y�8a�Ò��Z�f����iP�@5�i߾x�۷/a8&"��@�kJk؋֣{
w�l�vm��;�)���G����f>� -^�z�S(��� �VԪ����I�g�~�)H0t���H�/��]��N�Uu��O��kU� �A��URZ�j
������w;�����W��O��<5Iٞ:w�)S&Q�.]Ա��}�|��C����n�ԴT���ݻ���WϞl@oD˿����T6g	�3�O3�Ķ�  X�Z#����X�09|�PjҤ��V7o��G����5f$��iӦʹk��l�ER�y�t�G
yz�*# �����dC�6mJ�-xEM�<s���~�
σ��@���n&��2���9m|^�ez��͙�=��t�|q[�ҢE�WSv��i8EFFһ�i���
L'�S
*�+�A��Ԛ!f��uԖ��QQ�N[��_@׮]�ݻ��'O�|а2xz �f���`ʟ  x&��)�������9�M�6t��hժ����O�mM�е�kj�^9y�g+
�3�BZ-@�+;;��_��t����F}x�eHp0EDt�ƍ�\�+��AC�!Pk�RU���ۢ�k�����Ϝמ�����"�� `ꅔ��L>7�G��>rVA@p��ۓ��)N�������R�P:8�#�$M\����������4ɘC��|9O��o�/��}���F�'8C�4�2��


)??_y
�����'q:I�A��p[R���Ԅ�yR�/_��M�+)u��I*��[��&$���5�!5k֌?.�|��'�A�5�z��k�Y'�j2���lHxaW�N����F��HIkI@q=t��Ըq�j%
�@� ���7@��I�ڎڗ.]T3�KJJ�q9�  ��$%3!iRr�^^vv6]�X�%�o����*#�v�7��&#����>
!i$$���[��#�)Y��&�� �p+Rҍҡ&)�t	A���%)		Y����	!���dn4���@�A�mIɬ-���5�ya�%Z��Z������{����	��SU*������Z����o��ʡ5Λ�{��|���������'q�ܖ�ꪯN�<��>������y���PRR/
q���]'��8EV�<n۾����~��}�EE4�/������X.L��U����n9O�f�j7v��1:p���%�Ѓ�啕څ�%����"|���+ԡ}{�h]rb.�k��4o�
��	� ��R%���sK�|��`����1}��R%���l�"������|jZ����!YeoDE��lv�w!%'�BVV6�Z��RRR)_��.AH�������`���n�A6�R.�֡4u�$�ѽ��ҝ'c�����4���)==������x���G{��5
�ׯ/��I��K�\� ^��_?n�L���_A���
/�މW;�����4Z�r-��?}���;�4ns˖-l�>|�֭����s�a^�а0�ݫ�7nL9R�۲]��w�|6�����={�6뗨�x����凄���͠��vӱ��TXTHO?�k���Ͼ�ӧNy�ر�|���ϖ}�>�ݟ빉2�f�6�s
`�!��x�Fշ��A��3C9-O>1���y��bz����dFD��)�'ڤa$��[�"���g��{G��I'�f���������s�ԇ��6�1�`�F|,X�Тu�v�����
�R^�	￙%��t$EEE��;��	��9�b�<����bz��������ݯn�l&�!�Q@@ �8��Ã
��Um��C��P<���R�{��ԡC;^)8��;N%�%��KU�B�X��-Z��C|�C#X�7z�I�:LP�@&�(���_}���n�I-}3�?�Ҕ�oؤ�>8o�.᪨�Ǔ��y�����JH8D[�m�Aw�l3Fr�`Æ
��o�O^�����wR��Կ_�j+V�᥷�(�:t0�����{��!%%���A�O�:C���t<1���C��
���U�����ڂ���A���o#�G�I9��[������	�r@8��(�SGjժ�"�]�~V����v�Ԧ��ÇVi�d_�QuD=S�R������a�]��`^�gȐ;�����E�|��}r<1�j�3
�h��.�h%�ZIɩt�b�awƌit��!��M����P�|�@+����M�?��qQB��ᇕt��Q:$Fg�R8m�d���S3y�DZ��bڶm'�;F�����08���d^6}p9�̉�fߵkk	-��W^242ܘ��ֻ���Ԋo�}᷆�ً�x�M^6}����0���֭[U�!|����۵�06oުHj����N��i-A��N�_�>Ť���L��~��֎���T��2����O�����?<�~��o��;Ǆ��O�Ic7�r���E��?J��N-�XڶmC���k����t��o�c��&.�sDD=���F9+��7�� ���_�>F�+�1�p�E��tH1kGZ�-Z��$�m&c�#xJ�$ң�)a];����Y�I4'����1�&
�x��/��߇��.�6m��.#���k��m����+�Ϝ�ҋ�e��<��d	k3�BB^y�r�
�gϞ%h�gyHf� �132NImZ���7|`�u��ʚG;��͂cԹ��3'ӨQw�l�o��&NW����3'��������}�ḹ����j�h'�D�@^Z��lHC�W6<q"]vt�m�DG+RJMM�)���Xe�o�|BJz�\��y؇!�a~Re����G
�f$駶�"�ή]�����ȇn G��YBC�n�K�����w��ټY.޷o��؝y��.�\.D�9�9��]6�Ő	?{)5}ZƄ��(n�6C��a��֭+=0c��x=ݠ)�"-YW��y��Vy`�:}��;�Â��x!���;��9
�rrlh6�x��5f��!n)9�5���,��_�g;�!͚6S�M_�Ց�����a��u�
St�����!|d���rq�r�R9��p#�5�ر����F��`���aaG�� ;�GK��K/>��
*�\e{]U��6W�,�����
B¹0M ��L
jA?���Wu�'�BJz7З_~K��4{��l轪.�6<�0{EZkIYY���u�	���f����k��|X�ah5�'��f�!��4Mp&�[8���0CΞ=Ǟ�<��C�޽z���X��]۶��0��1��1�����G���T^br�'�Lʆ]pZ�����ϯ�	�����H��ç��N���<�3�ڨQc6�S	���B�KULkH�������W�/�s����q!%=�':l ��K?7<m� �~�]#x(v�ᒃb��W��{�V�={����,8p�Z
��>��k�)��v��
�q=y{Tf'��5�ɳ�)�� v���6�=�^ƏK˸~��և��+�܉<�C�v)}��rJIKe�R��!1mHeO�Q&�^=#�bqCÖ���d1��b��ƍ���`��0���Af��bڂn3
�ۧ�a�&v���,�-Z�g�4{�L�3ZŋYC���?dB�Q��Ν?���pvp�����+��e!ςW��	���}�a 0<�t=[3��[	�(J�}�>�kd�7v�ޫ<w�~z�)9������ֵ+��Sx���p�m:�޶g�\�$�ڂ.�~[�W%7v�zWKϋ��f���F{��c��Vc;%5����VUR�q3�AE�E��Z������Yf���CM�X�r5a#���Ӧ؜������WP�{���	�h��9Mfy��5b�nӦ͊�:u�D�f=dxO�e˾0f��"�I��WQ���bR������~�� �7j�H�ac��L`B��k�f�cJ�o�2�^'��#�1�4L�x�I	�������=t�es��!�%<���6x#�������.�V+�j�2�V�a6.���R�T�fIJ*3^���+xŊUԞ��#G�y���;8))٘�.l%�-p��[��/Z�4��a�����h�LN������Ub0�����ً�(?�e�#��������<z������ɬ�a:ڇ�3++[���uu��X�hJz%!�J-�����{��������P�.ęwΕ�	j�wE穬�����6�n8���\���FMa�)C@H������x�v���Ȏ�ݠ;88R�A��)9@���׍�;�H�j�O
��:w/7�wPL���"�ȿ����V!rP�5jD�I��>X2��)�V)T���M#IuK��qfo�9n��J�A�nKJ��o5�-8���l:���� P���M	������{��"1�_>Wj��l���[���R�b.�J��<͛~"�� `
�j�fO8�i�a2��w����B�#�V�dn��$MJp�c���"�� `]ܒ�@DMH '���;Kx�L�Gֽ �f���ڔ@HچR��h����Ƅ���i��A��#%MF�q��	�B��7��� 4&����3W�]#5<�#%ݍZ�)i1iA:�D�D�:���� P��%)imIBMH��g&$31�}�A���[��њ�֊�Ą}���<:4�#qA@�{ܖ�4����mIoCS�i�+���P�_ܚ�4!4��>�.�n����@�"�֤h5!A2��=)Ak��Ƥ`�?A��p{R�ȚIH�9͜O�%��G�cH	�j2B\kD�4���@�"�Q�d�Z�Ȍ��� psf�u�$5F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`�3DE�A�Xs    IEND�B`�


---
File: /docs/specification/2024-11-05/server/tools.md
---

---
title: Tools
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) allows servers to expose tools that can be invoked by
language models. Tools enable models to interact with external systems, such as querying
databases, calling APIs, or performing computations. Each tool is uniquely identified by
a name and includes metadata describing its schema.

## User Interaction Model

Tools in MCP are designed to be **model-controlled**, meaning that the language model can
discover and invoke tools automatically based on its contextual understanding and the
user's prompts.

However, implementations are free to expose tools through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

{{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
be a human in the loop with the ability to deny tool invocations.

Applications **SHOULD**:

- Provide UI that makes clear which tools are being exposed to the AI model
- Insert clear visual indicators when tools are invoked
- Present confirmation prompts to the user for operations, to ensure a human is in the
  loop {{< /callout >}}

## Capabilities

Servers that support tools **MUST** declare the `tools` capability:

```json
{
  "capabilities": {
    "tools": {
      "listChanged": true
    }
  }
}
```

`listChanged` indicates whether the server will emit notifications when the list of
available tools changes.

## Protocol Messages

### Listing Tools

To discover available tools, clients send a `tools/list` request. This operation supports
[pagination]({{< ref "/specification/2024-11-05/server/utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather information for a location",
        "inputSchema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name or zip code"
            }
          },
          "required": ["location"]
        }
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Calling Tools

To invoke a tool, clients send a `tools/call` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "location": "New York"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
      }
    ],
    "isError": false
  }
}
```

### List Changed Notification

When the list of available tools changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant LLM
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: tools/list
    Server-->>Client: List of tools

    Note over Client,LLM: Tool Selection
    LLM->>Client: Select tool to use

    Note over Client,Server: Invocation
    Client->>Server: tools/call
    Server-->>Client: Tool result
    Client->>LLM: Process result

    Note over Client,Server: Updates
    Server--)Client: tools/list_changed
    Client->>Server: tools/list
    Server-->>Client: Updated tools
```

## Data Types

### Tool

A tool definition includes:

- `name`: Unique identifier for the tool
- `description`: Human-readable description of functionality
- `inputSchema`: JSON Schema defining expected parameters

### Tool Result

Tool results can contain multiple content items of different types:

#### Text Content

```json
{
  "type": "text",
  "text": "Tool result text"
}
```

#### Image Content

```json
{
  "type": "image",
  "data": "base64-encoded-data",
  "mimeType": "image/png"
}
```

#### Embedded Resources

[Resources]({{< ref "/specification/2024-11-05/server/resources" >}}) **MAY** be
embedded, to provide additional context or data, behind a URI that can be subscribed to
or fetched again by the client later:

```json
{
  "type": "resource",
  "resource": {
    "uri": "resource://example",
    "mimeType": "text/plain",
    "text": "Resource content"
  }
}
```

## Error Handling

Tools use two error reporting mechanisms:

1. **Protocol Errors**: Standard JSON-RPC errors for issues like:

   - Unknown tools
   - Invalid arguments
   - Server errors

2. **Tool Execution Errors**: Reported in tool results with `isError: true`:
   - API failures
   - Invalid input data
   - Business logic errors

Example protocol error:

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32602,
    "message": "Unknown tool: invalid_tool_name"
  }
}
```

Example tool execution error:

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Failed to fetch weather data: API rate limit exceeded"
      }
    ],
    "isError": true
  }
}
```

## Security Considerations

1. Servers **MUST**:

   - Validate all tool inputs
   - Implement proper access controls
   - Rate limit tool invocations
   - Sanitize tool outputs

2. Clients **SHOULD**:
   - Prompt for user confirmation on sensitive operations
   - Show tool inputs to the user before calling the server, to avoid malicious or
     accidental data exfiltration
   - Validate tool results before passing to LLM
   - Implement timeouts for tool calls
   - Log tool usage for audit purposes



---
File: /docs/specification/2024-11-05/_index.md
---

---
linkTitle: 2024-11-05 (Final)
title: Model Context Protocol specification
cascade:
  type: docs
breadcrumbs: false
weight: 2
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

[Model Context Protocol](https://modelcontextprotocol.io) (MCP) is an open protocol that
enables seamless integration between LLM applications and external data sources and
tools. Whether you're building an AI-powered IDE, enhancing a chat interface, or creating
custom AI workflows, MCP provides a standardized way to connect LLMs with the context
they need.

This specification defines the authoritative protocol requirements, based on the
TypeScript schema in
[schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.ts).

For implementation guides and examples, visit
[modelcontextprotocol.io](https://modelcontextprotocol.io).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14)
[[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)]
[[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)] when, and only when, they
appear in all capitals, as shown here.

## Overview

MCP provides a standardized way for applications to:

- Share contextual information with language models
- Expose tools and capabilities to AI systems
- Build composable integrations and workflows

The protocol uses [JSON-RPC](https://www.jsonrpc.org/) 2.0 messages to establish
communication between:

- **Hosts**: LLM applications that initiate connections
- **Clients**: Connectors within the host application
- **Servers**: Services that provide context and capabilities

MCP takes some inspiration from the
[Language Server Protocol](https://microsoft.github.io/language-server-protocol/), which
standardizes how to add support for programming languages across a whole ecosystem of
development tools. In a similar way, MCP standardizes how to integrate additional context
and tools into the ecosystem of AI applications.

## Key Details

### Base Protocol

- [JSON-RPC](https://www.jsonrpc.org/) message format
- Stateful connections
- Server and client capability negotiation

### Features

Servers offer any of the following features to clients:

- **Resources**: Context and data, for the user or the AI model to use
- **Prompts**: Templated messages and workflows for users
- **Tools**: Functions for the AI model to execute

Clients may offer the following feature to servers:

- **Sampling**: Server-initiated agentic behaviors and recursive LLM interactions

### Additional Utilities

- Configuration
- Progress tracking
- Cancellation
- Error reporting
- Logging

## Security and Trust & Safety

The Model Context Protocol enables powerful capabilities through arbitrary data access
and code execution paths. With this power comes important security and trust
considerations that all implementors must carefully address.

### Key Principles

1. **User Consent and Control**

   - Users must explicitly consent to and understand all data access and operations
   - Users must retain control over what data is shared and what actions are taken
   - Implementors should provide clear UIs for reviewing and authorizing activities

2. **Data Privacy**

   - Hosts must obtain explicit user consent before exposing user data to servers
   - Hosts must not transmit resource data elsewhere without user consent
   - User data should be protected with appropriate access controls

3. **Tool Safety**

   - Tools represent arbitrary code execution and must be treated with appropriate
     caution
   - Hosts must obtain explicit user consent before invoking any tool
   - Users should understand what each tool does before authorizing its use

4. **LLM Sampling Controls**
   - Users must explicitly approve any LLM sampling requests
   - Users should control:
     - Whether sampling occurs at all
     - The actual prompt that will be sent
     - What results the server can see
   - The protocol intentionally limits server visibility into prompts

### Implementation Guidelines

While MCP itself cannot enforce these security principles at the protocol level,
implementors **SHOULD**:

1. Build robust consent and authorization flows into their applications
2. Provide clear documentation of security implications
3. Implement appropriate access controls and data protections
4. Follow security best practices in their integrations
5. Consider privacy implications in their feature designs

## Learn More

Explore the detailed specification for each protocol component:

{{< cards >}} {{< card link="architecture" title="Architecture" icon="template" >}}
{{< card link="basic" title="Base Protocol" icon="code" >}}
{{< card link="server" title="Server Features" icon="server" >}}
{{< card link="client" title="Client Features" icon="user" >}}
{{< card link="contributing" title="Contributing" icon="pencil" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/architecture/_index.md
---

---
title: Architecture
cascade:
  type: docs
weight: 10
---

The Model Context Protocol (MCP) follows a client-host-server architecture where each
host can run multiple client instances. This architecture enables users to integrate AI
capabilities across applications while maintaining clear security boundaries and
isolating concerns. Built on JSON-RPC, MCP provides a stateful session protocol focused
on context exchange and sampling coordination between clients and servers.

## Core Components

```mermaid
graph LR
    subgraph "Application Host Process"
        H[Host]
        C1[Client 1]
        C2[Client 2]
        C3[Client 3]
        H --> C1
        H --> C2
        H --> C3
    end

    subgraph "Local machine"
        S1[Server 1<br>Files & Git]
        S2[Server 2<br>Database]
        R1[("Local<br>Resource A")]
        R2[("Local<br>Resource B")]

        C1 --> S1
        C2 --> S2
        S1 <--> R1
        S2 <--> R2
    end

    subgraph "Internet"
        S3[Server 3<br>External APIs]
        R3[("Remote<br>Resource C")]

        C3 --> S3
        S3 <--> R3
    end
```

### Host

The host process acts as the container and coordinator:

- Creates and manages multiple client instances
- Controls client connection permissions and lifecycle
- Enforces security policies and consent requirements
- Handles user authorization decisions
- Coordinates AI/LLM integration and sampling
- Manages context aggregation across clients

### Clients

Each client is created by the host and maintains an isolated server connection:

- Establishes one stateful session per server
- Handles protocol negotiation and capability exchange
- Routes protocol messages bidirectionally
- Manages subscriptions and notifications
- Maintains security boundaries between servers

A host application creates and manages multiple clients, with each client having a 1:1
relationship with a particular server.

### Servers

Servers provide specialized context and capabilities:

- Expose resources, tools and prompts via MCP primitives
- Operate independently with focused responsibilities
- Request sampling through client interfaces
- Must respect security constraints
- Can be local processes or remote services

## Design Principles

MCP is built on several key design principles that inform its architecture and
implementation:

1. **Servers should be extremely easy to build**

   - Host applications handle complex orchestration responsibilities
   - Servers focus on specific, well-defined capabilities
   - Simple interfaces minimize implementation overhead
   - Clear separation enables maintainable code

2. **Servers should be highly composable**

   - Each server provides focused functionality in isolation
   - Multiple servers can be combined seamlessly
   - Shared protocol enables interoperability
   - Modular design supports extensibility

3. **Servers should not be able to read the whole conversation, nor "see into" other
   servers**

   - Servers receive only necessary contextual information
   - Full conversation history stays with the host
   - Each server connection maintains isolation
   - Cross-server interactions are controlled by the host
   - Host process enforces security boundaries

4. **Features can be added to servers and clients progressively**
   - Core protocol provides minimal required functionality
   - Additional capabilities can be negotiated as needed
   - Servers and clients evolve independently
   - Protocol designed for future extensibility
   - Backwards compatibility is maintained

## Capability Negotiation

The Model Context Protocol uses a capability-based negotiation system where clients and
servers explicitly declare their supported features during initialization. Capabilities
determine which protocol features and primitives are available during a session.

- Servers declare capabilities like resource subscriptions, tool support, and prompt
  templates
- Clients declare capabilities like sampling support and notification handling
- Both parties must respect declared capabilities throughout the session
- Additional capabilities can be negotiated through extensions to the protocol

```mermaid
sequenceDiagram
    participant Host
    participant Client
    participant Server

    Host->>+Client: Initialize client
    Client->>+Server: Initialize session with capabilities
    Server-->>Client: Respond with supported capabilities

    Note over Host,Server: Active Session with Negotiated Features

    loop Client Requests
        Host->>Client: User- or model-initiated action
        Client->>Server: Request (tools/resources)
        Server-->>Client: Response
        Client-->>Host: Update UI or respond to model
    end

    loop Server Requests
        Server->>Client: Request (sampling)
        Client->>Host: Forward to AI
        Host-->>Client: AI response
        Client-->>Server: Response
    end

    loop Notifications
        Server--)Client: Resource updates
        Client--)Server: Status changes
    end

    Host->>Client: Terminate
    Client->>-Server: End session
    deactivate Server
```

Each capability unlocks specific protocol features for use during the session. For
example:

- Implemented [server features]({{< ref "../server" >}}) must be advertised in the
  server's capabilities
- Emitting resource subscription notifications requires the server to declare
  subscription support
- Tool invocation requires the server to declare tool capabilities
- [Sampling]({{< ref "../client" >}}) requires the client to declare support in its
  capabilities

This capability negotiation ensures clients and servers have a clear understanding of
supported functionality while maintaining protocol extensibility.



---
File: /docs/specification/2025-03-26/basic/utilities/_index.md
---

---
title: Utilities
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

These optional features enhance the base protocol functionality with various utilities.

{{< cards >}} {{< card link="ping" title="Ping" icon="status-online" >}}
{{< card link="cancellation" title="Cancellation" icon="x" >}}
{{< card link="progress" title="Progress" icon="clock" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/basic/utilities/cancellation.md
---

---
title: Cancellation
weight: 10
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) supports optional cancellation of in-progress requests
through notification messages. Either side can send a cancellation notification to
indicate that a previously-issued request should be terminated.

## Cancellation Flow

When a party wants to cancel an in-progress request, it sends a `notifications/cancelled`
notification containing:

- The ID of the request to cancel
- An optional reason string that can be logged or displayed

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": "123",
    "reason": "User requested cancellation"
  }
}
```

## Behavior Requirements

1. Cancellation notifications **MUST** only reference requests that:
   - Were previously issued in the same direction
   - Are believed to still be in-progress
2. The `initialize` request **MUST NOT** be cancelled by clients
3. Receivers of cancellation notifications **SHOULD**:
   - Stop processing the cancelled request
   - Free associated resources
   - Not send a response for the cancelled request
4. Receivers **MAY** ignore cancellation notifications if:
   - The referenced request is unknown
   - Processing has already completed
   - The request cannot be cancelled
5. The sender of the cancellation notification **SHOULD** ignore any response to the
   request that arrives afterward

## Timing Considerations

Due to network latency, cancellation notifications may arrive after request processing
has completed, and potentially after a response has already been sent.

Both parties **MUST** handle these race conditions gracefully:

```mermaid
sequenceDiagram
   participant Client
   participant Server

   Client->>Server: Request (ID: 123)
   Note over Server: Processing starts
   Client--)Server: notifications/cancelled (ID: 123)
   alt
      Note over Server: Processing may have<br/>completed before<br/>cancellation arrives
   else If not completed
      Note over Server: Stop processing
   end
```

## Implementation Notes

- Both parties **SHOULD** log cancellation reasons for debugging
- Application UIs **SHOULD** indicate when cancellation is requested

## Error Handling

Invalid cancellation notifications **SHOULD** be ignored:

- Unknown request IDs
- Already completed requests
- Malformed notifications

This maintains the "fire and forget" nature of notifications while allowing for race
conditions in asynchronous communication.



---
File: /docs/specification/2025-03-26/basic/utilities/ping.md
---

---
title: Ping
weight: 5
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol includes an optional ping mechanism that allows either party
to verify that their counterpart is still responsive and the connection is alive.

## Overview

The ping functionality is implemented through a simple request/response pattern. Either
the client or server can initiate a ping by sending a `ping` request.

## Message Format

A ping request is a standard JSON-RPC request with no parameters:

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "method": "ping"
}
```

## Behavior Requirements

1. The receiver **MUST** respond promptly with an empty response:

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "result": {}
}
```

2. If no response is received within a reasonable timeout period, the sender **MAY**:
   - Consider the connection stale
   - Terminate the connection
   - Attempt reconnection procedures

## Usage Patterns

```mermaid
sequenceDiagram
    participant Sender
    participant Receiver

    Sender->>Receiver: ping request
    Receiver->>Sender: empty response
```

## Implementation Considerations

- Implementations **SHOULD** periodically issue pings to detect connection health
- The frequency of pings **SHOULD** be configurable
- Timeouts **SHOULD** be appropriate for the network environment
- Excessive pinging **SHOULD** be avoided to reduce network overhead

## Error Handling

- Timeouts **SHOULD** be treated as connection failures
- Multiple failed pings **MAY** trigger connection reset
- Implementations **SHOULD** log ping failures for diagnostics



---
File: /docs/specification/2025-03-26/basic/utilities/progress.md
---

---
title: Progress
weight: 30
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) supports optional progress tracking for long-running
operations through notification messages. Either side can send progress notifications to
provide updates about operation status.

## Progress Flow

When a party wants to _receive_ progress updates for a request, it includes a
`progressToken` in the request metadata.

- Progress tokens **MUST** be a string or integer value
- Progress tokens can be chosen by the sender using any means, but **MUST** be unique
  across all active requests.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "some_method",
  "params": {
    "_meta": {
      "progressToken": "abc123"
    }
  }
}
```

The receiver **MAY** then send progress notifications containing:

- The original progress token
- The current progress value so far
- An optional "total" value
- An optional "message" value

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/progress",
  "params": {
    "progressToken": "abc123",
    "progress": 50,
    "total": 100,
    "message": "Reticulating splines..."
  }
}
```

- The `progress` value **MUST** increase with each notification, even if the total is
  unknown.
- The `progress` and the `total` values **MAY** be floating point.
- The `message` field **SHOULD** provide relevant human readable progress information.

## Behavior Requirements

1. Progress notifications **MUST** only reference tokens that:

   - Were provided in an active request
   - Are associated with an in-progress operation

2. Receivers of progress requests **MAY**:
   - Choose not to send any progress notifications
   - Send notifications at whatever frequency they deem appropriate
   - Omit the total value if unknown

```mermaid
sequenceDiagram
    participant Sender
    participant Receiver

    Note over Sender,Receiver: Request with progress token
    Sender->>Receiver: Method request with progressToken

    Note over Sender,Receiver: Progress updates
    loop Progress Updates
        Receiver-->>Sender: Progress notification (0.2/1.0)
        Receiver-->>Sender: Progress notification (0.6/1.0)
        Receiver-->>Sender: Progress notification (1.0/1.0)
    end

    Note over Sender,Receiver: Operation complete
    Receiver->>Sender: Method response
```

## Implementation Notes

- Senders and receivers **SHOULD** track active progress tokens
- Both parties **SHOULD** implement rate limiting to prevent flooding
- Progress notifications **MUST** stop after completion



---
File: /docs/specification/2025-03-26/basic/_index.md
---

---
title: Base Protocol
cascade:
  type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol consists of several key components that work together:

- **Base Protocol**: Core JSON-RPC message types
- **Lifecycle Management**: Connection initialization, capability negotiation, and
  session control
- **Server Features**: Resources, prompts, and tools exposed by servers
- **Client Features**: Sampling and root directory lists provided by clients
- **Utilities**: Cross-cutting concerns like logging and argument completion

All implementations **MUST** support the base protocol and lifecycle management
components. Other components **MAY** be implemented based on the specific needs of the
application.

These protocol layers establish clear separation of concerns while enabling rich
interactions between clients and servers. The modular design allows implementations to
support exactly the features they need.

## Messages

All messages between MCP clients and servers **MUST** follow the
[JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. The protocol defines
these types of messages:

### Requests

Requests are sent from the client to the server or vice versa, to initiate an operation.

```typescript
{
  jsonrpc: "2.0";
  id: string | number;
  method: string;
  params?: {
    [key: string]: unknown;
  };
}
```

- Requests **MUST** include a string or integer ID.
- Unlike base JSON-RPC, the ID **MUST NOT** be `null`.
- The request ID **MUST NOT** have been previously used by the requestor within the same
  session.

### Responses

Responses are sent in reply to requests, containing the result or error of the operation.

```typescript
{
  jsonrpc: "2.0";
  id: string | number;
  result?: {
    [key: string]: unknown;
  }
  error?: {
    code: number;
    message: string;
    data?: unknown;
  }
}
```

- Responses **MUST** include the same ID as the request they correspond to.
- **Responses** are further sub-categorized as either **successful results** or
  **errors**. Either a `result` or an `error` **MUST** be set. A response **MUST NOT**
  set both.
- Results **MAY** follow any JSON object structure, while errors **MUST** include an
  error code and message at minimum.
- Error codes **MUST** be integers.

### Notifications

Notifications are sent from the client to the server or vice versa, as a one-way message.
The receiver **MUST NOT** send a response.

```typescript
{
  jsonrpc: "2.0";
  method: string;
  params?: {
    [key: string]: unknown;
  };
}
```

- Notifications **MUST NOT** include an ID.

### Batching

JSON-RPC also defines a means to
[batch multiple requests and notifications](https://www.jsonrpc.org/specification#batch),
by sending them in an array. MCP implementations **MAY** support sending JSON-RPC
batches, but **MUST** support receiving JSON-RPC batches.

## Auth

MCP provides an [Authorization]({{< ref "authorization" >}}) framework for use with HTTP.
Implementations using an HTTP-based transport **SHOULD** conform to this specification,
whereas implementations using STDIO transport **SHOULD NOT** follow this specification,
and instead retrieve credentials from the environment.

Additionally, clients and servers **MAY** negotiate their own custom authentication and
authorization strategies.

For further discussions and contributions to the evolution of MCP’s auth mechanisms, join
us in
[GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions)
to help shape the future of the protocol!

## Schema

The full specification of the protocol is defined as a
[TypeScript schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.ts).
This is the source of truth for all protocol messages and structures.

There is also a
[JSON Schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.json),
which is automatically generated from the TypeScript source of truth, for use with
various automated tooling.



---
File: /docs/specification/2025-03-26/basic/authorization.md
---

---
title: Authorization
type: docs
weight: 15
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

## 1. Introduction

### 1.1 Purpose and Scope

The Model Context Protocol provides authorization capabilities at the transport level,
enabling MCP clients to make requests to restricted MCP servers on behalf of resource
owners. This specification defines the authorization flow for HTTP-based transports.

### 1.2 Protocol Requirements

Authorization is **OPTIONAL** for MCP implementations. When supported:

- Implementations using an HTTP-based transport **SHOULD** conform to this specification.
- Implementations using an STDIO transport **SHOULD NOT** follow this specification, and
  instead retrieve credentials from the environment.
- Implementations using alternative transports **MUST** follow established security best
  practices for their protocol.

### 1.3 Standards Compliance

This authorization mechanism is based on established specifications listed below, but
implements a selected subset of their features to ensure security and interoperability
while maintaining simplicity:

- [OAuth 2.1 IETF DRAFT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12)
- OAuth 2.0 Authorization Server Metadata
  ([RFC8414](https://datatracker.ietf.org/doc/html/rfc8414))
- OAuth 2.0 Dynamic Client Registration Protocol
  ([RFC7591](https://datatracker.ietf.org/doc/html/rfc7591))

## 2. Authorization Flow

### 2.1 Overview

1. MCP auth implementations **MUST** implement OAuth 2.1 with appropriate security
   measures for both confidential and public clients.

2. MCP auth implementations **SHOULD** support the OAuth 2.0 Dynamic Client Registration
   Protocol ([RFC7591](https://datatracker.ietf.org/doc/html/rfc7591)).

3. MCP servers **SHOULD** and MCP clients **MUST** implement OAuth 2.0 Authorization
   Server Metadata ([RFC8414](https://datatracker.ietf.org/doc/html/rfc8414)). Servers
   that do not support Authorization Server Metadata **MUST** follow the default URI
   schema.

### 2.2 Basic OAuth 2.1 Authorization

When authorization is required and not yet proven by the client, servers **MUST** respond
with _HTTP 401 Unauthorized_.

Clients initiate the
[OAuth 2.1 IETF DRAFT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12)
authorization flow after receiving the _HTTP 401 Unauthorized_.

The following demonstrates the basic OAuth 2.1 for public clients using PKCE.

```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as Client
    participant M as MCP Server

    C->>M: MCP Request
    M->>C: HTTP 401 Unauthorized
    Note over C: Generate code_verifier and code_challenge
    C->>B: Open browser with authorization URL + code_challenge
    B->>M: GET /authorize
    Note over M: User logs in and authorizes
    M->>B: Redirect to callback URL with auth code
    B->>C: Callback with authorization code
    C->>M: Token Request with code + code_verifier
    M->>C: Access Token (+ Refresh Token)
    C->>M: MCP Request with Access Token
    Note over C,M: Begin standard MCP message exchange
```

### 2.3 Server Metadata Discovery

For server capability discovery:

- MCP clients _MUST_ follow the OAuth 2.0 Authorization Server Metadata protocol defined
  in [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414).
- MCP server _SHOULD_ follow the OAuth 2.0 Authorization Server Metadata protocol.
- MCP servers that do not support the OAuth 2.0 Authorization Server Metadata protocol,
  _MUST_ support fallback URLs.

The discovery flow is illustrated below:

```mermaid
sequenceDiagram
    participant C as Client
    participant S as Server

    C->>S: GET /.well-known/oauth-authorization-server
    alt Discovery Success
        S->>C: 200 OK + Metadata Document
        Note over C: Use endpoints from metadata
    else Discovery Failed
        S->>C: 404 Not Found
        Note over C: Fall back to default endpoints
    end
    Note over C: Continue with authorization flow
```

#### 2.3.1 Server Metadata Discovery Headers

MCP clients _SHOULD_ include the header `MCP-Protocol-Version: <protocol-version>` during
Server Metadata Discovery to allow the MCP server to respond based on the MCP protocol
version.

For example: `MCP-Protocol-Version: 2024-11-05`

#### 2.3.2 Authorization Base URL

The authorization base URL **MUST** be determined from the MCP server URL by discarding
any existing `path` component. For example:

If the MCP server URL is `https://api.example.com/v1/mcp`, then:

- The authorization base URL is `https://api.example.com`
- The metadata endpoint **MUST** be at
  `https://api.example.com/.well-known/oauth-authorization-server`

This ensures authorization endpoints are consistently located at the root level of the
domain hosting the MCP server, regardless of any path components in the MCP server URL.

#### 2.3.3 Fallbacks for Servers without Metadata Discovery

For servers that do not implement OAuth 2.0 Authorization Server Metadata, clients
**MUST** use the following default endpoint paths relative to the authorization base URL
(as defined in [Section 2.3.2](#232-authorization-base-url)):

| Endpoint               | Default Path | Description                          |
| ---------------------- | ------------ | ------------------------------------ |
| Authorization Endpoint | /authorize   | Used for authorization requests      |
| Token Endpoint         | /token       | Used for token exchange & refresh    |
| Registration Endpoint  | /register    | Used for dynamic client registration |

For example, with an MCP server hosted at `https://api.example.com/v1/mcp`, the default
endpoints would be:

- `https://api.example.com/authorize`
- `https://api.example.com/token`
- `https://api.example.com/register`

Clients **MUST** first attempt to discover endpoints via the metadata document before
falling back to default paths. When using default paths, all other protocol requirements
remain unchanged.

### 2.3 Dynamic Client Registration

MCP clients and servers **SHOULD** support the
[OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591)
to allow MCP clients to obtain OAuth client IDs without user interaction. This provides a
standardized way for clients to automatically register with new servers, which is crucial
for MCP because:

- Clients cannot know all possible servers in advance
- Manual registration would create friction for users
- It enables seamless connection to new servers
- Servers can implement their own registration policies

Any MCP servers that _do not_ support Dynamic Client Registration need to provide
alternative ways to obtain a client ID (and, if applicable, client secret). For one of
these servers, MCP clients will have to either:

1. Hardcode a client ID (and, if applicable, client secret) specifically for that MCP
   server, or
2. Present a UI to users that allows them to enter these details, after registering an
   OAuth client themselves (e.g., through a configuration interface hosted by the
   server).

### 2.4 Authorization Flow Steps

The complete Authorization flow proceeds as follows:

```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as Client
    participant M as MCP Server

    C->>M: GET /.well-known/oauth-authorization-server
    alt Server Supports Discovery
        M->>C: Authorization Server Metadata
    else No Discovery
        M->>C: 404 (Use default endpoints)
    end

    alt Dynamic Client Registration
        C->>M: POST /register
        M->>C: Client Credentials
    end

    Note over C: Generate PKCE Parameters
    C->>B: Open browser with authorization URL + code_challenge
    B->>M: Authorization Request
    Note over M: User /authorizes
    M->>B: Redirect to callback with authorization code
    B->>C: Authorization code callback
    C->>M: Token Request + code_verifier
    M->>C: Access Token (+ Refresh Token)
    C->>M: API Requests with Access Token
```

#### 2.4.1 Decision Flow Overview

```mermaid
flowchart TD
    A[Start Auth Flow] --> B{Check Metadata Discovery}
    B -->|Available| C[Use Metadata Endpoints]
    B -->|Not Available| D[Use Default Endpoints]

    C --> G{Check Registration Endpoint}
    D --> G

    G -->|Available| H[Perform Dynamic Registration]
    G -->|Not Available| I[Alternative Registration Required]

    H --> J[Start OAuth Flow]
    I --> J

    J --> K[Generate PKCE Parameters]
    K --> L[Request Authorization]
    L --> M[User Authorization]
    M --> N[Exchange Code for Tokens]
    N --> O[Use Access Token]
```

### 2.5 Access Token Usage

#### 2.5.1 Token Requirements

Access token handling **MUST** conform to
[OAuth 2.1 Section 5](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5)
requirements for resource requests. Specifically:

1. MCP client **MUST** use the Authorization request header field
   [Section 5.1.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.1.1):

```
Authorization: Bearer <access-token>
```

Note that authorization **MUST** be included in every HTTP request from client to server,
even if they are part of the same logical session.

2. Access tokens **MUST NOT** be included in the URI query string

Example request:

```http
GET /v1/contexts HTTP/1.1
Host: mcp.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```

#### 2.5.2 Token Handling

Resource servers **MUST** validate access tokens as described in
[Section 5.2](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.2).
If validation fails, servers **MUST** respond according to
[Section 5.3](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.3)
error handling requirements. Invalid or expired tokens **MUST** receive a HTTP 401
response.

### 2.6 Security Considerations

The following security requirements **MUST** be implemented:

1. Clients **MUST** securely store tokens following OAuth 2.0 best practices
2. Servers **SHOULD** enforce token expiration and rotation
3. All authorization endpoints **MUST** be served over HTTPS
4. Servers **MUST** validate redirect URIs to prevent open redirect vulnerabilities
5. Redirect URIs **MUST** be either localhost URLs or HTTPS URLs

### 2.7 Error Handling

Servers **MUST** return appropriate HTTP status codes for authorization errors:

| Status Code | Description  | Usage                                      |
| ----------- | ------------ | ------------------------------------------ |
| 401         | Unauthorized | Authorization required or token invalid    |
| 403         | Forbidden    | Invalid scopes or insufficient permissions |
| 400         | Bad Request  | Malformed authorization request            |

### 2.8 Implementation Requirements

1. Implementations **MUST** follow OAuth 2.1 security best practices
2. PKCE is **REQUIRED** for all clients
3. Token rotation **SHOULD** be implemented for enhanced security
4. Token lifetimes **SHOULD** be limited based on security requirements

### 2.9 Third-Party Authorization Flow

#### 2.9.1 Overview

MCP servers **MAY** support delegated authorization through third-party authorization
servers. In this flow, the MCP server acts as both an OAuth client (to the third-party
auth server) and an OAuth authorization server (to the MCP client).

#### 2.9.2 Flow Description

The third-party authorization flow comprises these steps:

1. MCP client initiates standard OAuth flow with MCP server
2. MCP server redirects user to third-party authorization server
3. User authorizes with third-party server
4. Third-party server redirects back to MCP server with authorization code
5. MCP server exchanges code for third-party access token
6. MCP server generates its own access token bound to the third-party session
7. MCP server completes original OAuth flow with MCP client

```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as MCP Client
    participant M as MCP Server
    participant T as Third-Party Auth Server

    C->>M: Initial OAuth Request
    M->>B: Redirect to Third-Party /authorize
    B->>T: Authorization Request
    Note over T: User authorizes
    T->>B: Redirect to MCP Server callback
    B->>M: Authorization code
    M->>T: Exchange code for token
    T->>M: Third-party access token
    Note over M: Generate bound MCP token
    M->>B: Redirect to MCP Client callback
    B->>C: MCP authorization code
    C->>M: Exchange code for token
    M->>C: MCP access token
```

#### 2.9.3 Session Binding Requirements

MCP servers implementing third-party authorization **MUST**:

1. Maintain secure mapping between third-party tokens and issued MCP tokens
2. Validate third-party token status before honoring MCP tokens
3. Implement appropriate token lifecycle management
4. Handle third-party token expiration and renewal

#### 2.9.4 Security Considerations

When implementing third-party authorization, servers **MUST**:

1. Validate all redirect URIs
2. Securely store third-party credentials
3. Implement appropriate session timeout handling
4. Consider security implications of token chaining
5. Implement proper error handling for third-party auth failures

## 3. Best Practices

#### 3.1 Local clients as Public OAuth 2.1 Clients

We strongly recommend that local clients implement OAuth 2.1 as a public client:

1. Utilizing code challenges (PKCE) for authorization requests to prevent interception
   attacks
2. Implementing secure token storage appropriate for the local system
3. Following token refresh best practices to maintain sessions
4. Properly handling token expiration and renewal

#### 3.2 Authorization Metadata Discovery

We strongly recommend that all clients implement metadata discovery. This reduces the
need for users to provide endpoints manually or clients to fallback to the defined
defaults.

#### 3.3 Dynamic Client Registration

Since clients do not know the set of MCP servers in advance, we strongly recommend the
implementation of dynamic client registration. This allows applications to automatically
register with the MCP server, and removes the need for users to obtain client ids
manually.



---
File: /docs/specification/2025-03-26/basic/lifecycle.md
---

---
title: Lifecycle
type: docs
weight: 30
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) defines a rigorous lifecycle for client-server
connections that ensures proper capability negotiation and state management.

1. **Initialization**: Capability negotiation and protocol version agreement
2. **Operation**: Normal protocol communication
3. **Shutdown**: Graceful termination of the connection

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Initialization Phase
    activate Client
    Client->>+Server: initialize request
    Server-->>Client: initialize response
    Client--)Server: initialized notification

    Note over Client,Server: Operation Phase
    rect rgb(200, 220, 250)
        note over Client,Server: Normal protocol operations
    end

    Note over Client,Server: Shutdown
    Client--)-Server: Disconnect
    deactivate Server
    Note over Client,Server: Connection closed
```

## Lifecycle Phases

### Initialization

The initialization phase **MUST** be the first interaction between client and server.
During this phase, the client and server:

- Establish protocol version compatibility
- Exchange and negotiate capabilities
- Share implementation details

The client **MUST** initiate this phase by sending an `initialize` request containing:

- Protocol version supported
- Client capabilities
- Client implementation information

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "roots": {
        "listChanged": true
      },
      "sampling": {}
    },
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

The initialize request **MUST NOT** be part of a JSON-RPC
[batch](https://www.jsonrpc.org/specification#batch), as other requests and notifications
are not possible until initialization has completed. This also permits backwards
compatibility with prior protocol versions that do not explicitly support JSON-RPC
batches.

The server **MUST** respond with its own capabilities and information:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "logging": {},
      "prompts": {
        "listChanged": true
      },
      "resources": {
        "subscribe": true,
        "listChanged": true
      },
      "tools": {
        "listChanged": true
      }
    },
    "serverInfo": {
      "name": "ExampleServer",
      "version": "1.0.0"
    }
  }
}
```

After successful initialization, the client **MUST** send an `initialized` notification
to indicate it is ready to begin normal operations:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
```

- The client **SHOULD NOT** send requests other than
  [pings]({{< ref "utilities/ping" >}}) before the server has responded to the
  `initialize` request.
- The server **SHOULD NOT** send requests other than
  [pings]({{< ref "utilities/ping" >}}) and
  [logging]({{< ref "../server/utilities/logging" >}}) before receiving the `initialized`
  notification.

#### Version Negotiation

In the `initialize` request, the client **MUST** send a protocol version it supports.
This **SHOULD** be the _latest_ version supported by the client.

If the server supports the requested protocol version, it **MUST** respond with the same
version. Otherwise, the server **MUST** respond with another protocol version it
supports. This **SHOULD** be the _latest_ version supported by the server.

If the client does not support the version in the server's response, it **SHOULD**
disconnect.

#### Capability Negotiation

Client and server capabilities establish which optional protocol features will be
available during the session.

Key capabilities include:

| Category | Capability     | Description                                                                |
| -------- | -------------- | -------------------------------------------------------------------------- |
| Client   | `roots`        | Ability to provide filesystem [roots]({{< ref "../client/roots" >}})       |
| Client   | `sampling`     | Support for LLM [sampling]({{< ref "../client/sampling" >}}) requests      |
| Client   | `experimental` | Describes support for non-standard experimental features                   |
| Server   | `prompts`      | Offers [prompt templates]({{< ref "../server/prompts" >}})                 |
| Server   | `resources`    | Provides readable [resources]({{< ref "../server/resources" >}})           |
| Server   | `tools`        | Exposes callable [tools]({{< ref "../server/tools" >}})                    |
| Server   | `logging`      | Emits structured [log messages]({{< ref "../server/utilities/logging" >}}) |
| Server   | `experimental` | Describes support for non-standard experimental features                   |

Capability objects can describe sub-capabilities like:

- `listChanged`: Support for list change notifications (for prompts, resources, and
  tools)
- `subscribe`: Support for subscribing to individual items' changes (resources only)

### Operation

During the operation phase, the client and server exchange messages according to the
negotiated capabilities.

Both parties **SHOULD**:

- Respect the negotiated protocol version
- Only use capabilities that were successfully negotiated

### Shutdown

During the shutdown phase, one side (usually the client) cleanly terminates the protocol
connection. No specific shutdown messages are defined—instead, the underlying transport
mechanism should be used to signal connection termination:

#### stdio

For the stdio [transport]({{< ref "transports" >}}), the client **SHOULD** initiate
shutdown by:

1. First, closing the input stream to the child process (the server)
2. Waiting for the server to exit, or sending `SIGTERM` if the server does not exit
   within a reasonable time
3. Sending `SIGKILL` if the server does not exit within a reasonable time after `SIGTERM`

The server **MAY** initiate shutdown by closing its output stream to the client and
exiting.

#### HTTP

For HTTP [transports]({{< ref "transports" >}}), shutdown is indicated by closing the
associated HTTP connection(s).

## Timeouts

Implementations **SHOULD** establish timeouts for all sent requests, to prevent hung
connections and resource exhaustion. When the request has not received a success or error
response within the timeout period, the sender **SHOULD** issue a [cancellation
notification]({{< ref "utilities/cancellation" >}}) for that request and stop waiting for
a response.

SDKs and other middleware **SHOULD** allow these timeouts to be configured on a
per-request basis.

Implementations **MAY** choose to reset the timeout clock when receiving a [progress
notification]({{< ref "utilities/progress" >}}) corresponding to the request, as this
implies that work is actually happening. However, implementations **SHOULD** always
enforce a maximum timeout, regardless of progress notifications, to limit the impact of a
misbehaving client or server.

## Error Handling

Implementations **SHOULD** be prepared to handle these error cases:

- Protocol version mismatch
- Failure to negotiate required capabilities
- Request [timeouts](#timeouts)

Example initialization error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Unsupported protocol version",
    "data": {
      "supported": ["2024-11-05"],
      "requested": "1.0.0"
    }
  }
}
```



---
File: /docs/specification/2025-03-26/basic/transports.md
---

---
title: Transports
type: docs
weight: 10
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

MCP uses JSON-RPC to encode messages. JSON-RPC messages **MUST** be UTF-8 encoded.

The protocol currently defines two standard transport mechanisms for client-server
communication:

1. [stdio](#stdio), communication over standard in and standard out
2. [Streamable HTTP](#streamable-http)

Clients **SHOULD** support stdio whenever possible.

It is also possible for clients and servers to implement
[custom transports](#custom-transports) in a pluggable fashion.

## stdio

In the **stdio** transport:

- The client launches the MCP server as a subprocess.
- The server reads JSON-RPC messages from its standard input (`stdin`) and sends messages
  to its standard output (`stdout`).
- Messages may be JSON-RPC requests, notifications, responses—or a JSON-RPC
  [batch](https://www.jsonrpc.org/specification#batch) containing one or more requests
  and/or notifications.
- Messages are delimited by newlines, and **MUST NOT** contain embedded newlines.
- The server **MAY** write UTF-8 strings to its standard error (`stderr`) for logging
  purposes. Clients **MAY** capture, forward, or ignore this logging.
- The server **MUST NOT** write anything to its `stdout` that is not a valid MCP message.
- The client **MUST NOT** write anything to the server's `stdin` that is not a valid MCP
  message.

```mermaid
sequenceDiagram
    participant Client
    participant Server Process

    Client->>+Server Process: Launch subprocess
    loop Message Exchange
        Client->>Server Process: Write to stdin
        Server Process->>Client: Write to stdout
        Server Process--)Client: Optional logs on stderr
    end
    Client->>Server Process: Close stdin, terminate subprocess
    deactivate Server Process
```

## Streamable HTTP

{{< callout type="info" >}} This replaces the [HTTP+SSE
transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) from
protocol version 2024-11-05. See the [backwards compatibility](#backwards-compatibility)
guide below. {{< /callout >}}

In the **Streamable HTTP** transport, the server operates as an independent process that
can handle multiple client connections. This transport uses HTTP POST and GET requests.
Server can optionally make use of
[Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) (SSE) to stream
multiple server messages. This permits basic MCP servers, as well as more feature-rich
servers supporting streaming and server-to-client notifications and requests.

The server **MUST** provide a single HTTP endpoint path (hereafter referred to as the
**MCP endpoint**) that supports both POST and GET methods. For example, this could be a
URL like `https://example.com/mcp`.

### Sending Messages to the Server

Every JSON-RPC message sent from the client **MUST** be a new HTTP POST request to the
MCP endpoint.

1. The client **MUST** use HTTP POST to send JSON-RPC messages to the MCP endpoint.
2. The client **MUST** include an `Accept` header, listing both `application/json` and
   `text/event-stream` as supported content types.
3. The body of the POST request **MUST** be one of the following:
   - A single JSON-RPC _request_, _notification_, or _response_
   - An array [batching](https://www.jsonrpc.org/specification#batch) one or more
     _requests and/or notifications_
   - An array [batching](https://www.jsonrpc.org/specification#batch) one or more
     _responses_
4. If the input consists solely of (any number of) JSON-RPC _responses_ or
   _notifications_:
   - If the server accepts the input, the server **MUST** return HTTP status code 202
     Accepted with no body.
   - If the server cannot accept the input, it **MUST** return an HTTP error status code
     (e.g., 400 Bad Request). The HTTP response body **MAY** comprise a JSON-RPC _error
     response_ that has no `id`.
5. If the input contains any number of JSON-RPC _requests_, the server **MUST** either
   return `Content-Type: text/event-stream`, to initiate an SSE stream, or
   `Content-Type: application/json`, to return one JSON object. The client **MUST**
   support both these cases.
6. If the server initiates an SSE stream:
   - The SSE stream **SHOULD** eventually include one JSON-RPC _response_ per each
     JSON-RPC _request_ sent in the POST body. These _responses_ **MAY** be
     [batched](https://www.jsonrpc.org/specification#batch).
   - The server **MAY** send JSON-RPC _requests_ and _notifications_ before sending a
     JSON-RPC _response_. These messages **SHOULD** relate to the originating client
     _request_. These _requests_ and _notifications_ **MAY** be
     [batched](https://www.jsonrpc.org/specification#batch).
   - The server **SHOULD NOT** close the SSE stream before sending a JSON-RPC _response_
     per each received JSON-RPC _request_, unless the [session](#session-management)
     expires.
   - After all JSON-RPC _responses_ have been sent, the server **SHOULD** close the SSE
     stream.
   - Disconnection **MAY** occur at any time (e.g., due to network conditions).
     Therefore:
     - Disconnection **SHOULD NOT** be interpreted as the client cancelling its request.
     - To cancel, the client **SHOULD** explicitly send an MCP `CancelledNotification`.
     - To avoid message loss due to disconnection, the server **MAY** make the stream
       [resumable](#resumability-and-redelivery).

### Listening for Messages from the Server

1. The client **MAY** issue an HTTP GET to the MCP endpoint. This can be used to open an
   SSE stream, allowing the server to communicate to the client, without the client first
   sending data via HTTP POST.
2. The client **MUST** include an `Accept` header, listing `text/event-stream` as a
   supported content type.
3. The server **MUST** either return `Content-Type: text/event-stream` in response to
   this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the server
   does not offer an SSE stream at this endpoint.
4. If the server initiates an SSE stream:
   - The server **MAY** send JSON-RPC _requests_ and _notifications_ on the stream. These
     _requests_ and _notifications_ **MAY** be
     [batched](https://www.jsonrpc.org/specification#batch).
   - These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC
     _request_ from the client.
   - The server **MUST NOT** send a JSON-RPC _response_ on the stream **unless**
     [resuming](#resumability-and-redelivery) a stream associated with a previous client
     request.
   - The server **MAY** close the SSE stream at any time.
   - The client **MAY** close the SSE stream at any time.

### Multiple Connections

1. The client **MAY** remain connected to multiple SSE streams simultaneously.
2. The server **MUST** send each of its JSON-RPC messages on only one of the connected
   streams; that is, it **MUST NOT** broadcast the same message across multiple streams.
   - The risk of message loss **MAY** be mitigated by making the stream
     [resumable](#resumability-and-redelivery).

### Resumability and Redelivery

To support resuming broken connections, and redelivering messages that might otherwise be
lost:

1. Servers **MAY** attach an `id` field to their SSE events, as described in the
   [SSE standard](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation).
   - If present, the ID **MUST** be globally unique across all streams within that
     [session](#session-management)—or all streams with that specific client, if session
     management is not in use.
2. If the client wishes to resume after a broken connection, it **SHOULD** issue an HTTP
   GET to the MCP endpoint, and include the
   [`Last-Event-ID`](https://html.spec.whatwg.org/multipage/server-sent-events.html#the-last-event-id-header)
   header to indicate the last event ID it received.
   - The server **MAY** use this header to replay messages that would have been sent
     after the last event ID, _on the stream that was disconnected_, and to resume the
     stream from that point.
   - The server **MUST NOT** replay messages that would have been delivered on a
     different stream.

In other words, these event IDs should be assigned by servers on a _per-stream_ basis, to
act as a cursor within that particular stream.

### Session Management

An MCP "session" consists of logically related interactions between a client and a
server, beginning with the [initialization phase]({{< ref "lifecycle" >}}). To support
servers which want to establish stateful sessions:

1. A server using the Streamable HTTP transport **MAY** assign a session ID at
   initialization time, by including it in an `Mcp-Session-Id` header on the HTTP
   response containing the `InitializeResult`.
   - The session ID **SHOULD** be globally unique and cryptographically secure (e.g., a
     securely generated UUID, a JWT, or a cryptographic hash).
   - The session ID **MUST** only contain visible ASCII characters (ranging from 0x21 to
     0x7E).
2. If an `Mcp-Session-Id` is returned by the server during initialization, clients using
   the Streamable HTTP transport **MUST** include it in the `Mcp-Session-Id` header on
   all of their subsequent HTTP requests.
   - Servers that require a session ID **SHOULD** respond to requests without an
     `Mcp-Session-Id` header (other than initialization) with HTTP 400 Bad Request.
3. The server **MAY** terminate the session at any time, after which it **MUST** respond
   to requests containing that session ID with HTTP 404 Not Found.
4. When a client receives HTTP 404 in response to a request containing an
   `Mcp-Session-Id`, it **MUST** start a new session by sending a new `InitializeRequest`
   without a session ID attached.
5. Clients that no longer need a particular session (e.g., because the user is leaving
   the client application) **SHOULD** send an HTTP DELETE to the MCP endpoint with the
   `Mcp-Session-Id` header, to explicitly terminate the session.
   - The server **MAY** respond to this request with HTTP 405 Method Not Allowed,
     indicating that the server does not allow clients to terminate sessions.

### Sequence Diagram

```mermaid
sequenceDiagram
    participant Client
    participant Server

    note over Client, Server: initialization

    Client->>+Server: POST InitializeRequest
    Server->>-Client: InitializeResponse<br>Mcp-Session-Id: 1868a90c...

    Client->>+Server: POST InitializedNotification<br>Mcp-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted

    note over Client, Server: client requests
    Client->>+Server: POST ... request ...<br>Mcp-Session-Id: 1868a90c...

    alt single HTTP response
      Server->>Client: ... response ...
    else server opens SSE stream
      loop while connection remains open
          Server-)Client: ... SSE messages from server ...
      end
      Server-)Client: SSE event: ... response ...
    end
    deactivate Server

    note over Client, Server: client notifications/responses
    Client->>+Server: POST ... notification/response ...<br>Mcp-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted

    note over Client, Server: server requests
    Client->>+Server: GET<br>Mcp-Session-Id: 1868a90c...
    loop while connection remains open
        Server-)Client: ... SSE messages from server ...
    end
    deactivate Server

```

### Backwards Compatibility

Clients and servers can maintain backwards compatibility with the deprecated [HTTP+SSE
transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) (from
protocol version 2024-11-05) as follows:

**Servers** wanting to support older clients should:

- Continue to host both the SSE and POST endpoints of the old transport, alongside the
  new "MCP endpoint" defined for the Streamable HTTP transport.
  - It is also possible to combine the old POST endpoint and the new MCP endpoint, but
    this may introduce unneeded complexity.

**Clients** wanting to support older servers should:

1. Accept an MCP server URL from the user, which may point to either a server using the
   old transport or the new transport.
2. Attempt to POST an `InitializeRequest` to the server URL, with an `Accept` header as
   defined above:
   - If it succeeds, the client can assume this is a server supporting the new Streamable
     HTTP transport.
   - If it fails with an HTTP 4xx status code (e.g., 405 Method Not Allowed or 404 Not
     Found):
     - Issue a GET request to the server URL, expecting that this will open an SSE stream
       and return an `endpoint` event as the first event.
     - When the `endpoint` event arrives, the client can assume this is a server running
       the old HTTP+SSE transport, and should use that transport for all subsequent
       communication.

## Custom Transports

Clients and servers **MAY** implement additional custom transport mechanisms to suit
their specific needs. The protocol is transport-agnostic and can be implemented over any
communication channel that supports bidirectional message exchange.

Implementers who choose to support custom transports **MUST** ensure they preserve the
JSON-RPC message format and lifecycle requirements defined by MCP. Custom transports
**SHOULD** document their specific connection establishment and message exchange patterns
to aid interoperability.



---
File: /docs/specification/2025-03-26/client/_index.md
---

---
title: Client Features
cascade:
  type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

Clients can implement additional features to enrich connected MCP servers:

{{< cards >}} {{< card link="roots" title="Roots" icon="folder" >}}
{{< card link="sampling" title="Sampling" icon="annotation" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/client/roots.md
---

---
title: Roots
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for clients to expose
filesystem "roots" to servers. Roots define the boundaries of where servers can operate
within the filesystem, allowing them to understand which directories and files they have
access to. Servers can request the list of roots from supporting clients and receive
notifications when that list changes.

## User Interaction Model

Roots in MCP are typically exposed through workspace or project configuration interfaces.

For example, implementations could offer a workspace/project picker that allows users to
select directories and files the server should have access to. This can be combined with
automatic workspace detection from version control systems or project files.

However, implementations are free to expose roots through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Capabilities

Clients that support roots **MUST** declare the `roots` capability during
[initialization]({{< ref "../basic/lifecycle#initialization" >}}):

```json
{
  "capabilities": {
    "roots": {
      "listChanged": true
    }
  }
}
```

`listChanged` indicates whether the client will emit notifications when the list of roots
changes.

## Protocol Messages

### Listing Roots

To retrieve roots, servers send a `roots/list` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "roots/list"
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "roots": [
      {
        "uri": "file:///home/user/projects/myproject",
        "name": "My Project"
      }
    ]
  }
}
```

### Root List Changes

When roots change, clients that support `listChanged` **MUST** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/roots/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Server
    participant Client

    Note over Server,Client: Discovery
    Server->>Client: roots/list
    Client-->>Server: Available roots

    Note over Server,Client: Changes
    Client--)Server: notifications/roots/list_changed
    Server->>Client: roots/list
    Client-->>Server: Updated roots
```

## Data Types

### Root

A root definition includes:

- `uri`: Unique identifier for the root. This **MUST** be a `file://` URI in the current
  specification.
- `name`: Optional human-readable name for display purposes.

Example roots for different use cases:

#### Project Directory

```json
{
  "uri": "file:///home/user/projects/myproject",
  "name": "My Project"
}
```

#### Multiple Repositories

```json
[
  {
    "uri": "file:///home/user/repos/frontend",
    "name": "Frontend Repository"
  },
  {
    "uri": "file:///home/user/repos/backend",
    "name": "Backend Repository"
  }
]
```

## Error Handling

Clients **SHOULD** return standard JSON-RPC errors for common failure cases:

- Client does not support roots: `-32601` (Method not found)
- Internal errors: `-32603`

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Roots not supported",
    "data": {
      "reason": "Client does not have roots capability"
    }
  }
}
```

## Security Considerations

1. Clients **MUST**:

   - Only expose roots with appropriate permissions
   - Validate all root URIs to prevent path traversal
   - Implement proper access controls
   - Monitor root accessibility

2. Servers **SHOULD**:
   - Handle cases where roots become unavailable
   - Respect root boundaries during operations
   - Validate all paths against provided roots

## Implementation Guidelines

1. Clients **SHOULD**:

   - Prompt users for consent before exposing roots to servers
   - Provide clear user interfaces for root management
   - Validate root accessibility before exposing
   - Monitor for root changes

2. Servers **SHOULD**:
   - Check for roots capability before usage
   - Handle root list changes gracefully
   - Respect root boundaries in operations
   - Cache root information appropriately



---
File: /docs/specification/2025-03-26/client/sampling.md
---

---
title: Sampling
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to request LLM
sampling ("completions" or "generations") from language models via clients. This flow
allows clients to maintain control over model access, selection, and permissions while
enabling servers to leverage AI capabilities&mdash;with no server API keys necessary.
Servers can request text, audio, or image-based interactions and optionally include
context from MCP servers in their prompts.

## User Interaction Model

Sampling in MCP allows servers to implement agentic behaviors, by enabling LLM calls to
occur _nested_ inside other MCP server features.

Implementations are free to expose sampling through any interface pattern that suits
their needs&mdash;the protocol itself does not mandate any specific user interaction
model.

{{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
be a human in the loop with the ability to deny sampling requests.

Applications **SHOULD**:

- Provide UI that makes it easy and intuitive to review sampling requests
- Allow users to view and edit prompts before sending
- Present generated responses for review before delivery {{< /callout >}}

## Capabilities

Clients that support sampling **MUST** declare the `sampling` capability during
[initialization]({{< ref "../basic/lifecycle#initialization" >}}):

```json
{
  "capabilities": {
    "sampling": {}
  }
}
```

## Protocol Messages

### Creating Messages

To request a language model generation, servers send a `sampling/createMessage` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "What is the capital of France?"
        }
      }
    ],
    "modelPreferences": {
      "hints": [
        {
          "name": "claude-3-sonnet"
        }
      ],
      "intelligencePriority": 0.8,
      "speedPriority": 0.5
    },
    "systemPrompt": "You are a helpful assistant.",
    "maxTokens": 100
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "role": "assistant",
    "content": {
      "type": "text",
      "text": "The capital of France is Paris."
    },
    "model": "claude-3-sonnet-20240307",
    "stopReason": "endTurn"
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Server
    participant Client
    participant User
    participant LLM

    Note over Server,Client: Server initiates sampling
    Server->>Client: sampling/createMessage

    Note over Client,User: Human-in-the-loop review
    Client->>User: Present request for approval
    User-->>Client: Review and approve/modify

    Note over Client,LLM: Model interaction
    Client->>LLM: Forward approved request
    LLM-->>Client: Return generation

    Note over Client,User: Response review
    Client->>User: Present response for approval
    User-->>Client: Review and approve/modify

    Note over Server,Client: Complete request
    Client-->>Server: Return approved response
```

## Data Types

### Messages

Sampling messages can contain:

#### Text Content

```json
{
  "type": "text",
  "text": "The message content"
}
```

#### Image Content

```json
{
  "type": "image",
  "data": "base64-encoded-image-data",
  "mimeType": "image/jpeg"
}
```

#### Audio Content

```json
{
  "type": "audio",
  "data": "base64-encoded-audio-data",
  "mimeType": "audio/wav"
}
```

### Model Preferences

Model selection in MCP requires careful abstraction since servers and clients may use
different AI providers with distinct model offerings. A server cannot simply request a
specific model by name since the client may not have access to that exact model or may
prefer to use a different provider's equivalent model.

To solve this, MCP implements a preference system that combines abstract capability
priorities with optional model hints:

#### Capability Priorities

Servers express their needs through three normalized priority values (0-1):

- `costPriority`: How important is minimizing costs? Higher values prefer cheaper models.
- `speedPriority`: How important is low latency? Higher values prefer faster models.
- `intelligencePriority`: How important are advanced capabilities? Higher values prefer
  more capable models.

#### Model Hints

While priorities help select models based on characteristics, `hints` allow servers to
suggest specific models or model families:

- Hints are treated as substrings that can match model names flexibly
- Multiple hints are evaluated in order of preference
- Clients **MAY** map hints to equivalent models from different providers
- Hints are advisory&mdash;clients make final model selection

For example:

```json
{
  "hints": [
    { "name": "claude-3-sonnet" }, // Prefer Sonnet-class models
    { "name": "claude" } // Fall back to any Claude model
  ],
  "costPriority": 0.3, // Cost is less important
  "speedPriority": 0.8, // Speed is very important
  "intelligencePriority": 0.5 // Moderate capability needs
}
```

The client processes these preferences to select an appropriate model from its available
options. For instance, if the client doesn't have access to Claude models but has Gemini,
it might map the sonnet hint to `gemini-1.5-pro` based on similar capabilities.

## Error Handling

Clients **SHOULD** return errors for common failure cases:

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -1,
    "message": "User rejected sampling request"
  }
}
```

## Security Considerations

1. Clients **SHOULD** implement user approval controls
2. Both parties **SHOULD** validate message content
3. Clients **SHOULD** respect model preference hints
4. Clients **SHOULD** implement rate limiting
5. Both parties **MUST** handle sensitive data appropriately



---
File: /docs/specification/2025-03-26/server/utilities/_index.md
---

---
title: Utilities
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

These optional features can be used to enhance server functionality.

{{< cards >}} {{< card link="completion" title="Completion" icon="at-symbol" >}}
{{< card link="logging" title="Logging" icon="terminal" >}}
{{< card link="pagination" title="Pagination" icon="collection" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/server/utilities/completion.md
---

---
title: Completion
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to offer
argument autocompletion suggestions for prompts and resource URIs. This enables rich,
IDE-like experiences where users receive contextual suggestions while entering argument
values.

## User Interaction Model

Completion in MCP is designed to support interactive user experiences similar to IDE code
completion.

For example, applications may show completion suggestions in a dropdown or popup menu as
users type, with the ability to filter and select from available options.

However, implementations are free to expose completion through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Capabilities

Servers that support completions **MUST** declare the `completions` capability:

```json
{
  "capabilities": {
    "completions": {}
  }
}
```

## Protocol Messages

### Requesting Completions

To get completion suggestions, clients send a `completion/complete` request specifying
what is being completed through a reference type:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/prompt",
      "name": "code_review"
    },
    "argument": {
      "name": "language",
      "value": "py"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "completion": {
      "values": ["python", "pytorch", "pyside"],
      "total": 10,
      "hasMore": true
    }
  }
}
```

### Reference Types

The protocol supports two types of completion references:

| Type           | Description                 | Example                                             |
| -------------- | --------------------------- | --------------------------------------------------- |
| `ref/prompt`   | References a prompt by name | `{"type": "ref/prompt", "name": "code_review"}`     |
| `ref/resource` | References a resource URI   | `{"type": "ref/resource", "uri": "file:///{path}"}` |

### Completion Results

Servers return an array of completion values ranked by relevance, with:

- Maximum 100 items per response
- Optional total number of available matches
- Boolean indicating if additional results exist

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client: User types argument
    Client->>Server: completion/complete
    Server-->>Client: Completion suggestions

    Note over Client: User continues typing
    Client->>Server: completion/complete
    Server-->>Client: Refined suggestions
```

## Data Types

### CompleteRequest

- `ref`: A `PromptReference` or `ResourceReference`
- `argument`: Object containing:
  - `name`: Argument name
  - `value`: Current value

### CompleteResult

- `completion`: Object containing:
  - `values`: Array of suggestions (max 100)
  - `total`: Optional total matches
  - `hasMore`: Additional results flag

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Method not found: `-32601` (Capability not supported)
- Invalid prompt name: `-32602` (Invalid params)
- Missing required arguments: `-32602` (Invalid params)
- Internal errors: `-32603` (Internal error)

## Implementation Considerations

1. Servers **SHOULD**:

   - Return suggestions sorted by relevance
   - Implement fuzzy matching where appropriate
   - Rate limit completion requests
   - Validate all inputs

2. Clients **SHOULD**:
   - Debounce rapid completion requests
   - Cache completion results where appropriate
   - Handle missing or partial results gracefully

## Security

Implementations **MUST**:

- Validate all completion inputs
- Implement appropriate rate limiting
- Control access to sensitive suggestions
- Prevent completion-based information disclosure



---
File: /docs/specification/2025-03-26/server/utilities/logging.md
---

---
title: Logging
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to send
structured log messages to clients. Clients can control logging verbosity by setting
minimum log levels, with servers sending notifications containing severity levels,
optional logger names, and arbitrary JSON-serializable data.

## User Interaction Model

Implementations are free to expose logging through any interface pattern that suits their
needs&mdash;the protocol itself does not mandate any specific user interaction model.

## Capabilities

Servers that emit log message notifications **MUST** declare the `logging` capability:

```json
{
  "capabilities": {
    "logging": {}
  }
}
```

## Log Levels

The protocol follows the standard syslog severity levels specified in
[RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1):

| Level     | Description                      | Example Use Case           |
| --------- | -------------------------------- | -------------------------- |
| debug     | Detailed debugging information   | Function entry/exit points |
| info      | General informational messages   | Operation progress updates |
| notice    | Normal but significant events    | Configuration changes      |
| warning   | Warning conditions               | Deprecated feature usage   |
| error     | Error conditions                 | Operation failures         |
| critical  | Critical conditions              | System component failures  |
| alert     | Action must be taken immediately | Data corruption detected   |
| emergency | System is unusable               | Complete system failure    |

## Protocol Messages

### Setting Log Level

To configure the minimum log level, clients **MAY** send a `logging/setLevel` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logging/setLevel",
  "params": {
    "level": "info"
  }
}
```

### Log Message Notifications

Servers send log messages using `notifications/message` notifications:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/message",
  "params": {
    "level": "error",
    "logger": "database",
    "data": {
      "error": "Connection failed",
      "details": {
        "host": "localhost",
        "port": 5432
      }
    }
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Configure Logging
    Client->>Server: logging/setLevel (info)
    Server-->>Client: Empty Result

    Note over Client,Server: Server Activity
    Server--)Client: notifications/message (info)
    Server--)Client: notifications/message (warning)
    Server--)Client: notifications/message (error)

    Note over Client,Server: Level Change
    Client->>Server: logging/setLevel (error)
    Server-->>Client: Empty Result
    Note over Server: Only sends error level<br/>and above
```

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Invalid log level: `-32602` (Invalid params)
- Configuration errors: `-32603` (Internal error)

## Implementation Considerations

1. Servers **SHOULD**:

   - Rate limit log messages
   - Include relevant context in data field
   - Use consistent logger names
   - Remove sensitive information

2. Clients **MAY**:
   - Present log messages in the UI
   - Implement log filtering/search
   - Display severity visually
   - Persist log messages

## Security

1. Log messages **MUST NOT** contain:

   - Credentials or secrets
   - Personal identifying information
   - Internal system details that could aid attacks

2. Implementations **SHOULD**:
   - Rate limit messages
   - Validate all data fields
   - Control log access
   - Monitor for sensitive content



---
File: /docs/specification/2025-03-26/server/utilities/pagination.md
---

---
title: Pagination
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) supports paginating list operations that may return
large result sets. Pagination allows servers to yield results in smaller chunks rather
than all at once.

Pagination is especially important when connecting to external services over the
internet, but also useful for local integrations to avoid performance issues with large
data sets.

## Pagination Model

Pagination in MCP uses an opaque cursor-based approach, instead of numbered pages.

- The **cursor** is an opaque string token, representing a position in the result set
- **Page size** is determined by the server, and **MAY NOT** be fixed

## Response Format

Pagination starts when the server sends a **response** that includes:

- The current page of results
- An optional `nextCursor` field if more results exist

```json
{
  "jsonrpc": "2.0",
  "id": "123",
  "result": {
    "resources": [...],
    "nextCursor": "eyJwYWdlIjogM30="
  }
}
```

## Request Format

After receiving a cursor, the client can _continue_ paginating by issuing a request
including that cursor:

```json
{
  "jsonrpc": "2.0",
  "method": "resources/list",
  "params": {
    "cursor": "eyJwYWdlIjogMn0="
  }
}
```

## Pagination Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: List Request (no cursor)
    loop Pagination Loop
      Server-->>Client: Page of results + nextCursor
      Client->>Server: List Request (with cursor)
    end
```

## Operations Supporting Pagination

The following MCP operations support pagination:

- `resources/list` - List available resources
- `resources/templates/list` - List resource templates
- `prompts/list` - List available prompts
- `tools/list` - List available tools

## Implementation Guidelines

1. Servers **SHOULD**:

   - Provide stable cursors
   - Handle invalid cursors gracefully

2. Clients **SHOULD**:

   - Treat a missing `nextCursor` as the end of results
   - Support both paginated and non-paginated flows

3. Clients **MUST** treat cursors as opaque tokens:
   - Don't make assumptions about cursor format
   - Don't attempt to parse or modify cursors
   - Don't persist cursors across sessions

## Error Handling

Invalid cursors **SHOULD** result in an error with code -32602 (Invalid params).



---
File: /docs/specification/2025-03-26/server/_index.md
---

---
title: Server Features
cascade:
  type: docs
weight: 30
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

Servers provide the fundamental building blocks for adding context to language models via
MCP. These primitives enable rich interactions between clients, servers, and language
models:

- **Prompts**: Pre-defined templates or instructions that guide language model
  interactions
- **Resources**: Structured data or content that provides additional context to the model
- **Tools**: Executable functions that allow models to perform actions or retrieve
  information

Each primitive can be summarized in the following control hierarchy:

| Primitive | Control                | Description                                        | Example                         |
| --------- | ---------------------- | -------------------------------------------------- | ------------------------------- |
| Prompts   | User-controlled        | Interactive templates invoked by user choice       | Slash commands, menu options    |
| Resources | Application-controlled | Contextual data attached and managed by the client | File contents, git history      |
| Tools     | Model-controlled       | Functions exposed to the LLM to take actions       | API POST requests, file writing |

Explore these key primitives in more detail below:

{{< cards >}} {{< card link="prompts" title="Prompts" icon="chat-alt-2" >}}
{{< card link="resources" title="Resources" icon="document" >}}
{{< card link="tools" title="Tools" icon="adjustments" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/server/prompts.md
---

---
title: Prompts
weight: 10
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose prompt
templates to clients. Prompts allow servers to provide structured messages and
instructions for interacting with language models. Clients can discover available
prompts, retrieve their contents, and provide arguments to customize them.

## User Interaction Model

Prompts are designed to be **user-controlled**, meaning they are exposed from servers to
clients with the intention of the user being able to explicitly select them for use.

Typically, prompts would be triggered through user-initiated commands in the user
interface, which allows users to naturally discover and invoke available prompts.

For example, as slash commands:

![Example of prompt exposed as slash command](slash-command.png)

However, implementors are free to expose prompts through any interface pattern that suits
their needs&mdash;the protocol itself does not mandate any specific user interaction
model.

## Capabilities

Servers that support prompts **MUST** declare the `prompts` capability during
[initialization]({{< ref "../basic/lifecycle#initialization" >}}):

/draft`json { "capabilities": { "prompts": { "listChanged": true } } }

````

`listChanged` indicates whether the server will emit notifications when the list of
available prompts changes.

## Protocol Messages

### Listing Prompts

To retrieve available prompts, clients send a `prompts/list` request. This operation
supports [pagination]({{< ref "utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "prompts/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
````

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "prompts": [
      {
        "name": "code_review",
        "description": "Asks the LLM to analyze code quality and suggest improvements",
        "arguments": [
          {
            "name": "code",
            "description": "The code to review",
            "required": true
          }
        ]
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Getting a Prompt

To retrieve a specific prompt, clients send a `prompts/get` request. Arguments may be
auto-completed through [the completion API]({{< ref "utilities/completion" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "code": "def hello():\n    print('world')"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "description": "Code review prompt",
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Please review this Python code:\ndef hello():\n    print('world')"
        }
      }
    ]
  }
}
```

### List Changed Notification

When the list of available prompts changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/prompts/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: prompts/list
    Server-->>Client: List of prompts

    Note over Client,Server: Usage
    Client->>Server: prompts/get
    Server-->>Client: Prompt content

    opt listChanged
      Note over Client,Server: Changes
      Server--)Client: prompts/list_changed
      Client->>Server: prompts/list
      Server-->>Client: Updated prompts
    end
```

## Data Types

### Prompt

A prompt definition includes:

- `name`: Unique identifier for the prompt
- `description`: Optional human-readable description
- `arguments`: Optional list of arguments for customization

### PromptMessage

Messages in a prompt can contain:

- `role`: Either "user" or "assistant" to indicate the speaker
- `content`: One of the following content types:

#### Text Content

Text content represents plain text messages:

```json
{
  "type": "text",
  "text": "The text content of the message"
}
```

This is the most common content type used for natural language interactions.

#### Image Content

Image content allows including visual information in messages:

```json
{
  "type": "image",
  "data": "base64-encoded-image-data",
  "mimeType": "image/png"
}
```

The image data **MUST** be base64-encoded and include a valid MIME type. This enables
multi-modal interactions where visual context is important.

#### Audio Content

Audio content allows including audio information in messages:

```json
{
  "type": "audio",
  "data": "base64-encoded-audio-data",
  "mimeType": "audio/wav"
}
```

The audio data MUST be base64-encoded and include a valid MIME type. This enables
multi-modal interactions where audio context is important.

#### Embedded Resources

Embedded resources allow referencing server-side resources directly in messages:

```json
{
  "type": "resource",
  "resource": {
    "uri": "resource://example",
    "mimeType": "text/plain",
    "text": "Resource content"
  }
}
```

Resources can contain either text or binary (blob) data and **MUST** include:

- A valid resource URI
- The appropriate MIME type
- Either text content or base64-encoded blob data

Embedded resources enable prompts to seamlessly incorporate server-managed content like
documentation, code samples, or other reference materials directly into the conversation
flow.

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Invalid prompt name: `-32602` (Invalid params)
- Missing required arguments: `-32602` (Invalid params)
- Internal errors: `-32603` (Internal error)

## Implementation Considerations

1. Servers **SHOULD** validate prompt arguments before processing
2. Clients **SHOULD** handle pagination for large prompt lists
3. Both parties **SHOULD** respect capability negotiation

## Security

Implementations **MUST** carefully validate all prompt inputs and outputs to prevent
injection attacks or unauthorized access to resources.



---
File: /docs/specification/2025-03-26/server/resource-picker.png
---

�PNG

   
IHDR   �   �   �Ķ  `iCCPICC Profile  (�u�;HA��h$D��H!Q�*���rF,� XQ��K��d�w������6bci��B҉��"��B4���z�������0��3� �%�g�	ium]�!
?n���.P	�����z7&fͤcR�rp68$o��?����x�����~P�t�m���;6|H��`����-�5k�2I�{�^�r��đl�o�q��ֿv���E�0�0R�ä��
�P ӟ"�?}J�/�2�����	�¤��Q��qD�eLR*�޿��zG������%P��׮7z\7L���u=u���[�@ϛ㼎 �K�����q�@�#P�|.La�vY'   beXIfMM *           �i       &     ��       P�       ��       �    ASCII   Screenshot9UD  =iTXtXML:com.adobe.xmp     <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:exif="http://ns.adobe.com/exif/1.0/"
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
         <exif:PixelYDimension>181</exif:PixelYDimension>
         <exif:UserComment>Screenshot</exif:UserComment>
         <exif:PixelXDimension>174</exif:PixelXDimension>
         <tiff:Orientation>1</tiff:Orientation>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
oP�=  3HIDATx�}�ՑnMM�fA(�0BFH"�dl����omd���9�. �k�g>{�k�
�Ȁ�������m�EAH��r�H3�h�h�����ܾ}c���#���Vש:u�ԩS]}�oߢ��S�Q�r�X�e��1��ޑ�ED�,�_�RQ� ���W�Hzd�L,P,N+�?2����x"���i%�f
��P�^]]M���
�������B�w�*%+��f�L�� w��i:]}�Uq�oXO�>�;���[iz�4���w��C@��;��.�[�>k�����O���h��IT\TL}�i�կ~� ����������6嗿�5=��v9眳隫��;v��I��7��-����6۠cA���
Z�N���k���E���
�暫h������~''��UW�O�s�R�-i�%���!���XW\~-�Ń��~��w�����|9mݶ=��1c�ҋ/�H+V����ڽ�=��ȑ#�c[L_������>!���]K睷� w̘1��֛�/~��=��@!�n��Ϊ�*8�)=D��pЛn��+�N#z�
"<�z.�.��Wn�5k�ҵ<�C��uz0n�XZ��
zs��J��G��]D]]�B�|,�����r
}��R�?����N+J�+.���K�������4o�\ڶm��� ;w���=W��w�Fw��}���o�)�N��o�I<���%�L�:E���H;/�����������/|������8p��m JF�l�9.�ٹnΚ(^SSM�����d�-r�WG������b֑�D�_��ujDeԟw޹�U��A�m`���ӧ�/���x�v[���aÆ���_K����y��s�Cs�̦q��q���z0�����.����|{��}������	/�8Ϗ|/=������>��O�m�1�A��4o�<q�W^y��{�o4��VUEXTp�9s���ɓ%y���i5/�k�����hϞ�4f�h�����{~(i����yA\�����`>n��K��3�R'�;ХX�)��c��xH"ڦ+�~|pz8
"3rT�!��O��)?����Z���A�~�C���|�
G���4����O[�DWg-�?�>��%t���"Q�bagjg��G�*��K_���8���}ｒ�x�
ڷo��!Ү]�V�#��������}��~{mٲ�^}M�6U�Q�Z�����#nٺ��0�y�fB�EyGd8<���_�	N�h-|̜ٔ���&�eBH���M%W`ĆJ��d#
�~��BM/� t�u�c��h���N�o_��:�`���Q>]#����K�����-{���ɷ���/���.ਸ��.�����f��ߡ/�k4��s��.��|����>"�|��I�"���ΦM�h�"�*��JKJ��HwO�fc�ĉt�I'�%l��Ŵu�6�%�}���qMP��9Xja师�,�7ǵ��T�������:/�׭[*��Q4Sm��p|��9��D?ɑc��䰛�wtt�i��~���i,粋���� ���bp¦3�Z��#䊽���^|�%z�����q�x�ɿP
絼-�Q��?��ښZz�h�����>v���ڵ�Q�v^uZЂwWsXd��s� �%��%+��~FBJ�
N�M�#k�v���3�ſ��/��n��tE�)w��E��+n\��?��*++]�]�v'��r�g�R���ߖS	_��WH�0~�I�446����� 4�i��/��ظ�˦�A]�a9-����l ��,�=F��g�u
^8N�p�d�#"2����ԡ�tੜ�6]��.*���I�N�Yg��N*Ҁ3N�h��;��u�2�Tj�s\�O�۽8mF�ZerRGOw7����d�@�fϞ�g�9�=§��謳Β(б�>�,�ӓO
;��Q���b�t�x�'j�����q:����i��y�mh�oWK���2�~�@�7UQ�i�wW�DZ�����]����	mW�pP@���-�ַ�{�q�%�б"Z������<���s�%�!���U�ptе�қ�7��Q�r
>w��W�����|��v~9..~&L�@��=���k���/�V��|>u�:�����g-_P������r�f�F�pn����0o�!ո��2i�Dzoo���H
�td7����>��X�҅.�?>�ȯ���?B�G�f�C6l���z/�u�8y����@�nlh���p.��R:�ǈvm�?Ҙ��r��wH�{�<�S��g��}�f�~8+\v��4m�T�����ڪ�����PGGx�EMM�tl'MM�%���apX��ξ!�Ӣw����|	�t�S��#���M�L��c����U��m���(�U:���QT"[]�<I��>���$nAba�p ik��,�ZQQɻ�O��#G����N����o]m$]`�����F�*�� Y�}V���q�����W�FL�?��}6��%�P�L���#Y��luN���o#�)��r�`���?~��Q>R�ĵ@B����r\l�`��?
�'����=9���FV�\�;k�@�Mf�4r����W��� N���틻s�.�`Z 7�8��33�gqq0*���r�Qn.������w0g,�[,P�h+NčǙǢ��?�x�8��i�A�i�49.TK�};�A��r\�YWo�9����츩s[?zo�Q�h��/�O8�E.��<��O'��DZ���c��?ŏ��ѷ�Dh�W#k6�0?N��+g�T�@2�����q�r�d��&�=F���hKK�\���D(d��������8��}��^?��*++�������b�]�@D^��o^��&m���NpG�σܧ�D��$��ǋ�䆅�_�(����T�[S�~���e�xy���<�$yBY��y\�7��f!9D�p�
�e���Z�;W���>ŮC��V0�
��D���Y���]�����N��B CP�a됻l����d#e";��S(9��>�a��d����`d��� i�'t��i�TtD\�����&�D8��g����Oz;X���,�N�Qm7!#�����qZs!fG\G�����ZtE��F0SX��܄C"���A��-���;��,_��k~̫�4
��Q�-Ǖ�Df$��]L�E���� �Ԩ7%�7�Q��⢠S�uʥx&<ٴ�����������LxT����]n�W̥zf�sjct��X�$�������ǤaA�X�x|�Kn
6�9r�d/7�>.{B'�r�?��t	�֐|�
0��.�C Hqګ��99'-^�^e6ӂ�xTF&<f����r���MR�,Ƥ2��7�>��x���&�ѹ89>DyŅb>�
9�IWk�?����JJ�0�G�L:�f�/ Q	b�R���M�Dlؠ0���R�&�h����
���ܛ���?�h��+'������[�����渐e���KPbA�JCnB����$��J�x,��a�09.7:���L@�����E����������<!+T�!'�����ar\g|�8�@6x�sS��9�~�|o��GWKh�T�ɵ�!#׾O�vy�qu�`�xW�H�.�B��,Y,:�0d�Ԩ� 0}<2��/�H�%���+2�4a���������,z��JMCF�Nh����L��q3���"���3Xx�	=����ͳ
���Gs7Vр�������!˲3-?E��(=���uţ�d�o�9���B� �8~�e�
��Hן΍/�ƺڼLJG}:�dt��������D�\��g�Q�-�o���g�,Nׯ�{n�B8�Q$O::�O�8_�}W�N���Ul���&��Qv��g��__B�^r)-�����/�I�C�2��3�I�GT���'��B�y��;�ivXr���[L���gM�E?˖-������aGC��?��A:�p��Œ�z��ҥK%£%.�uN^}��E���}\���8t1���|�!���y�v�9s���e���l�Q7����
�����]��2����z�QC��>��
��������{6\�i"L9����t4�����#��촜�"� �"ǽ�����9?)$C�Cy��5�����y5���i莣�QOZp����EZ8�uѝ8-緈���D�0�}X�A�	���;�b $H���z��<�}9�;���NΘ����W�5g�ۑv�㴈�ϝiﻟ�s�k�t��'����Y��>S\��q�mm>�}9�V{['G�4߀0}�-�f�1�r ��JN�M8��ϑv�w�ҪU��8#��s�tcJ��(�����{qm��K����Ǚ����j�#�#.Jl�6(.aP�50 ���V� �E���i���-���q����^c����:"��@�}\]&�dM��Vh�����\N0QW�Z��n�]�:i���KgȱKظ-�=����z��m�s`��6v�W���_���Xe��Oև���J&C�Q�9n�X�� �w� !;>�rziy���������@�ȑ�������P�&G<Ž�K�+����S����:��s�﷿�mN~�]������6a����+^N	��AE�k/�+����EMM�8F!L���aMu5�w�Y�& ҢHf<�=�%�z\B��*�n`r56���)Kw<ru\َ)��>r�f����À5�U�;.ƅ"�.CI�&��"��q�YC����F���1TQ5���o�:���<.��.�|a�an8쓯�æTN-�L�{a0��V���ε�p�$�8�HQ����A�ʲ�Ök��~���o���Ǖ�گ��`S�T|X�0��d�ʬ+&>�*�B�[u4��gz��ϱ��z�y��Q���&N_[�}̼��kZɳ�cP(�X�L�5���s��<��� 
��u��W�C���ぐk���8��NNd
B_w�8+� q��z+���$�"*A,`�,���<�͌.���'Ӭ@��N���@�8����]��j:]D��<�+�mV�(��6�(�x���f*W�i_^\�>��Q�d}{r\g@�Z�s�4Pq/L�K���U�A�W"��ޚ0q�65��O�]ω3B|�b1��H)1'1r
�P�x��*��Im��%�X�����jx�i�*��mk��sf�*U%w��AP�����Ag-�$�鎡��;V>?�J�� �Wl~�m\����ܯ���۸걗8J&<�3������Ǔ�7��
c�a��.͘	ax6�R�����K��<������*�p�>���8���yp��t2��3�#S�X&��v2i�� �
C�ĲL��1�x)�x&|���K���,��
ۙV�q���v�n.��v C!X ��qӍ*vN��l��VQm�Y@��E|5��� ��z�����G��~��������Ǖ�V�+ɽ�h���K{���;U%b��#�7����j�j��j�WTp��G�R?.���Im�������3^nW��n,��а�g�D\�}C9#qx
��m�
�13���@#F�Soo��wRwO���rc"<�[^VFUê��!���Ct����Xf�ŗe ��Сk�Пǭ�����r;v4�tj�8�:+�5i��%�Ŵg�>v|���@��9�ϒ5[N+�+h��qt�����a7¦3���i���,#�~#~�z��K���|�ϡ�� ���q��8l�KW\����c8�vw�1ۂ6h;v�(G#[��Pk���<����=L��S�Ú���Y�u�A�@�]�8����ќ�V��yG����Wr^!���m�hcX�={��<.b��=�5���-��ؾ}|���B�ZZZ�݆�B��myVA#n���g>s��"n�
��j���+��5�^�ڵ{/�x��8��sΤ�ƍ�G{"�s؉��V�m���o�Yq�d��bv�L�*������7�C�5"r��
���pڹg��:/�u+^]�ӂd7bѢ��m7��G��Y@����S��~p7�ͣΟw^(z��QC��e���2������V(����(��6�2�Y�uZ���[��o�������,, ������gS1��=?�ۑ`��g�?z�9n���,�#�j�Vԍ�i��o ��%x��'�D����___o3�ӿ�|3N�t�=�g3p�X�/��"���@��s\^���d1��H������8�y�9n
��-7�_ޣ΋��n~�Lw#��y.�ZQ��h�����[�������Mu�9�y=l��5bD��`8.�G�8/G^L(�����T�n���%����,� 8h�+��G�9���t'�Mk;���r^<�0e��us� �֯x#�'<x��o~M���Bw#.�Չ�� ����g"�F���k��:߈�-/��N�Ǡ%+g�uN2RT���T�n���8罛�#/����?6�3x��J��q�0�jV�F^ŽЗ�M5�*lE���ڎ��Q
��w�V��Ϋ�
k���/����<X�D�[0ɒ6�G^3ϩ�ߨ��^?I�^���q��B\N��+�
�g��#�j9x���y?7`��b��
T[[PR�<h�����Y���u�Mk����9P��	����q|��}g�6zyyi�����sR!]@X�R:;;�nWYi)����n
%�O8-��x�m_μQę�H����apR������wŊ���Ͽi��9��|A�Fq\,���ERWW������Ћ���
�TR\����i'L<���۩�~8K�JPd��G�w��?�O/����3�Rͷw�s�%�"���b`��y#9�9�Ñ2t�����i���W�Ϛ5K�v����3��q\3����G�+^��Ἑο���?��Ï��Tq�p<�x��a�ӏ9B����(�f�x����#�D�V��G�����"/;�D\xn��_���2ǎN�u¹8�|�F}����������DN�iV�\�>-���{]�ʧ��p�=�3je9��O�Q����>�Y���q��q�1���8���7�G���n�y�]wG͈A�Ü�q�W�˼o�m����C~��w�SϿ8�o;�Jw�qU9KYq<OEW��PՊ��Z@�;��O��g�g��?�#�\���O{�Ι�n���(Wz��OJ7�F�C�p�Rޢ�ve/oSb{��{#2pD\\�`g���W�C�q;4�21��L�-�G�JkuFu�
~!�j;�� �-������'�7��6YN��
M����v�ce��4+(^hKHE���ǀZ N����f�h�?D^L�w��t����<�`�d���$#3�iiV�i[������� �N
�Q=�s\�=ֈ��;8(�F\㜈���P#��^�HW�ԕ�����.�gu:�G�:��=V�l�;S�<���mV� W�k�8`�r�S-������q�Gܓ�"��+IO9��j�Md;ߙ�;����QqR�r��ڊ�"-w\�EC��6�x��r\�l��IqI�%(>dg,R\,t���yTFw��� <��!m�8��\�?��8������T�69ᬤ�ur['��H�,��7�����x�q���?I��s\�,.r5���k0:�Ee�Z �?������縺��F\'v����z���=��;o'����7��&��g���}s\^'�Z�yaJ�Qu栴�<�e���-�g;ߙ�{r\d��Eq/T.o=:EQ��9����$��:2MQ�jF3ah̛��1��;�*8ΠNaC5�c�+�GG�҃B�B�v�p��m���}b����
����cSu�@ץ* ru:o���;g~L�S����Z7���q��C��?� �
�Ÿ���8� ����ן��>�z��MCB_qԐ�+��$��4�5��x����Q��H<��K�T&i���:�B
��;CV3����F���������Z���w>\�<==ր;u�x�\������;�QGW�w�Zںiˮ6���~�jHv�k��f��w�^��7-x�Qgwu���|<��/��<��Gڐ���N�����H�st�S�O�q��x4�����ϡ1�ɐ.��Th����Ap凾�����VӺ��,�e~�E��-9�ڏ��?{��_���'�V&�W.�(8>^Y�L?|x
:�C#�W��[ϣ)'�S[g}�g�ѳ��ފ����x}𲩴|����^��t���|���#W6��t�����^�0��e!�zR��v�n��
ں�|�����_�D�f�+�1��/_�6Hޒ��{�
�w"���&ƚO�
q3��vfW�
&	]ze
���ы��x�{���}p����.�?�>{��3}$;q�^����ⴥ%��`�C����k�y�aw4~i;ճ��[���?�#z����g�E�`��d��?�@^{�Y��H����������>���+�k1E��`'=��&^�E���,N;w�h�����Vӽ�YK+�5}0짱�5�d1��$:��W�^������-�+WQ�O�Ŋ�`��}�)|ͦ�8����h2�=sUU�ѿ�������\�����5��0Gֲ2^Q�j�\0�>�x=��V���_�g^�E���l��Kۤ���
ǟ�Qs��fzb�6��qB��?x��T_SF�-��8�'�W��l��߶q�~��zu�������zs�A��o�<��ӗôz��=�qP쇈�y	2�0c���r��p�k(�JW�e�G�։�����DUfvS�dߠ~/�:�z�˞��f�w�_I;�!D0��������4v>D����NK���]�̜2\�o�d^ȇ�v��.7�}������Ά��4�F����`�O���u�4}B�țz�y�*ro��?�[IX�U��|�i�1亃e?�C�����U�;^j�偮B��K8+Ѷ��zM�s�6���_&9�m���'6�)y������b��Z�a?]:b<=��nj=�-N=�x�o_H5��W�9���������|ч2�|��&
�oAt������N|�D�︄&���/��胋�����3��_���0�[��L���\pcit��� ��F>1������g>�r�3g�t�,�r��賛�?y�~��z�Ļ�=��ފn6��l ����ΟD�<�����iG����/��ǯ>�f8�"��L&�8�]{�����y�w$~a�^��=�(����b/U"6?�Q��!�źP�7+.W��ر�"
'��p0 �Wo:��}�kre��{�sg��]�@�:�{�//����)�����W3��"3��4Sw�>��������/+v����M���4ze�q:��h)�M.�����m���8��B�F���?�d����`��������l?�i��
���F��+n�.?uz�P��Zɹ�_��a:c���T����G:�ҁC�PWE�U��K�N�����}4zD�DHIJ-z*�~����Ө�՜&�B���r��F���Y9��\��
\�����>�A�$��J��}�;[����CMm�c�qD��ي�b�-�ǫ*�y'�F���{��F��Mt�F?��eLC��0���%����J���H��~�Y&�������r\6]v�]�Z��XIJ��$0爣w�VsQ1�cs ��=�V��X���r\�$r(��[i�t6Xc�B���W�
��WKX��8���'��lL��
��'�����y��
����x"'Kx��PMRH���M��=��GO5#I�o .���/l{��
1y	9�BY�ŵ]}K���±q0��Q
�>q'Jg����qC�P�0�؈��2�~��Z�ܨ��F6�x�⹩����Y�p����j�^�ZŜ�lhn+y/�'(����,q�1�۟�n,Y��p�|��iO:���מ���B��H?��".`�S��C�+	�,��+��>�d��H�k
9fxB��O�7�>.k):�ޟ��f*.(��Y-���;��C��{���VB"Nb�u��!]��`�Å.,
�j�Gp(ف�
3h�Q�3<�q���Y*��a�I��-s��q�3��a���U����C�EW�}�����/v����N`QrP�����820������l{
�}x�d�B��e|@�yr\�spF�r��toč�<��
��ja�/�Зnx`Dw&�cr����E�U6�����r\�4g� �E��Ņb>�Nq�ˊ�c�"��R�q��u���3��\�_���>���N�9�nąs�%Mua��rL���"݇7�a�m��*B���$벢�
Y
�4�W�v��A�<�2O��eb»��9�ܐ[�{P��dW�� U���M�I�/��>T�gf$6>�]��O�ޓ�c����s�p��s�h�n������6�Ѿ�����y5R�d������P�o�)��r*-����R���1^q2�'���[h~`�f�Q�9.\�%��0��2ǡ��ء 1�^v��#���F��TRZB��m`*�W*�,Ǩ�������N\F�U5�W��[�Ca���g�~����s�|�45���BÏ�纺:�P�~~c���Ruu
���qDMW����]���!�_:��J=�T];�e��S����ޙ�XN�
��q��].�9[����θ��h���p��QL���A������i[쥺�j1�����V��&��r����n��ʨ�� �۳�F�Oe⼅1�ب��yC�
0��#Y���9��0	f�Ŏ���8�Mc�Zh8Vfoo'�4�����ШQch��1���C�[[WǲFӰ�rڷ{;Ga�F�B��>p:Pr��T�݈�����D�\q�(;Ī���2���&�PH�Qv��{wSͰa4r�(����yn<�4���F��]�wQgG�
�n�I�'4?H�_\�+�l�E�3����JI�,��ݬh��&����*x�A���C�|�-�ӻ;��loo/߲�WH��x**L�
zG{;�3�u.'���DcC#m߹�y�=c�?�9��'�3O�̹�	����bH�H�+��Υ���ZK�����>�KK=5���8PQ�} ��|A�s�Vj^G���dЎz�����c;^�+xf��1��/���~�6l�@---TSSM3f�Fg�9�,N�	���j�d���n��a^�WE�=� �0��1~�u���3��=��<B7�� ��+��kĕ��s��eRz��}r����D�E�A�5�
�KG�����B������[i�[o����fjhl������A�g͢�~��ny�N7�֬y�֯[O�9�=��mQ�K��s���N���g�lg~Ǘ����n��s�8�p�M�������iB�<(���Ӥ���)x]o�_�v
͚}6�>9��\�:�9w�\�� �<�_����k��͸YS-���]@3gΤu��ѓO>Is�Υ3�<�w�����6mz��O�Ns�=��vp�-� �p�۾c�7��Ga�P�,ؘ����x����:��?�帆�p_�x1<#:4���8 W|�����W��G�����pG9�C:S0�t��8���\�J<�����)S��)���3~ؤ�&N� ��Iݽ{7Mc�mim��W�����=����"����!�~����+uȃ0~���?��r� a�b��0)o���W��(�8f8|�����?���kjiܸSX��^�S�[�|��ù0Q�Z��xX��͟T�W]w�u�6�{؉�*���kr�b޼y>��}���[��߉s�!�-q� �w���s�8mܸA�2��a��A����>.[�W�>��_��z�٧8:��L��[��x0;��� NGN��?����.�6o�$<��>�����G۷mK����n�{9o�����gϮ��sOѲ�~�h|����quq�E�p�	���6N�i6�,�&r�w~�[��_vŕ|:E5�u���bWEUu !�uh㼴���/�pєX�#;�&�c���҆�%ڎ;��S襉�&�ԩSyPbIW�Ѿ>v�4~©�9�a�(�@C<H��#m������$��P(�|gҾh��
��q��
/�ޱ�Ƈ>��2�o@�8ܯ��755�E]D��~:���$<M5�[?��L�y�`�xNg|JGם;wҪ�+Y�Yt꩓��z+v֮������qq1����ሎ�oQ1~��X�|��*ly�ݻ��|�Mz���4��A���EM��%!
�
��Ώ���R^�`�L�r*}��_�S}հ���CD��ZRR*�^HZ[[y[m
}�/�����D���be���ꮝ�h��-t�y?�:���v�9��	�Y��xZl׮�����ü�r��5����a:���:����~z/縷H�ll)[_�a>�]]������uo��իN(��t��dԨ��Ż��>^�?��=K�y����`|'l떭t������JX�]���D��
�={v��U��'��_ ��v��OJo�ڪ)���&�|���<�
�����l�L�|�#����K��{qA���f��"8p���ٴ�}����#���_�L'�D���U`��*�������Sg쉨d�������Orag��/�'�e;��뼯�W.���o�m۶�3|������Ԟ8ǩ�\K3>wW!,�)�G�I�ÿs���JH�1���!���'�r���������s�=������
���;sHR�D+���c:��&�ʠ�u��������b���Ώ�EŘԜ�2��y�+S����Up���*�9�ǽ�rN̣�ncz�A\�Z�����>.ŝ��
�[�f�bs�f.���#'{����0�Gd'�����AbDq�t�=��qq� �  A���h6�0��:�u�8e�����$�Fv`��ną�aH��8\곣��'l

�����E\�Fxd��y������A3h0    IEND�B`�


---
File: /docs/specification/2025-03-26/server/resources.md
---

---
title: Resources
type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose
resources to clients. Resources allow servers to share data that provides context to
language models, such as files, database schemas, or application-specific information.
Each resource is uniquely identified by a
[URI](https://datatracker.ietf.org/doc/html/rfc3986).

## User Interaction Model

Resources in MCP are designed to be **application-driven**, with host applications
determining how to incorporate context based on their needs.

For example, applications could:

- Expose resources through UI elements for explicit selection, in a tree or list view
- Allow the user to search through and filter available resources
- Implement automatic context inclusion, based on heuristics or the AI model's selection

![Example of resource context picker](resource-picker.png)

However, implementations are free to expose resources through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

## Capabilities

Servers that support resources **MUST** declare the `resources` capability:

```json
{
  "capabilities": {
    "resources": {
      "subscribe": true,
      "listChanged": true
    }
  }
}
```

The capability supports two optional features:

- `subscribe`: whether the client can subscribe to be notified of changes to individual
  resources.
- `listChanged`: whether the server will emit notifications when the list of available
  resources changes.

Both `subscribe` and `listChanged` are optional&mdash;servers can support neither,
either, or both:

```json
{
  "capabilities": {
    "resources": {} // Neither feature supported
  }
}
```

```json
{
  "capabilities": {
    "resources": {
      "subscribe": true // Only subscriptions supported
    }
  }
}
```

```json
{
  "capabilities": {
    "resources": {
      "listChanged": true // Only list change notifications supported
    }
  }
}
```

## Protocol Messages

### Listing Resources

To discover available resources, clients send a `resources/list` request. This operation
supports [pagination]({{< ref "utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resources": [
      {
        "uri": "file:///project/src/main.rs",
        "name": "main.rs",
        "description": "Primary application entry point",
        "mimeType": "text/x-rust"
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Reading Resources

To retrieve resource contents, clients send a `resources/read` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "contents": [
      {
        "uri": "file:///project/src/main.rs",
        "mimeType": "text/x-rust",
        "text": "fn main() {\n    println!(\"Hello world!\");\n}"
      }
    ]
  }
}
```

### Resource Templates

Resource templates allow servers to expose parameterized resources using
[URI templates](https://datatracker.ietf.org/doc/html/rfc6570). Arguments may be
auto-completed through [the completion API]({{< ref "utilities/completion" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list"
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "resourceTemplates": [
      {
        "uriTemplate": "file:///{path}",
        "name": "Project Files",
        "description": "Access files in the project directory",
        "mimeType": "application/octet-stream"
      }
    ]
  }
}
```

### List Changed Notification

When the list of available resources changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/list_changed"
}
```

### Subscriptions

The protocol supports optional subscriptions to resource changes. Clients can subscribe
to specific resources and receive notifications when they change:

**Subscribe Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "resources/subscribe",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

**Update Notification:**

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Resource Discovery
    Client->>Server: resources/list
    Server-->>Client: List of resources

    Note over Client,Server: Resource Access
    Client->>Server: resources/read
    Server-->>Client: Resource contents

    Note over Client,Server: Subscriptions
    Client->>Server: resources/subscribe
    Server-->>Client: Subscription confirmed

    Note over Client,Server: Updates
    Server--)Client: notifications/resources/updated
    Client->>Server: resources/read
    Server-->>Client: Updated contents
```

## Data Types

### Resource

A resource definition includes:

- `uri`: Unique identifier for the resource
- `name`: Human-readable name
- `description`: Optional description
- `mimeType`: Optional MIME type
- `size`: Optional size in bytes

### Resource Contents

Resources can contain either text or binary data:

#### Text Content

```json
{
  "uri": "file:///example.txt",
  "mimeType": "text/plain",
  "text": "Resource content"
}
```

#### Binary Content

```json
{
  "uri": "file:///example.png",
  "mimeType": "image/png",
  "blob": "base64-encoded-data"
}
```

## Common URI Schemes

The protocol defines several standard URI schemes. This list not
exhaustive&mdash;implementations are always free to use additional, custom URI schemes.

### https://

Used to represent a resource available on the web.

Servers **SHOULD** use this scheme only when the client is able to fetch and load the
resource directly from the web on its own—that is, it doesn’t need to read the resource
via the MCP server.

For other use cases, servers **SHOULD** prefer to use another URI scheme, or define a
custom one, even if the server will itself be downloading resource contents over the
internet.

### file://

Used to identify resources that behave like a filesystem. However, the resources do not
need to map to an actual physical filesystem.

MCP servers **MAY** identify file:// resources with an
[XDG MIME type](https://specifications.freedesktop.org/shared-mime-info-spec/0.14/ar01s02.html#id-1.3.14),
like `inode/directory`, to represent non-regular files (such as directories) that don’t
otherwise have a standard MIME type.

### git://

Git version control integration.

## Error Handling

Servers **SHOULD** return standard JSON-RPC errors for common failure cases:

- Resource not found: `-32002`
- Internal errors: `-32603`

Example error:

```json
{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32002,
    "message": "Resource not found",
    "data": {
      "uri": "file:///nonexistent.txt"
    }
  }
}
```

## Security Considerations

1. Servers **MUST** validate all resource URIs
2. Access controls **SHOULD** be implemented for sensitive resources
3. Binary data **MUST** be properly encoded
4. Resource permissions **SHOULD** be checked before operations



---
File: /docs/specification/2025-03-26/server/slash-command.png
---

�PNG

   
IHDR  %   j   �Gz  ^iCCPICC Profile  (�u�;HA���h0�"����b$�6"�"XQ��es^�K\7'b���66������+E�O��
��EM������33��u�-�B��٤�������!��Og%�дy*�����#<R�G����i��W^��;#���-/�3J��r�qa�X۵��∠���%�u����s٭Y̤���,��+��l�o6q��a_;��Fqi����i�($��8T��O�>��Ka{؄�<lw��h��9�0�(q㔪���;6��;`f�`��%9p�t�4��# t
܎q]�?��T}��x��A��9�k/�j�q�O�vx����'�9aj�J�   DeXIfMM *           �i       &     �      %�       j    oI��  iTXtXML:com.adobe.xmp     <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
            xmlns:exif="http://ns.adobe.com/exif/1.0/">
         <tiff:Orientation>1</tiff:Orientation>
         <exif:PixelXDimension>293</exif:PixelXDimension>
         <exif:PixelYDimension>106</exif:PixelYDimension>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
l0�5  lIDATx�]	xUE�>Y YH����HXH�DDdw�Glhm�lu�F���vz>��v�[g[wT�%HXd�%a'+	[ !�Ad�_�.���Gܼ֗w���Wu�֭[�׽�=uN�[^W�^�N"��  Xo��C�!��B@HI.A@�BJ����  )�5 �B@H�R�!�!%�A�R)Y�;�2��  �$׀  X
!%Ku�TF���K! �d�������\�� `)��,�RA@���+��]��������^i� �PM�����[pS��ܴc�Y�@CE@H�����[pS��ܴc�Y�@CE@H�����[pS��ܴc�Y�@CE�头n�zJKK�1>�Ν�����#���p))���ӛo�C.�����YN��C�,���r���(.n��\p�Gv���p))�Z��Z�jE�^#$��5%/oo
n��i9�h��7����N��A@�>���bAA>�ر��1���n�}EE���l�¢+4tH�nm;�zܸ�4f�h���qZ��$��9Gv
��҆������Ə���G�PjJ7������5k��ˋ�B[)R�p�ĉ�c;v�@���F�իW())Emo���
��3(((��ޑ���m����p)�]������÷PJ��濼���m���Kt�:���G��Ggy���wc�y��*�K'�g��y�E���%��f����ѐ!�m�dC���KH)99�RSSi��+���VҼy��iS'Sn�eE>�>��&M�H�o؍���>�@�ɞ���_-WV���F���[o�KO>��h�
3��#�RZ�z�f�9|X9�O�F���)���ǗBBB�^t/���q�3H��w�k׮���_�FF�3gΪ]�Ut���������u-))���[i�ȑ��[���3� Oz�M{Qrr�:S�V-�qF9D�	��Q���m�F��y�8a�Ò��Z�f����iP�@5�i߾x�۷/a8&"��@�kJk؋֣{
w�l�vm��;�)���G����f>� -^�z�S(��� �VԪ����I�g�~�)H0t���H�/��]��N�Uu��O��kU� �A��URZ�j
������w;�����W��O��<5Iٞ:w�)S&Q�.]Ա��}�|��C����n�ԴT���ݻ���WϞl@oD˿����T6g	�3�O3�Ķ�  X�Z#����X�09|�PjҤ��V7o��G����5f$��iӦʹk��l�ER�y�t�G
yz�*# �����dC�6mJ�-xEM�<s���~�
σ��@���n&��2���9m|^�ez��͙�=��t�|q[�ҢE�WSv��i8EFFһ�i���
L'�S
*�+�A��Ԛ!f��uԖ��QQ�N[��_@׮]�ݻ��'O�|а2xz �f���`ʟ  x&��)�������9�M�6t��hժ����O�mM�е�kj�^9y�g+
�3�BZ-@�+;;��_��t����F}x�eHp0EDt�ƍ�\�+��AC�!Pk�RU���ۢ�k�����Ϝמ�����"�� `ꅔ��L>7�G��>rVA@p��ۓ��)N�������R�P:8�#�$M\����������4ɘC��|9O��o�/��}���F�'8C�4�2��


)??_y
�����'q:I�A��p[R���Ԅ�yR�/_��M�+)u��I*��[��&$���5�!5k֌?.�|��'�A�5�z��k�Y'�j2���lHxaW�N����F��HIkI@q=t��Ըq�j%
�@� ���7@��I�ڎڗ.]T3�KJJ�q9�  ��$%3!iRr�^^vv6]�X�%�o����*#�v�7��&#����>
!i$$���[��#�)Y��&�� �p+Rҍҡ&)�t	A���%)		Y����	!���dn4���@�A�mIɬ-���5�ya�%Z��Z������{����	��SU*������Z����o��ʡ5Λ�{��|���������'q�ܖ�ꪯN�<��>������y���PRR/
q���]'��8EV�<n۾����~��}�EE4�/������X.L��U����n9O�f�j7v��1:p���%�Ѓ�啕څ�%����"|���+ԡ}{�h]rb.�k��4o�
��	� ��R%���sK�|��`����1}��R%���l�"������|jZ����!YeoDE��lv�w!%'�BVV6�Z��RRR)_��.AH�������`���n�A6�R.�֡4u�$�ѽ��ҝ'c�����4���)==������x���G{��5
�ׯ/��I��K�\� ^��_?n�L���_A���
/�މW;�����4Z�r-��?}���;�4ns˖-l�>|�֭����s�a^�а0�ݫ�7nL9R�۲]��w�|6�����={�6뗨�x����凄���͠��vӱ��TXTHO?�k���Ͼ�ӧNy�ر�|���ϖ}�>�ݟ빉2�f�6�s
`�!��x�Fշ��A��3C9-O>1���y��bz����dFD��)�'ڤa$��[�"���g��{G��I'�f���������s�ԇ��6�1�`�F|,X�Тu�v�����
�R^�	￙%��t$EEE��;��	��9�b�<����bz��������ݯn�l&�!�Q@@ �8��Ã
��Um��C��P<���R�{��ԡC;^)8��;N%�%��KU�B�X��-Z��C|�C#X�7z�I�:LP�@&�(���_}���n�I-}3�?�Ҕ�oؤ�>8o�.᪨�Ǔ��y�����JH8D[�m�Aw�l3Fr�`Æ
��o�O^�����wR��Կ_�j+V�᥷�(�:t0�����{��!%%���A�O�:C���t<1���C��
���U�����ڂ���A���o#�G�I9��[������	�r@8��(�SGjժ�"�]�~V����v�Ԧ��ÇVi�d_�QuD=S�R������a�]��`^�gȐ;�����E�|��}r<1�j�3
�h��.�h%�ZIɩt�b�awƌit��!��M����P�|�@+����M�?��qQB��ᇕt��Q:$Fg�R8m�d���S3y�DZ��bڶm'�;F�����08���d^6}p9�̉�fߵkk	-��W^242ܘ��ֻ���Ԋo�}᷆�ً�x�M^6}����0���֭[U�!|����۵�06oުHj����N��i-A��N�_�>Ť���L��~��֎���T��2����O�����?<�~��o��;Ǆ��O�Ic7�r���E��?J��N-�XڶmC���k����t��o�c��&.�sDD=���F9+��7�� ���_�>F�+�1�p�E��tH1kGZ�-Z��$�m&c�#xJ�$ң�)a];����Y�I4'����1�&
�x��/��߇��.�6m��.#���k��m����+�Ϝ�ҋ�e��<��d	k3�BB^y�r�
�gϞ%h�gyHf� �132NImZ���7|`�u��ʚG;��͂cԹ��3'ӨQw�l�o��&NW����3'��������}�ḹ����j�h'�D�@^Z��lHC�W6<q"]vt�m�DG+RJMM�)���Xe�o�|BJz�\��y؇!�a~Re����G
�f$駶�"�ή]�����ȇn G��YBC�n�K�����w��ټY.޷o��؝y��.�\.D�9�9��]6�Ő	?{)5}ZƄ��(n�6C��a��֭+=0c��x=ݠ)�"-YW��y��Vy`�:}��;�Â��x!���;��9
�rrlh6�x��5f��!n)9�5���,��_�g;�!͚6S�M_�Ց�����a��u�
St�����!|d���rq�r�R9��p#�5�ر����F��`���aaG�� ;�GK��K/>��
*�\e{]U��6W�,�����
B¹0M ��L
jA?���Wu�'�BJz7З_~K��4{��l轪.�6<�0{EZkIYY���u�	���f����k��|X�ah5�'��f�!��4Mp&�[8���0CΞ=Ǟ�<��C�޽z���X��]۶��0��1��1�����G���T^br�'�Lʆ]pZ�����ϯ�	�����H��ç��N���<�3�ڨQc6�S	���B�KULkH�������W�/�s����q!%=�':l ��K?7<m� �~�]#x(v�ᒃb��W��{�V�={����,8p�Z
��>��k�)��v��
�q=y{Tf'��5�ɳ�)�� v���6�=�^ƏK˸~��և��+�܉<�C�v)}��rJIKe�R��!1mHeO�Q&�^=#�bqCÖ���d1��b��ƍ���`��0���Af��bڂn3
�ۧ�a�&v���,�-Z�g�4{�L�3ZŋYC���?dB�Q��Ν?���pvp�����+��e!ςW��	���}�a 0<�t=[3��[	�(J�}�>�kd�7v�ޫ<w�~z�)9������ֵ+��Sx���p�m:�޶g�\�$�ڂ.�~[�W%7v�zWKϋ��f���F{��c��Vc;%5����VUR�q3�AE�E��Z������Yf���CM�X�r5a#���Ӧ؜������WP�{���	�h��9Mfy��5b�nӦ͊�:u�D�f=dxO�e˾0f��"�I��WQ���bR������~�� �7j�H�ac��L`B��k�f�cJ�o�2�^'��#�1�4L�x�I	�������=t�es��!�%<���6x#�������.�V+�j�2�V�a6.���R�T�fIJ*3^���+xŊUԞ��#G�y���;8))٘�.l%�-p��[��/Z�4��a�����h�LN������Ub0�����ً�(?�e�#��������<z������ɬ�a:ڇ�3++[���uu��X�hJz%!�J-�����{��������P�.ęwΕ�	j�wE穬�����6�n8���\���FMa�)C@H������x�v���Ȏ�ݠ;88R�A��)9@���׍�;�H�j�O
��:w/7�wPL���"�ȿ����V!rP�5jD�I��>X2��)�V)T���M#IuK��qfo�9n��J�A�nKJ��o5�-8���l:���� P���M	������{��"1�_>Wj��l���[���R�b.�J��<͛~"�� `
�j�fO8�i�a2��w����B�#�V�dn��$MJp�c���"�� `]ܒ�@DMH '���;Kx�L�Gֽ �f���ڔ@HچR��h����Ƅ���i��A��#%MF�q��	�B��7��� 4&����3W�]#5<�#%ݍZ�)i1iA:�D�D�:���� P��%)imIBMH��g&$31�}�A���[��њ�֊�Ą}���<:4�#qA@�{ܖ�4����mIoCS�i�+���P�_ܚ�4!4��>�.�n����@�"�֤h5!A2��=)Ak��Ƥ`�?A��p{R�ȚIH�9͜O�%��G�cH	�j2B\kD�4���@�"�Q�d�Z�Ȍ��� psf�u�$5F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`��<��邀R�b�H�F@HɃ;_�.X!%+���I�`�3DE�A�Xs    IEND�B`�


---
File: /docs/specification/2025-03-26/server/tools.md
---

---
title: Tools
type: docs
weight: 40
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) allows servers to expose tools that can be invoked by
language models. Tools enable models to interact with external systems, such as querying
databases, calling APIs, or performing computations. Each tool is uniquely identified by
a name and includes metadata describing its schema.

## User Interaction Model

Tools in MCP are designed to be **model-controlled**, meaning that the language model can
discover and invoke tools automatically based on its contextual understanding and the
user's prompts.

However, implementations are free to expose tools through any interface pattern that
suits their needs&mdash;the protocol itself does not mandate any specific user
interaction model.

{{< callout type="warning" >}} For trust & safety and security, there **SHOULD** always
be a human in the loop with the ability to deny tool invocations.

Applications **SHOULD**:

- Provide UI that makes clear which tools are being exposed to the AI model
- Insert clear visual indicators when tools are invoked
- Present confirmation prompts to the user for operations, to ensure a human is in the
  loop {{< /callout >}}

## Capabilities

Servers that support tools **MUST** declare the `tools` capability:

```json
{
  "capabilities": {
    "tools": {
      "listChanged": true
    }
  }
}
```

`listChanged` indicates whether the server will emit notifications when the list of
available tools changes.

## Protocol Messages

### Listing Tools

To discover available tools, clients send a `tools/list` request. This operation supports
[pagination]({{< ref "utilities/pagination" >}}).

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather information for a location",
        "inputSchema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name or zip code"
            }
          },
          "required": ["location"]
        }
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}
```

### Calling Tools

To invoke a tool, clients send a `tools/call` request:

**Request:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "location": "New York"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
      }
    ],
    "isError": false
  }
}
```

### List Changed Notification

When the list of available tools changes, servers that declared the `listChanged`
capability **SHOULD** send a notification:

```json
{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed"
}
```

## Message Flow

```mermaid
sequenceDiagram
    participant LLM
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: tools/list
    Server-->>Client: List of tools

    Note over Client,LLM: Tool Selection
    LLM->>Client: Select tool to use

    Note over Client,Server: Invocation
    Client->>Server: tools/call
    Server-->>Client: Tool result
    Client->>LLM: Process result

    Note over Client,Server: Updates
    Server--)Client: tools/list_changed
    Client->>Server: tools/list
    Server-->>Client: Updated tools
```

## Data Types

### Tool

A tool definition includes:

- `name`: Unique identifier for the tool
- `description`: Human-readable description of functionality
- `inputSchema`: JSON Schema defining expected parameters
- `annotations`: optional properties describing tool behavior

{{< callout type="warning" >}} For trust & safety and security, clients **MUST** consider
tool annotations to be untrusted unless they come from trusted servers. {{< /callout >}}

### Tool Result

Tool results can contain multiple content items of different types:

#### Text Content

```json
{
  "type": "text",
  "text": "Tool result text"
}
```

#### Image Content

```json
{
  "type": "image",
  "data": "base64-encoded-data",
  "mimeType": "image/png"
}
```

#### Audio Content

```json
{
  "type": "audio",
  "data": "base64-encoded-audio-data",
  "mimeType": "audio/wav"
}
```

#### Embedded Resources

[Resources]({{< ref "resources" >}}) **MAY** be embedded, to provide additional context
or data, behind a URI that can be subscribed to or fetched again by the client later:

```json
{
  "type": "resource",
  "resource": {
    "uri": "resource://example",
    "mimeType": "text/plain",
    "text": "Resource content"
  }
}
```

## Error Handling

Tools use two error reporting mechanisms:

1. **Protocol Errors**: Standard JSON-RPC errors for issues like:

   - Unknown tools
   - Invalid arguments
   - Server errors

2. **Tool Execution Errors**: Reported in tool results with `isError: true`:
   - API failures
   - Invalid input data
   - Business logic errors

Example protocol error:

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32602,
    "message": "Unknown tool: invalid_tool_name"
  }
}
```

Example tool execution error:

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Failed to fetch weather data: API rate limit exceeded"
      }
    ],
    "isError": true
  }
}
```

## Security Considerations

1. Servers **MUST**:

   - Validate all tool inputs
   - Implement proper access controls
   - Rate limit tool invocations
   - Sanitize tool outputs

2. Clients **SHOULD**:
   - Prompt for user confirmation on sensitive operations
   - Show tool inputs to the user before calling the server, to avoid malicious or
     accidental data exfiltration
   - Validate tool results before passing to LLM
   - Implement timeouts for tool calls
   - Log tool usage for audit purposes



---
File: /docs/specification/2025-03-26/_index.md
---

---
linkTitle: 2025-03-26 (Latest)
title: Model Context Protocol specification
cascade:
  type: docs
breadcrumbs: false
weight: 1
aliases:
  - /latest
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

[Model Context Protocol](https://modelcontextprotocol.io) (MCP) is an open protocol that
enables seamless integration between LLM applications and external data sources and
tools. Whether you're building an AI-powered IDE, enhancing a chat interface, or creating
custom AI workflows, MCP provides a standardized way to connect LLMs with the context
they need.

This specification defines the authoritative protocol requirements, based on the
TypeScript schema in
[schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.ts).

For implementation guides and examples, visit
[modelcontextprotocol.io](https://modelcontextprotocol.io).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14)
[[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)]
[[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)] when, and only when, they
appear in all capitals, as shown here.

## Overview

MCP provides a standardized way for applications to:

- Share contextual information with language models
- Expose tools and capabilities to AI systems
- Build composable integrations and workflows

The protocol uses [JSON-RPC](https://www.jsonrpc.org/) 2.0 messages to establish
communication between:

- **Hosts**: LLM applications that initiate connections
- **Clients**: Connectors within the host application
- **Servers**: Services that provide context and capabilities

MCP takes some inspiration from the
[Language Server Protocol](https://microsoft.github.io/language-server-protocol/), which
standardizes how to add support for programming languages across a whole ecosystem of
development tools. In a similar way, MCP standardizes how to integrate additional context
and tools into the ecosystem of AI applications.

## Key Details

### Base Protocol

- [JSON-RPC](https://www.jsonrpc.org/) message format
- Stateful connections
- Server and client capability negotiation

### Features

Servers offer any of the following features to clients:

- **Resources**: Context and data, for the user or the AI model to use
- **Prompts**: Templated messages and workflows for users
- **Tools**: Functions for the AI model to execute

Clients may offer the following feature to servers:

- **Sampling**: Server-initiated agentic behaviors and recursive LLM interactions

### Additional Utilities

- Configuration
- Progress tracking
- Cancellation
- Error reporting
- Logging

## Security and Trust & Safety

The Model Context Protocol enables powerful capabilities through arbitrary data access
and code execution paths. With this power comes important security and trust
considerations that all implementors must carefully address.

### Key Principles

1. **User Consent and Control**

   - Users must explicitly consent to and understand all data access and operations
   - Users must retain control over what data is shared and what actions are taken
   - Implementors should provide clear UIs for reviewing and authorizing activities

2. **Data Privacy**

   - Hosts must obtain explicit user consent before exposing user data to servers
   - Hosts must not transmit resource data elsewhere without user consent
   - User data should be protected with appropriate access controls

3. **Tool Safety**

   - Tools represent arbitrary code execution and must be treated with appropriate
     caution.
     - In particular, descriptions of tool behavior such as annotations should be
       considered untrusted, unless obtained from a trusted server.
   - Hosts must obtain explicit user consent before invoking any tool
   - Users should understand what each tool does before authorizing its use

4. **LLM Sampling Controls**
   - Users must explicitly approve any LLM sampling requests
   - Users should control:
     - Whether sampling occurs at all
     - The actual prompt that will be sent
     - What results the server can see
   - The protocol intentionally limits server visibility into prompts

### Implementation Guidelines

While MCP itself cannot enforce these security principles at the protocol level,
implementors **SHOULD**:

1. Build robust consent and authorization flows into their applications
2. Provide clear documentation of security implications
3. Implement appropriate access controls and data protections
4. Follow security best practices in their integrations
5. Consider privacy implications in their feature designs

## Learn More

Explore the detailed specification for each protocol component:

{{< cards >}} {{< card link="architecture" title="Architecture" icon="template" >}}
{{< card link="basic" title="Base Protocol" icon="code" >}}
{{< card link="server" title="Server Features" icon="server" >}}
{{< card link="client" title="Client Features" icon="user" >}}
{{< card link="contributing" title="Contributing" icon="pencil" >}} {{< /cards >}}



---
File: /docs/specification/2025-03-26/changelog.md
---

---
title: Key Changes
type: docs
weight: 5
---

This document lists changes made to the Model Context Protocol (MCP) specification since
the previous revision, [2024-11-05]({{< ref "../2024-11-05" >}}).

## Major changes

1. Added a comprehensive **[authorization framework]({{< ref "basic/authorization" >}})**
   based on OAuth 2.1 (PR
   [#133](https://github.com/modelcontextprotocol/specification/pull/133))
1. Replaced the previous HTTP+SSE transport with a more flexible **[Streamable HTTP
   transport]({{< ref "basic/transports#streamable-http" >}})** (PR
   [#206](https://github.com/modelcontextprotocol/specification/pull/206))
1. Added support for JSON-RPC **[batching](https://www.jsonrpc.org/specification#batch)**
   (PR [#228](https://github.com/modelcontextprotocol/specification/pull/228))
1. Added comprehensive **tool annotations** for better describing tool behavior, like
   whether it is read-only or destructive (PR
   [#185](https://github.com/modelcontextprotocol/specification/pull/185))

## Other schema changes

- Added `message` field to `ProgressNotification` to provide descriptive status updates
- Added support for audio data, joining the existing text and image content types
- Added `completions` capability to explicitly indicate support for argument
  autocompletion suggestions

See
[the updated schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2025-03-26/schema.ts)
for more details.

## Full changelog

For a complete list of all changes that have been made since the last protocol revision,
[see GitHub](https://github.com/modelcontextprotocol/specification/compare/2024-11-05...2025-03-26).



---
File: /docs/specification/_index.md
---

---
title: Specification
cascade:
  type: docs
breadcrumbs: false
weight: 10
---



---
File: /docs/specification/contributing.md
---

---
title: "Contributions"
weight: 20
cascade:
  type: docs
breadcrumbs: false
---

We welcome contributions from the community! Please review our
[contributing guidelines](https://github.com/modelcontextprotocol/specification/blob/main/CONTRIBUTING.md)
for details on how to submit changes.

All contributors must adhere to our
[Code of Conduct](https://github.com/modelcontextprotocol/specification/blob/main/CODE_OF_CONDUCT.md).

For questions and discussions, please use
[GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions).



---
File: /docs/specification/versioning.md
---

---
title: Versioning
type: docs
weight: 10
---

The Model Context Protocol uses string-based version identifiers following the format
`YYYY-MM-DD`, to indicate the last date backwards incompatible changes were made.

{{< callout type="info" >}} The protocol version will _not_ be incremented when the
protocol is updated, as long as the changes maintain backwards compatibility. This allows
for incremental improvements while preserving interoperability. {{< /callout >}}

## Revisions

Revisions may be marked as:

- **Draft**: in-progress specifications, not yet ready for consumption.
- **Current**: the current protocol version, which is ready for use and may continue to
  receive backwards compatible changes.
- **Final**: past, complete specifications that will not be changed.

The **current** protocol version is [**2025-03-26**]({{< ref "2025-03-26" >}}).

## Negotiation

Version negotiation happens during
[initialization]({{< ref "2025-03-26/basic/lifecycle#initialization" >}}). Clients and
servers **MAY** support multiple protocol versions simultaneously, but they **MUST**
agree on a single version to use for the session.

The protocol provides appropriate error handling if version negotiation fails, allowing
clients to gracefully terminate connections when they cannot find a version compatible
with the server.



---
File: /schema/2024-11-05/schema.ts
---

/* JSON-RPC types */
export type JSONRPCMessage =
  | JSONRPCRequest
  | JSONRPCNotification
  | JSONRPCResponse
  | JSONRPCError;

export const LATEST_PROTOCOL_VERSION = "2024-11-05";
export const JSONRPC_VERSION = "2.0";

/**
 * A progress token, used to associate progress notifications with the original request.
 */
export type ProgressToken = string | number;

/**
 * An opaque token used to represent a cursor for pagination.
 */
export type Cursor = string;

export interface Request {
  method: string;
  params?: {
    _meta?: {
      /**
       * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
       */
      progressToken?: ProgressToken;
    };
    [key: string]: unknown;
  };
}

export interface Notification {
  method: string;
  params?: {
    /**
     * This parameter name is reserved by MCP to allow clients and servers to attach additional metadata to their notifications.
     */
    _meta?: { [key: string]: unknown };
    [key: string]: unknown;
  };
}

export interface Result {
  /**
   * This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.
   */
  _meta?: { [key: string]: unknown };
  [key: string]: unknown;
}

/**
 * A uniquely identifying ID for a request in JSON-RPC.
 */
export type RequestId = string | number;

/**
 * A request that expects a response.
 */
export interface JSONRPCRequest extends Request {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
}

/**
 * A notification which does not expect a response.
 */
export interface JSONRPCNotification extends Notification {
  jsonrpc: typeof JSONRPC_VERSION;
}

/**
 * A successful (non-error) response to a request.
 */
export interface JSONRPCResponse {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
  result: Result;
}

// Standard JSON-RPC error codes
export const PARSE_ERROR = -32700;
export const INVALID_REQUEST = -32600;
export const METHOD_NOT_FOUND = -32601;
export const INVALID_PARAMS = -32602;
export const INTERNAL_ERROR = -32603;

/**
 * A response to a request that indicates an error occurred.
 */
export interface JSONRPCError {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
  error: {
    /**
     * The error type that occurred.
     */
    code: number;
    /**
     * A short description of the error. The message SHOULD be limited to a concise single sentence.
     */
    message: string;
    /**
     * Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.).
     */
    data?: unknown;
  };
}

/* Empty result */
/**
 * A response that indicates success but carries no data.
 */
export type EmptyResult = Result;

/* Cancellation */
/**
 * This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
 *
 * The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
 *
 * This notification indicates that the result will be unused, so any associated processing SHOULD cease.
 *
 * A client MUST NOT attempt to cancel its `initialize` request.
 */
export interface CancelledNotification extends Notification {
  method: "notifications/cancelled";
  params: {
    /**
     * The ID of the request to cancel.
     *
     * This MUST correspond to the ID of a request previously issued in the same direction.
     */
    requestId: RequestId;

    /**
     * An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
     */
    reason?: string;
  };
}

/* Initialization */
/**
 * This request is sent from the client to the server when it first connects, asking it to begin initialization.
 */
export interface InitializeRequest extends Request {
  method: "initialize";
  params: {
    /**
     * The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.
     */
    protocolVersion: string;
    capabilities: ClientCapabilities;
    clientInfo: Implementation;
  };
}

/**
 * After receiving an initialize request from the client, the server sends this response.
 */
export interface InitializeResult extends Result {
  /**
   * The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect.
   */
  protocolVersion: string;
  capabilities: ServerCapabilities;
  serverInfo: Implementation;
  /**
   * Instructions describing how to use the server and its features.
   *
   * This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt.
   */
  instructions?: string;
}

/**
 * This notification is sent from the client to the server after initialization has finished.
 */
export interface InitializedNotification extends Notification {
  method: "notifications/initialized";
}

/**
 * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
 */
export interface ClientCapabilities {
  /**
   * Experimental, non-standard capabilities that the client supports.
   */
  experimental?: { [key: string]: object };
  /**
   * Present if the client supports listing roots.
   */
  roots?: {
    /**
     * Whether the client supports notifications for changes to the roots list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the client supports sampling from an LLM.
   */
  sampling?: object;
}

/**
 * Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
 */
export interface ServerCapabilities {
  /**
   * Experimental, non-standard capabilities that the server supports.
   */
  experimental?: { [key: string]: object };
  /**
   * Present if the server supports sending log messages to the client.
   */
  logging?: object;
  /**
   * Present if the server offers any prompt templates.
   */
  prompts?: {
    /**
     * Whether this server supports notifications for changes to the prompt list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the server offers any resources to read.
   */
  resources?: {
    /**
     * Whether this server supports subscribing to resource updates.
     */
    subscribe?: boolean;
    /**
     * Whether this server supports notifications for changes to the resource list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the server offers any tools to call.
   */
  tools?: {
    /**
     * Whether this server supports notifications for changes to the tool list.
     */
    listChanged?: boolean;
  };
}

/**
 * Describes the name and version of an MCP implementation.
 */
export interface Implementation {
  name: string;
  version: string;
}

/* Ping */
/**
 * A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
 */
export interface PingRequest extends Request {
  method: "ping";
}

/* Progress notifications */
/**
 * An out-of-band notification used to inform the receiver of a progress update for a long-running request.
 */
export interface ProgressNotification extends Notification {
  method: "notifications/progress";
  params: {
    /**
     * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.
     */
    progressToken: ProgressToken;
    /**
     * The progress thus far. This should increase every time progress is made, even if the total is unknown.
     *
     * @TJS-type number
     */
    progress: number;
    /**
     * Total number of items to process (or total progress required), if known.
     *
     * @TJS-type number
     */
    total?: number;
  };
}

/* Pagination */
export interface PaginatedRequest extends Request {
  params?: {
    /**
     * An opaque token representing the current pagination position.
     * If provided, the server should return results starting after this cursor.
     */
    cursor?: Cursor;
  };
}

export interface PaginatedResult extends Result {
  /**
   * An opaque token representing the pagination position after the last returned result.
   * If present, there may be more results available.
   */
  nextCursor?: Cursor;
}

/* Resources */
/**
 * Sent from the client to request a list of resources the server has.
 */
export interface ListResourcesRequest extends PaginatedRequest {
  method: "resources/list";
}

/**
 * The server's response to a resources/list request from the client.
 */
export interface ListResourcesResult extends PaginatedResult {
  resources: Resource[];
}

/**
 * Sent from the client to request a list of resource templates the server has.
 */
export interface ListResourceTemplatesRequest extends PaginatedRequest {
  method: "resources/templates/list";
}

/**
 * The server's response to a resources/templates/list request from the client.
 */
export interface ListResourceTemplatesResult extends PaginatedResult {
  resourceTemplates: ResourceTemplate[];
}

/**
 * Sent from the client to the server, to read a specific resource URI.
 */
export interface ReadResourceRequest extends Request {
  method: "resources/read";
  params: {
    /**
     * The URI of the resource to read. The URI can use any protocol; it is up to the server how to interpret it.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * The server's response to a resources/read request from the client.
 */
export interface ReadResourceResult extends Result {
  contents: (TextResourceContents | BlobResourceContents)[];
}

/**
 * An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface ResourceListChangedNotification extends Notification {
  method: "notifications/resources/list_changed";
}

/**
 * Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
 */
export interface SubscribeRequest extends Request {
  method: "resources/subscribe";
  params: {
    /**
     * The URI of the resource to subscribe to. The URI can use any protocol; it is up to the server how to interpret it.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.
 */
export interface UnsubscribeRequest extends Request {
  method: "resources/unsubscribe";
  params: {
    /**
     * The URI of the resource to unsubscribe from.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
 */
export interface ResourceUpdatedNotification extends Notification {
  method: "notifications/resources/updated";
  params: {
    /**
     * The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * A known resource that the server is capable of reading.
 */
export interface Resource extends Annotated {
  /**
   * The URI of this resource.
   *
   * @format uri
   */
  uri: string;

  /**
   * A human-readable name for this resource.
   *
   * This can be used by clients to populate UI elements.
   */
  name: string;

  /**
   * A description of what this resource represents.
   *
   * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
   */
  description?: string;

  /**
   * The MIME type of this resource, if known.
   */
  mimeType?: string;

  /**
   * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
   *
   * This can be used by Hosts to display file sizes and estimate context window usage.
   */
  size?: number;
}

/**
 * A template description for resources available on the server.
 */
export interface ResourceTemplate extends Annotated {
  /**
   * A URI template (according to RFC 6570) that can be used to construct resource URIs.
   *
   * @format uri-template
   */
  uriTemplate: string;

  /**
   * A human-readable name for the type of resource this template refers to.
   *
   * This can be used by clients to populate UI elements.
   */
  name: string;

  /**
   * A description of what this template is for.
   *
   * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
   */
  description?: string;

  /**
   * The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
   */
  mimeType?: string;
}

/**
 * The contents of a specific resource or sub-resource.
 */
export interface ResourceContents {
  /**
   * The URI of this resource.
   *
   * @format uri
   */
  uri: string;
  /**
   * The MIME type of this resource, if known.
   */
  mimeType?: string;
}

export interface TextResourceContents extends ResourceContents {
  /**
   * The text of the item. This must only be set if the item can actually be represented as text (not binary data).
   */
  text: string;
}

export interface BlobResourceContents extends ResourceContents {
  /**
   * A base64-encoded string representing the binary data of the item.
   *
   * @format byte
   */
  blob: string;
}

/* Prompts */
/**
 * Sent from the client to request a list of prompts and prompt templates the server has.
 */
export interface ListPromptsRequest extends PaginatedRequest {
  method: "prompts/list";
}

/**
 * The server's response to a prompts/list request from the client.
 */
export interface ListPromptsResult extends PaginatedResult {
  prompts: Prompt[];
}

/**
 * Used by the client to get a prompt provided by the server.
 */
export interface GetPromptRequest extends Request {
  method: "prompts/get";
  params: {
    /**
     * The name of the prompt or prompt template.
     */
    name: string;
    /**
     * Arguments to use for templating the prompt.
     */
    arguments?: { [key: string]: string };
  };
}

/**
 * The server's response to a prompts/get request from the client.
 */
export interface GetPromptResult extends Result {
  /**
   * An optional description for the prompt.
   */
  description?: string;
  messages: PromptMessage[];
}

/**
 * A prompt or prompt template that the server offers.
 */
export interface Prompt {
  /**
   * The name of the prompt or prompt template.
   */
  name: string;
  /**
   * An optional description of what this prompt provides
   */
  description?: string;
  /**
   * A list of arguments to use for templating the prompt.
   */
  arguments?: PromptArgument[];
}

/**
 * Describes an argument that a prompt can accept.
 */
export interface PromptArgument {
  /**
   * The name of the argument.
   */
  name: string;
  /**
   * A human-readable description of the argument.
   */
  description?: string;
  /**
   * Whether this argument must be provided.
   */
  required?: boolean;
}

/**
 * The sender or recipient of messages and data in a conversation.
 */
export type Role = "user" | "assistant";

/**
 * Describes a message returned as part of a prompt.
 *
 * This is similar to `SamplingMessage`, but also supports the embedding of
 * resources from the MCP server.
 */
export interface PromptMessage {
  role: Role;
  content: TextContent | ImageContent | EmbeddedResource;
}

/**
 * The contents of a resource, embedded into a prompt or tool call result.
 *
 * It is up to the client how best to render embedded resources for the benefit
 * of the LLM and/or the user.
 */
export interface EmbeddedResource extends Annotated {
  type: "resource";
  resource: TextResourceContents | BlobResourceContents;
}

/**
 * An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface PromptListChangedNotification extends Notification {
  method: "notifications/prompts/list_changed";
}

/* Tools */
/**
 * Sent from the client to request a list of tools the server has.
 */
export interface ListToolsRequest extends PaginatedRequest {
  method: "tools/list";
}

/**
 * The server's response to a tools/list request from the client.
 */
export interface ListToolsResult extends PaginatedResult {
  tools: Tool[];
}

/**
 * The server's response to a tool call.
 *
 * Any errors that originate from the tool SHOULD be reported inside the result
 * object, with `isError` set to true, _not_ as an MCP protocol-level error
 * response. Otherwise, the LLM would not be able to see that an error occurred
 * and self-correct.
 *
 * However, any errors in _finding_ the tool, an error indicating that the
 * server does not support tool calls, or any other exceptional conditions,
 * should be reported as an MCP error response.
 */
export interface CallToolResult extends Result {
  content: (TextContent | ImageContent | EmbeddedResource)[];

  /**
   * Whether the tool call ended in an error.
   *
   * If not set, this is assumed to be false (the call was successful).
   */
  isError?: boolean;
}

/**
 * Used by the client to invoke a tool provided by the server.
 */
export interface CallToolRequest extends Request {
  method: "tools/call";
  params: {
    name: string;
    arguments?: { [key: string]: unknown };
  };
}

/**
 * An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface ToolListChangedNotification extends Notification {
  method: "notifications/tools/list_changed";
}

/**
 * Definition for a tool the client can call.
 */
export interface Tool {
  /**
   * The name of the tool.
   */
  name: string;
  /**
   * A human-readable description of the tool.
   */
  description?: string;
  /**
   * A JSON Schema object defining the expected parameters for the tool.
   */
  inputSchema: {
    type: "object";
    properties?: { [key: string]: object };
    required?: string[];
  };
}

/* Logging */
/**
 * A request from the client to the server, to enable or adjust logging.
 */
export interface SetLevelRequest extends Request {
  method: "logging/setLevel";
  params: {
    /**
     * The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message.
     */
    level: LoggingLevel;
  };
}

/**
 * Notification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
 */
export interface LoggingMessageNotification extends Notification {
  method: "notifications/message";
  params: {
    /**
     * The severity of this log message.
     */
    level: LoggingLevel;
    /**
     * An optional name of the logger issuing this message.
     */
    logger?: string;
    /**
     * The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
     */
    data: unknown;
  };
}

/**
 * The severity of a log message.
 *
 * These map to syslog message severities, as specified in RFC-5424:
 * https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1
 */
export type LoggingLevel =
  | "debug"
  | "info"
  | "notice"
  | "warning"
  | "error"
  | "critical"
  | "alert"
  | "emergency";

/* Sampling */
/**
 * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
 */
export interface CreateMessageRequest extends Request {
  method: "sampling/createMessage";
  params: {
    messages: SamplingMessage[];
    /**
     * The server's preferences for which model to select. The client MAY ignore these preferences.
     */
    modelPreferences?: ModelPreferences;
    /**
     * An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.
     */
    systemPrompt?: string;
    /**
     * A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. The client MAY ignore this request.
     */
    includeContext?: "none" | "thisServer" | "allServers";
    /**
     * @TJS-type number
     */
    temperature?: number;
    /**
     * The maximum number of tokens to sample, as requested by the server. The client MAY choose to sample fewer tokens than requested.
     */
    maxTokens: number;
    stopSequences?: string[];
    /**
     * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
     */
    metadata?: object;
  };
}

/**
 * The client's response to a sampling/create_message request from the server. The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) and decide whether to allow the server to see it.
 */
export interface CreateMessageResult extends Result, SamplingMessage {
  /**
   * The name of the model that generated the message.
   */
  model: string;
  /**
   * The reason why sampling stopped, if known.
   */
  stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
}

/**
 * Describes a message issued to or received from an LLM API.
 */
export interface SamplingMessage {
  role: Role;
  content: TextContent | ImageContent;
}

/**
 * Base for objects that include optional annotations for the client. The client can use annotations to inform how objects are used or displayed
 */
export interface Annotated {
  annotations?: {
    /**
     * Describes who the intended customer of this object or data is.
     * 
     * It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`).
     */
    audience?: Role[];

    /**
     * Describes how important this data is for operating the server.
     * 
     * A value of 1 means "most important," and indicates that the data is
     * effectively required, while 0 means "least important," and indicates that
     * the data is entirely optional.
     *
     * @TJS-type number
     * @minimum 0
     * @maximum 1
     */
    priority?: number;
  }
}

/**
 * Text provided to or from an LLM.
 */
export interface TextContent extends Annotated {
  type: "text";
  /**
   * The text content of the message.
   */
  text: string;
}

/**
 * An image provided to or from an LLM.
 */
export interface ImageContent extends Annotated {
  type: "image";
  /**
   * The base64-encoded image data.
   *
   * @format byte
   */
  data: string;
  /**
   * The MIME type of the image. Different providers may support different image types.
   */
  mimeType: string;
}

/**
 * The server's preferences for model selection, requested of the client during sampling.
 *
 * Because LLMs can vary along multiple dimensions, choosing the "best" model is
 * rarely straightforward.  Different models excel in different areas—some are
 * faster but less capable, others are more capable but more expensive, and so
 * on. This interface allows servers to express their priorities across multiple
 * dimensions to help clients make an appropriate selection for their use case.
 *
 * These preferences are always advisory. The client MAY ignore them. It is also
 * up to the client to decide how to interpret these preferences and how to
 * balance them against other considerations.
 */
export interface ModelPreferences {
  /**
   * Optional hints to use for model selection.
   *
   * If multiple hints are specified, the client MUST evaluate them in order
   * (such that the first match is taken).
   *
   * The client SHOULD prioritize these hints over the numeric priorities, but
   * MAY still use the priorities to select from ambiguous matches.
   */
  hints?: ModelHint[];

  /**
   * How much to prioritize cost when selecting a model. A value of 0 means cost
   * is not important, while a value of 1 means cost is the most important
   * factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  costPriority?: number;

  /**
   * How much to prioritize sampling speed (latency) when selecting a model. A
   * value of 0 means speed is not important, while a value of 1 means speed is
   * the most important factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  speedPriority?: number;

  /**
   * How much to prioritize intelligence and capabilities when selecting a
   * model. A value of 0 means intelligence is not important, while a value of 1
   * means intelligence is the most important factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  intelligencePriority?: number;
}

/**
 * Hints to use for model selection.
 *
 * Keys not declared here are currently left unspecified by the spec and are up
 * to the client to interpret.
 */
export interface ModelHint {
  /**
   * A hint for a model name.
   *
   * The client SHOULD treat this as a substring of a model name; for example:
   *  - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`
   *  - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.
   *  - `claude` should match any Claude model
   *
   * The client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example:
   *  - `gemini-1.5-flash` could match `claude-3-haiku-20240307`
   */
  name?: string;
}

/* Autocomplete */
/**
 * A request from the client to the server, to ask for completion options.
 */
export interface CompleteRequest extends Request {
  method: "completion/complete";
  params: {
    ref: PromptReference | ResourceReference;
    /**
     * The argument's information
     */
    argument: {
      /**
       * The name of the argument
       */
      name: string;
      /**
       * The value of the argument to use for completion matching.
       */
      value: string;
    };
  };
}

/**
 * The server's response to a completion/complete request
 */
export interface CompleteResult extends Result {
  completion: {
    /**
     * An array of completion values. Must not exceed 100 items.
     */
    values: string[];
    /**
     * The total number of completion options available. This can exceed the number of values actually sent in the response.
     */
    total?: number;
    /**
     * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
     */
    hasMore?: boolean;
  };
}

/**
 * A reference to a resource or resource template definition.
 */
export interface ResourceReference {
  type: "ref/resource";
  /**
   * The URI or URI template of the resource.
   *
   * @format uri-template
   */
  uri: string;
}

/**
 * Identifies a prompt.
 */
export interface PromptReference {
  type: "ref/prompt";
  /**
   * The name of the prompt or prompt template
   */
  name: string;
}

/* Roots */
/**
 * Sent from the server to request a list of root URIs from the client. Roots allow
 * servers to ask for specific directories or files to operate on. A common example
 * for roots is providing a set of repositories or directories a server should operate
 * on.
 *
 * This request is typically used when the server needs to understand the file system
 * structure or access specific locations that the client has permission to read from.
 */
export interface ListRootsRequest extends Request {
  method: "roots/list";
}

/**
 * The client's response to a roots/list request from the server.
 * This result contains an array of Root objects, each representing a root directory
 * or file that the server can operate on.
 */
export interface ListRootsResult extends Result {
  roots: Root[];
}

/**
 * Represents a root directory or file that the server can operate on.
 */
export interface Root {
  /**
   * The URI identifying the root. This *must* start with file:// for now.
   * This restriction may be relaxed in future versions of the protocol to allow
   * other URI schemes.
   *
   * @format uri
   */
  uri: string;
  /**
   * An optional name for the root. This can be used to provide a human-readable
   * identifier for the root, which may be useful for display purposes or for
   * referencing the root in other parts of the application.
   */
  name?: string;
}

/**
 * A notification from the client to the server, informing it that the list of roots has changed.
 * This notification should be sent whenever the client adds, removes, or modifies any root.
 * The server should then request an updated list of roots using the ListRootsRequest.
 */
export interface RootsListChangedNotification extends Notification {
  method: "notifications/roots/list_changed";
}

/* Client messages */
export type ClientRequest =
  | PingRequest
  | InitializeRequest
  | CompleteRequest
  | SetLevelRequest
  | GetPromptRequest
  | ListPromptsRequest
  | ListResourcesRequest
  | ListResourceTemplatesRequest
  | ReadResourceRequest
  | SubscribeRequest
  | UnsubscribeRequest
  | CallToolRequest
  | ListToolsRequest;

export type ClientNotification =
  | CancelledNotification
  | ProgressNotification
  | InitializedNotification
  | RootsListChangedNotification;

export type ClientResult = EmptyResult | CreateMessageResult | ListRootsResult;

/* Server messages */
export type ServerRequest =
  | PingRequest
  | CreateMessageRequest
  | ListRootsRequest;

export type ServerNotification =
  | CancelledNotification
  | ProgressNotification
  | LoggingMessageNotification
  | ResourceUpdatedNotification
  | ResourceListChangedNotification
  | ToolListChangedNotification
  | PromptListChangedNotification;

export type ServerResult =
  | EmptyResult
  | InitializeResult
  | CompleteResult
  | GetPromptResult
  | ListPromptsResult
  | ListResourcesResult
  | ListResourceTemplatesResult
  | ReadResourceResult
  | CallToolResult
  | ListToolsResult;



---
File: /schema/2025-03-26/schema.ts
---

/* JSON-RPC types */

/**
 * Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent.
 */
export type JSONRPCMessage =
  | JSONRPCRequest
  | JSONRPCNotification
  | JSONRPCBatchRequest
  | JSONRPCResponse
  | JSONRPCError
  | JSONRPCBatchResponse;

/**
 * A JSON-RPC batch request, as described in https://www.jsonrpc.org/specification#batch.
 */
export type JSONRPCBatchRequest = (JSONRPCRequest | JSONRPCNotification)[];

/**
 * A JSON-RPC batch response, as described in https://www.jsonrpc.org/specification#batch.
 */
export type JSONRPCBatchResponse = (JSONRPCResponse | JSONRPCError)[];

export const LATEST_PROTOCOL_VERSION = "2025-03-26";
export const JSONRPC_VERSION = "2.0";

/**
 * A progress token, used to associate progress notifications with the original request.
 */
export type ProgressToken = string | number;

/**
 * An opaque token used to represent a cursor for pagination.
 */
export type Cursor = string;

export interface Request {
  method: string;
  params?: {
    _meta?: {
      /**
       * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
       */
      progressToken?: ProgressToken;
    };
    [key: string]: unknown;
  };
}

export interface Notification {
  method: string;
  params?: {
    /**
     * This parameter name is reserved by MCP to allow clients and servers to attach additional metadata to their notifications.
     */
    _meta?: { [key: string]: unknown };
    [key: string]: unknown;
  };
}

export interface Result {
  /**
   * This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses.
   */
  _meta?: { [key: string]: unknown };
  [key: string]: unknown;
}

/**
 * A uniquely identifying ID for a request in JSON-RPC.
 */
export type RequestId = string | number;

/**
 * A request that expects a response.
 */
export interface JSONRPCRequest extends Request {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
}

/**
 * A notification which does not expect a response.
 */
export interface JSONRPCNotification extends Notification {
  jsonrpc: typeof JSONRPC_VERSION;
}

/**
 * A successful (non-error) response to a request.
 */
export interface JSONRPCResponse {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
  result: Result;
}

// Standard JSON-RPC error codes
export const PARSE_ERROR = -32700;
export const INVALID_REQUEST = -32600;
export const METHOD_NOT_FOUND = -32601;
export const INVALID_PARAMS = -32602;
export const INTERNAL_ERROR = -32603;

/**
 * A response to a request that indicates an error occurred.
 */
export interface JSONRPCError {
  jsonrpc: typeof JSONRPC_VERSION;
  id: RequestId;
  error: {
    /**
     * The error type that occurred.
     */
    code: number;
    /**
     * A short description of the error. The message SHOULD be limited to a concise single sentence.
     */
    message: string;
    /**
     * Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.).
     */
    data?: unknown;
  };
}

/* Empty result */
/**
 * A response that indicates success but carries no data.
 */
export type EmptyResult = Result;

/* Cancellation */
/**
 * This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
 *
 * The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
 *
 * This notification indicates that the result will be unused, so any associated processing SHOULD cease.
 *
 * A client MUST NOT attempt to cancel its `initialize` request.
 */
export interface CancelledNotification extends Notification {
  method: "notifications/cancelled";
  params: {
    /**
     * The ID of the request to cancel.
     *
     * This MUST correspond to the ID of a request previously issued in the same direction.
     */
    requestId: RequestId;

    /**
     * An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
     */
    reason?: string;
  };
}

/* Initialization */
/**
 * This request is sent from the client to the server when it first connects, asking it to begin initialization.
 */
export interface InitializeRequest extends Request {
  method: "initialize";
  params: {
    /**
     * The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.
     */
    protocolVersion: string;
    capabilities: ClientCapabilities;
    clientInfo: Implementation;
  };
}

/**
 * After receiving an initialize request from the client, the server sends this response.
 */
export interface InitializeResult extends Result {
  /**
   * The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect.
   */
  protocolVersion: string;
  capabilities: ServerCapabilities;
  serverInfo: Implementation;

  /**
   * Instructions describing how to use the server and its features.
   *
   * This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt.
   */
  instructions?: string;
}

/**
 * This notification is sent from the client to the server after initialization has finished.
 */
export interface InitializedNotification extends Notification {
  method: "notifications/initialized";
}

/**
 * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
 */
export interface ClientCapabilities {
  /**
   * Experimental, non-standard capabilities that the client supports.
   */
  experimental?: { [key: string]: object };
  /**
   * Present if the client supports listing roots.
   */
  roots?: {
    /**
     * Whether the client supports notifications for changes to the roots list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the client supports sampling from an LLM.
   */
  sampling?: object;
}

/**
 * Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
 */
export interface ServerCapabilities {
  /**
   * Experimental, non-standard capabilities that the server supports.
   */
  experimental?: { [key: string]: object };
  /**
   * Present if the server supports sending log messages to the client.
   */
  logging?: object;
  /**
   * Present if the server supports argument autocompletion suggestions.
   */
  completions?: object;
  /**
   * Present if the server offers any prompt templates.
   */
  prompts?: {
    /**
     * Whether this server supports notifications for changes to the prompt list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the server offers any resources to read.
   */
  resources?: {
    /**
     * Whether this server supports subscribing to resource updates.
     */
    subscribe?: boolean;
    /**
     * Whether this server supports notifications for changes to the resource list.
     */
    listChanged?: boolean;
  };
  /**
   * Present if the server offers any tools to call.
   */
  tools?: {
    /**
     * Whether this server supports notifications for changes to the tool list.
     */
    listChanged?: boolean;
  };
}

/**
 * Describes the name and version of an MCP implementation.
 */
export interface Implementation {
  name: string;
  version: string;
}

/* Ping */
/**
 * A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
 */
export interface PingRequest extends Request {
  method: "ping";
}

/* Progress notifications */
/**
 * An out-of-band notification used to inform the receiver of a progress update for a long-running request.
 */
export interface ProgressNotification extends Notification {
  method: "notifications/progress";
  params: {
    /**
     * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding.
     */
    progressToken: ProgressToken;
    /**
     * The progress thus far. This should increase every time progress is made, even if the total is unknown.
     *
     * @TJS-type number
     */
    progress: number;
    /**
     * Total number of items to process (or total progress required), if known.
     *
     * @TJS-type number
     */
    total?: number;
    /**
     * An optional message describing the current progress.
     */
    message?: string;
  };
}

/* Pagination */
export interface PaginatedRequest extends Request {
  params?: {
    /**
     * An opaque token representing the current pagination position.
     * If provided, the server should return results starting after this cursor.
     */
    cursor?: Cursor;
  };
}

export interface PaginatedResult extends Result {
  /**
   * An opaque token representing the pagination position after the last returned result.
   * If present, there may be more results available.
   */
  nextCursor?: Cursor;
}

/* Resources */
/**
 * Sent from the client to request a list of resources the server has.
 */
export interface ListResourcesRequest extends PaginatedRequest {
  method: "resources/list";
}

/**
 * The server's response to a resources/list request from the client.
 */
export interface ListResourcesResult extends PaginatedResult {
  resources: Resource[];
}

/**
 * Sent from the client to request a list of resource templates the server has.
 */
export interface ListResourceTemplatesRequest extends PaginatedRequest {
  method: "resources/templates/list";
}

/**
 * The server's response to a resources/templates/list request from the client.
 */
export interface ListResourceTemplatesResult extends PaginatedResult {
  resourceTemplates: ResourceTemplate[];
}

/**
 * Sent from the client to the server, to read a specific resource URI.
 */
export interface ReadResourceRequest extends Request {
  method: "resources/read";
  params: {
    /**
     * The URI of the resource to read. The URI can use any protocol; it is up to the server how to interpret it.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * The server's response to a resources/read request from the client.
 */
export interface ReadResourceResult extends Result {
  contents: (TextResourceContents | BlobResourceContents)[];
}

/**
 * An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface ResourceListChangedNotification extends Notification {
  method: "notifications/resources/list_changed";
}

/**
 * Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
 */
export interface SubscribeRequest extends Request {
  method: "resources/subscribe";
  params: {
    /**
     * The URI of the resource to subscribe to. The URI can use any protocol; it is up to the server how to interpret it.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.
 */
export interface UnsubscribeRequest extends Request {
  method: "resources/unsubscribe";
  params: {
    /**
     * The URI of the resource to unsubscribe from.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
 */
export interface ResourceUpdatedNotification extends Notification {
  method: "notifications/resources/updated";
  params: {
    /**
     * The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
     *
     * @format uri
     */
    uri: string;
  };
}

/**
 * A known resource that the server is capable of reading.
 */
export interface Resource {
  /**
   * The URI of this resource.
   *
   * @format uri
   */
  uri: string;

  /**
   * A human-readable name for this resource.
   *
   * This can be used by clients to populate UI elements.
   */
  name: string;

  /**
   * A description of what this resource represents.
   *
   * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
   */
  description?: string;

  /**
   * The MIME type of this resource, if known.
   */
  mimeType?: string;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * A template description for resources available on the server.
 */
export interface ResourceTemplate {
  /**
   * A URI template (according to RFC 6570) that can be used to construct resource URIs.
   *
   * @format uri-template
   */
  uriTemplate: string;

  /**
   * A human-readable name for the type of resource this template refers to.
   *
   * This can be used by clients to populate UI elements.
   */
  name: string;

  /**
   * A description of what this template is for.
   *
   * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
   */
  description?: string;

  /**
   * The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
   */
  mimeType?: string;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * The contents of a specific resource or sub-resource.
 */
export interface ResourceContents {
  /**
   * The URI of this resource.
   *
   * @format uri
   */
  uri: string;
  /**
   * The MIME type of this resource, if known.
   */
  mimeType?: string;
}

export interface TextResourceContents extends ResourceContents {
  /**
   * The text of the item. This must only be set if the item can actually be represented as text (not binary data).
   */
  text: string;
}

export interface BlobResourceContents extends ResourceContents {
  /**
   * A base64-encoded string representing the binary data of the item.
   *
   * @format byte
   */
  blob: string;
}

/* Prompts */
/**
 * Sent from the client to request a list of prompts and prompt templates the server has.
 */
export interface ListPromptsRequest extends PaginatedRequest {
  method: "prompts/list";
}

/**
 * The server's response to a prompts/list request from the client.
 */
export interface ListPromptsResult extends PaginatedResult {
  prompts: Prompt[];
}

/**
 * Used by the client to get a prompt provided by the server.
 */
export interface GetPromptRequest extends Request {
  method: "prompts/get";
  params: {
    /**
     * The name of the prompt or prompt template.
     */
    name: string;
    /**
     * Arguments to use for templating the prompt.
     */
    arguments?: { [key: string]: string };
  };
}

/**
 * The server's response to a prompts/get request from the client.
 */
export interface GetPromptResult extends Result {
  /**
   * An optional description for the prompt.
   */
  description?: string;
  messages: PromptMessage[];
}

/**
 * A prompt or prompt template that the server offers.
 */
export interface Prompt {
  /**
   * The name of the prompt or prompt template.
   */
  name: string;
  /**
   * An optional description of what this prompt provides
   */
  description?: string;
  /**
   * A list of arguments to use for templating the prompt.
   */
  arguments?: PromptArgument[];
}

/**
 * Describes an argument that a prompt can accept.
 */
export interface PromptArgument {
  /**
   * The name of the argument.
   */
  name: string;
  /**
   * A human-readable description of the argument.
   */
  description?: string;
  /**
   * Whether this argument must be provided.
   */
  required?: boolean;
}

/**
 * The sender or recipient of messages and data in a conversation.
 */
export type Role = "user" | "assistant";

/**
 * Describes a message returned as part of a prompt.
 *
 * This is similar to `SamplingMessage`, but also supports the embedding of
 * resources from the MCP server.
 */
export interface PromptMessage {
  role: Role;
  content: TextContent | ImageContent | AudioContent | EmbeddedResource;
}

/**
 * The contents of a resource, embedded into a prompt or tool call result.
 *
 * It is up to the client how best to render embedded resources for the benefit
 * of the LLM and/or the user.
 */
export interface EmbeddedResource {
  type: "resource";
  resource: TextResourceContents | BlobResourceContents;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface PromptListChangedNotification extends Notification {
  method: "notifications/prompts/list_changed";
}

/* Tools */
/**
 * Sent from the client to request a list of tools the server has.
 */
export interface ListToolsRequest extends PaginatedRequest {
  method: "tools/list";
}

/**
 * The server's response to a tools/list request from the client.
 */
export interface ListToolsResult extends PaginatedResult {
  tools: Tool[];
}

/**
 * The server's response to a tool call.
 *
 * Any errors that originate from the tool SHOULD be reported inside the result
 * object, with `isError` set to true, _not_ as an MCP protocol-level error
 * response. Otherwise, the LLM would not be able to see that an error occurred
 * and self-correct.
 *
 * However, any errors in _finding_ the tool, an error indicating that the
 * server does not support tool calls, or any other exceptional conditions,
 * should be reported as an MCP error response.
 */
export interface CallToolResult extends Result {
  content: (TextContent | ImageContent | AudioContent | EmbeddedResource)[];

  /**
   * Whether the tool call ended in an error.
   *
   * If not set, this is assumed to be false (the call was successful).
   */
  isError?: boolean;
}

/**
 * Used by the client to invoke a tool provided by the server.
 */
export interface CallToolRequest extends Request {
  method: "tools/call";
  params: {
    name: string;
    arguments?: { [key: string]: unknown };
  };
}

/**
 * An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
 */
export interface ToolListChangedNotification extends Notification {
  method: "notifications/tools/list_changed";
}

/**
 * Additional properties describing a Tool to clients.
 * 
 * NOTE: all properties in ToolAnnotations are **hints**. 
 * They are not guaranteed to provide a faithful description of 
 * tool behavior (including descriptive properties like `title`).
 * 
 * Clients should never make tool use decisions based on ToolAnnotations
 * received from untrusted servers.
 */
export interface ToolAnnotations {
  /**
   * A human-readable title for the tool.
   */
  title?: string;

  /**
   * If true, the tool does not modify its environment.
   * 
   * Default: false
   */
  readOnlyHint?: boolean;

  /**
   * If true, the tool may perform destructive updates to its environment.
   * If false, the tool performs only additive updates.
   * 
   * (This property is meaningful only when `readOnlyHint == false`)
   * 
   * Default: true
   */
  destructiveHint?: boolean;

  /**
   * If true, calling the tool repeatedly with the same arguments 
   * will have no additional effect on the its environment.
   * 
   * (This property is meaningful only when `readOnlyHint == false`)
   * 
   * Default: false
   */
  idempotentHint?: boolean;

  /**
   * If true, this tool may interact with an "open world" of external
   * entities. If false, the tool's domain of interaction is closed.
   * For example, the world of a web search tool is open, whereas that
   * of a memory tool is not.
   * 
   * Default: true
   */
  openWorldHint?: boolean;
}

/**
 * Definition for a tool the client can call.
 */
export interface Tool {
  /**
   * The name of the tool.
   */
  name: string;

  /**
   * A human-readable description of the tool.
   *
   * This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a "hint" to the model.
   */
  description?: string;

  /**
   * A JSON Schema object defining the expected parameters for the tool.
   */
  inputSchema: {
    type: "object";
    properties?: { [key: string]: object };
    required?: string[];
  };

  /**
   * Optional additional tool information.
   */
  annotations?: ToolAnnotations;
}

/* Logging */
/**
 * A request from the client to the server, to enable or adjust logging.
 */
export interface SetLevelRequest extends Request {
  method: "logging/setLevel";
  params: {
    /**
     * The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message.
     */
    level: LoggingLevel;
  };
}

/**
 * Notification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
 */
export interface LoggingMessageNotification extends Notification {
  method: "notifications/message";
  params: {
    /**
     * The severity of this log message.
     */
    level: LoggingLevel;
    /**
     * An optional name of the logger issuing this message.
     */
    logger?: string;
    /**
     * The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
     */
    data: unknown;
  };
}

/**
 * The severity of a log message.
 *
 * These map to syslog message severities, as specified in RFC-5424:
 * https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1
 */
export type LoggingLevel =
  | "debug"
  | "info"
  | "notice"
  | "warning"
  | "error"
  | "critical"
  | "alert"
  | "emergency";

/* Sampling */
/**
 * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
 */
export interface CreateMessageRequest extends Request {
  method: "sampling/createMessage";
  params: {
    messages: SamplingMessage[];
    /**
     * The server's preferences for which model to select. The client MAY ignore these preferences.
     */
    modelPreferences?: ModelPreferences;
    /**
     * An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.
     */
    systemPrompt?: string;
    /**
     * A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. The client MAY ignore this request.
     */
    includeContext?: "none" | "thisServer" | "allServers";
    /**
     * @TJS-type number
     */
    temperature?: number;
    /**
     * The maximum number of tokens to sample, as requested by the server. The client MAY choose to sample fewer tokens than requested.
     */
    maxTokens: number;
    stopSequences?: string[];
    /**
     * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
     */
    metadata?: object;
  };
}

/**
 * The client's response to a sampling/create_message request from the server. The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) and decide whether to allow the server to see it.
 */
export interface CreateMessageResult extends Result, SamplingMessage {
  /**
   * The name of the model that generated the message.
   */
  model: string;
  /**
   * The reason why sampling stopped, if known.
   */
  stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
}

/**
 * Describes a message issued to or received from an LLM API.
 */
export interface SamplingMessage {
  role: Role;
  content: TextContent | ImageContent | AudioContent;
}

/**
 * Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
 */
export interface Annotations {
  /**
   * Describes who the intended customer of this object or data is.
   *
   * It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`).
   */
  audience?: Role[];

  /**
   * Describes how important this data is for operating the server.
   *
   * A value of 1 means "most important," and indicates that the data is
   * effectively required, while 0 means "least important," and indicates that
   * the data is entirely optional.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  priority?: number;
}

/**
 * Text provided to or from an LLM.
 */
export interface TextContent {
  type: "text";

  /**
   * The text content of the message.
   */
  text: string;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * An image provided to or from an LLM.
 */
export interface ImageContent {
  type: "image";

  /**
   * The base64-encoded image data.
   *
   * @format byte
   */
  data: string;

  /**
   * The MIME type of the image. Different providers may support different image types.
   */
  mimeType: string;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * Audio provided to or from an LLM.
 */
export interface AudioContent {
  type: "audio";

  /**
   * The base64-encoded audio data.
   *
   * @format byte
   */
  data: string;

  /**
   * The MIME type of the audio. Different providers may support different audio types.
   */
  mimeType: string;

  /**
   * Optional annotations for the client.
   */
  annotations?: Annotations;
}

/**
 * The server's preferences for model selection, requested of the client during sampling.
 *
 * Because LLMs can vary along multiple dimensions, choosing the "best" model is
 * rarely straightforward.  Different models excel in different areas—some are
 * faster but less capable, others are more capable but more expensive, and so
 * on. This interface allows servers to express their priorities across multiple
 * dimensions to help clients make an appropriate selection for their use case.
 *
 * These preferences are always advisory. The client MAY ignore them. It is also
 * up to the client to decide how to interpret these preferences and how to
 * balance them against other considerations.
 */
export interface ModelPreferences {
  /**
   * Optional hints to use for model selection.
   *
   * If multiple hints are specified, the client MUST evaluate them in order
   * (such that the first match is taken).
   *
   * The client SHOULD prioritize these hints over the numeric priorities, but
   * MAY still use the priorities to select from ambiguous matches.
   */
  hints?: ModelHint[];

  /**
   * How much to prioritize cost when selecting a model. A value of 0 means cost
   * is not important, while a value of 1 means cost is the most important
   * factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  costPriority?: number;

  /**
   * How much to prioritize sampling speed (latency) when selecting a model. A
   * value of 0 means speed is not important, while a value of 1 means speed is
   * the most important factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  speedPriority?: number;

  /**
   * How much to prioritize intelligence and capabilities when selecting a
   * model. A value of 0 means intelligence is not important, while a value of 1
   * means intelligence is the most important factor.
   *
   * @TJS-type number
   * @minimum 0
   * @maximum 1
   */
  intelligencePriority?: number;
}

/**
 * Hints to use for model selection.
 *
 * Keys not declared here are currently left unspecified by the spec and are up
 * to the client to interpret.
 */
export interface ModelHint {
  /**
   * A hint for a model name.
   *
   * The client SHOULD treat this as a substring of a model name; for example:
   *  - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`
   *  - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.
   *  - `claude` should match any Claude model
   *
   * The client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example:
   *  - `gemini-1.5-flash` could match `claude-3-haiku-20240307`
   */
  name?: string;
}

/* Autocomplete */
/**
 * A request from the client to the server, to ask for completion options.
 */
export interface CompleteRequest extends Request {
  method: "completion/complete";
  params: {
    ref: PromptReference | ResourceReference;
    /**
     * The argument's information
     */
    argument: {
      /**
       * The name of the argument
       */
      name: string;
      /**
       * The value of the argument to use for completion matching.
       */
      value: string;
    };
  };
}

/**
 * The server's response to a completion/complete request
 */
export interface CompleteResult extends Result {
  completion: {
    /**
     * An array of completion values. Must not exceed 100 items.
     */
    values: string[];
    /**
     * The total number of completion options available. This can exceed the number of values actually sent in the response.
     */
    total?: number;
    /**
     * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
     */
    hasMore?: boolean;
  };
}

/**
 * A reference to a resource or resource template definition.
 */
export interface ResourceReference {
  type: "ref/resource";
  /**
   * The URI or URI template of the resource.
   *
   * @format uri-template
   */
  uri: string;
}

/**
 * Identifies a prompt.
 */
export interface PromptReference {
  type: "ref/prompt";
  /**
   * The name of the prompt or prompt template
   */
  name: string;
}

/* Roots */
/**
 * Sent from the server to request a list of root URIs from the client. Roots allow
 * servers to ask for specific directories or files to operate on. A common example
 * for roots is providing a set of repositories or directories a server should operate
 * on.
 *
 * This request is typically used when the server needs to understand the file system
 * structure or access specific locations that the client has permission to read from.
 */
export interface ListRootsRequest extends Request {
  method: "roots/list";
}

/**
 * The client's response to a roots/list request from the server.
 * This result contains an array of Root objects, each representing a root directory
 * or file that the server can operate on.
 */
export interface ListRootsResult extends Result {
  roots: Root[];
}

/**
 * Represents a root directory or file that the server can operate on.
 */
export interface Root {
  /**
   * The URI identifying the root. This *must* start with file:// for now.
   * This restriction may be relaxed in future versions of the protocol to allow
   * other URI schemes.
   *
   * @format uri
   */
  uri: string;
  /**
   * An optional name for the root. This can be used to provide a human-readable
   * identifier for the root, which may be useful for display purposes or for
   * referencing the root in other parts of the application.
   */
  name?: string;
}

/**
 * A notification from the client to the server, informing it that the list of roots has changed.
 * This notification should be sent whenever the client adds, removes, or modifies any root.
 * The server should then request an updated list of roots using the ListRootsRequest.
 */
export interface RootsListChangedNotification extends Notification {
  method: "notifications/roots/list_changed";
}

/* Client messages */
export type ClientRequest =
  | PingRequest
  | InitializeRequest
  | CompleteRequest
  | SetLevelRequest
  | GetPromptRequest
  | ListPromptsRequest
  | ListResourcesRequest
  | ReadResourceRequest
  | SubscribeRequest
  | UnsubscribeRequest
  | CallToolRequest
  | ListToolsRequest;

export type ClientNotification =
  | CancelledNotification
  | ProgressNotification
  | InitializedNotification
  | RootsListChangedNotification;

export type ClientResult = EmptyResult | CreateMessageResult | ListRootsResult;

/* Server messages */
export type ServerRequest =
  | PingRequest
  | CreateMessageRequest
  | ListRootsRequest;

export type ServerNotification =
  | CancelledNotification
  | ProgressNotification
  | LoggingMessageNotification
  | ResourceUpdatedNotification
  | ResourceListChangedNotification
  | ToolListChangedNotification
  | PromptListChangedNotification;

export type ServerResult =
  | EmptyResult
  | InitializeResult
  | CompleteResult
  | GetPromptResult
  | ListPromptsResult
  | ListResourcesResult
  | ReadResourceResult
  | CallToolResult
  | ListToolsResult;



---
File: /scripts/validate_examples.ts
---

import * as fs from "fs";
import Ajv, { ValidateFunction } from "ajv";
import { globSync } from "glob";
import addFormats from "ajv-formats";
import { readFileSync } from "node:fs";

function createAjvInstance(): { ajv: Ajv; validate: ValidateFunction } {
  const ajv = new Ajv({
    // strict: true,
    allowUnionTypes: true,
  });
  addFormats(ajv);
  const schema = JSON.parse(readFileSync("schema/schema.json", "utf8"));
  const validate = ajv.compile(schema);

  return { ajv, validate };
}

function validateJsonBlocks(
  validate: ValidateFunction,
  filePath: string,
): void {
  const content = fs.readFileSync(filePath, "utf8");
  const jsonBlocks = content.match(/```json\s*\n([\s\S]*?)\n\s*```/g);

  if (!jsonBlocks) {
    console.log("No JSON blocks found in the file.");
    return;
  }

  jsonBlocks.forEach((block, index) => {
    try {
      const jsonContent = block.replace(/```json\s*\n|\n\s*```/g, "");
      const parsedJson = JSON.parse(jsonContent);
      const valid = validate(parsedJson);

      if (valid) {
        console.log(`JSON block ${index + 1} is valid.`);
      } else {
        console.log(`JSON block ${index + 1} is invalid:`);
        console.log(parsedJson);
        console.log(validate.errors);
      }
    } catch (error) {
      console.error(
        `Error parsing JSON block ${index + 1}:`,
        (error as Error).message,
      );
    }
  });
}

const { validate } = createAjvInstance();

// Usage
const mdFiles = globSync("examples/**/*.md", {});

mdFiles.forEach((filePath) => {
  console.log(`Validating JSON blocks in ${filePath}:`);
  validateJsonBlocks(validate, filePath);
  console.log("\n"); // Add a newline for separation between files
});



---
File: /site/layouts/index.html
---

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Model Context Protocol Specification</title>
    <script>window.location.replace("/latest");</script>
    <meta http-equiv="refresh" content="0; url=/latest">
    <link rel="canonical" href="/latest">
</head>
<body>
    <h1>Model Context Protocol Specification</h1>
    <p>Redirecting to <a href="/latest">specification</a>...</p>
</body>
</html>


---
File: /README.md
---

# Model Context Protocol specification

This repo contains the specification and protocol schema for the Model Context Protocol.

The schema is [defined in TypeScript](schema/2024-11-05/schema.ts) first, but
[made available as JSON Schema](schema/2024-11-05/schema.json) as well, for wider
compatibility.

## Contributing

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this
project.

## License

This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for
details.



## Links discovered
- [modelcontextprotocol.io](https://modelcontextprotocol.io)
- [github.com/modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk)
- [Issues](https://github.com/modelcontextprotocol/python-sdk/issues)
- [github.com/modelcontextprotocol/specification](https://github.com/modelcontextprotocol/specification)
- [Discussions](https://github.com/modelcontextprotocol/specification/discussions)
- [github.com/modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk)
- [Issues](https://github.com/modelcontextprotocol/typescript-sdk/issues)
- [Model Context Protocol organization on GitHub](https://github.com/modelcontextprotocol)
- [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
- [GitHub Discussions](https://github.com/modelcontextprotocol/specification/discussions)
- [TypeScript schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.ts)
- [JSON Schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2024-11-05/schema.json)
- [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1)
- [Example of prompt exposed as slash command](https://github.com/eyaltoledano/claude-task-master/blob/main/context/slash-command.png)
- [�f�bs�f.���#'{����0�Gd'�����AbDq�t�=��qq� �  A���h6�0��:�u�8e�����$�Fv`��ną�aH��8\곣��'l

�����E\�Fxd��y������A3h0    IEND�B`�


---
File: /docs/specification/2024-11-05/server/resources.md
---

---
title: Resources
type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2024-11-05 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose
resources to clients. Resources allow servers to share data that provides context to
language models, such as files, database schemas, or application-specific information.
Each resource is uniquely identified by a
[URI](https://datatracker.ietf.org/doc/html/rfc3986)
- [Example of resource context picker](https://github.com/eyaltoledano/claude-task-master/blob/main/context/resource-picker.png)
- [URI templates](https://datatracker.ietf.org/doc/html/rfc6570)
- [XDG MIME type](https://specifications.freedesktop.org/shared-mime-info-spec/0.14/ar01s02.html#id-1.3.14)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.ts)
- [BCP 14](https://datatracker.ietf.org/doc/html/bcp14)
- [[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)
- [[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)
- [JSON-RPC](https://www.jsonrpc.org/)
- [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)
- [batch multiple requests and notifications](https://www.jsonrpc.org/specification#batch)
- [TypeScript schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.ts)
- [JSON Schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.json)
- [OAuth 2.1 IETF DRAFT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12)
- [RFC8414](https://datatracker.ietf.org/doc/html/rfc8414)
- [RFC7591](https://datatracker.ietf.org/doc/html/rfc7591)
- [OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591)
- [OAuth 2.1 Section 5](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5)
- [Section 5.1.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.1.1)
- [Section 5.2](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.2)
- [Section 5.3](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-5.3)
- [batch](https://www.jsonrpc.org/specification#batch)
- [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events)
- [batching](https://www.jsonrpc.org/specification#batch)
- [batched](https://www.jsonrpc.org/specification#batch)
- [SSE standard](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation)
- [`Last-Event-ID`](https://html.spec.whatwg.org/multipage/server-sent-events.html#the-last-event-id-header)
- [�f�bs�f.���#'{����0�Gd'�����AbDq�t�=��qq� �  A���h6�0��:�u�8e�����$�Fv`��ną�aH��8\곣��'l

�����E\�Fxd��y������A3h0    IEND�B`�


---
File: /docs/specification/2025-03-26/server/resources.md
---

---
title: Resources
type: docs
weight: 20
---

{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}}

The Model Context Protocol (MCP) provides a standardized way for servers to expose
resources to clients. Resources allow servers to share data that provides context to
language models, such as files, database schemas, or application-specific information.
Each resource is uniquely identified by a
[URI](https://datatracker.ietf.org/doc/html/rfc3986)
- [schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.ts)
- [#133](https://github.com/modelcontextprotocol/specification/pull/133)
- [#206](https://github.com/modelcontextprotocol/specification/pull/206)
- [#228](https://github.com/modelcontextprotocol/specification/pull/228)
- [#185](https://github.com/modelcontextprotocol/specification/pull/185)
- [the updated schema](http://github.com/modelcontextprotocol/specification/tree/main/schema/2025-03-26/schema.ts)
- [see GitHub](https://github.com/modelcontextprotocol/specification/compare/2024-11-05...2025-03-26)
- [contributing guidelines](https://github.com/modelcontextprotocol/specification/blob/main/CONTRIBUTING.md)
- [Code of Conduct](https://github.com/modelcontextprotocol/specification/blob/main/CODE_OF_CONDUCT.md)
- [defined in TypeScript](https://github.com/eyaltoledano/claude-task-master/blob/main/context/schema/2024-11-05/schema.ts)
- [made available as JSON Schema](https://github.com/eyaltoledano/claude-task-master/blob/main/context/schema/2024-11-05/schema.json)
- [CONTRIBUTING.md](https://github.com/eyaltoledano/claude-task-master/blob/main/context/CONTRIBUTING.md)
- [LICENSE](https://github.com/eyaltoledano/claude-task-master/blob/main/context/LICENSE.md)
- [specification](https://github.com/eyaltoledano/claude-task-master/blob/main/latest.md)

--- context/chats/add-task-dependencies-1.md ---
# Task Title Formatting Issue Discussion

_Exported on 5/22/2025 at 00:05:09 EDT from Cursor (0.50.5)_

---

**User**

in add-task, i noticed that with some providers, the title comes out with the id in it. i dont know if this is a parsing issue (@ollama.js) or if it this is an improvement we ought to make to the system prompt in @add-task.js

---

**Cursor**

Okay, I've looked into this. The issue where the task ID is sometimes included in the generated task title (e.g., "Task #89: Introduce Prioritize Command...") likely stems from the prompt construction in `scripts/modules/task-manager/add-task.js`.

The current user prompt (around line 208) is:
`Create a comprehensive new task (Task #${newTaskId}) for a software development project based on this description: "${prompt}"`

The AI might be interpreting `(Task #${newTaskId})` as part of the content it needs to generate, especially for the title. The `ollama.js` provider itself doesn't seem to be modifying the content in a way that would add the ID; it primarily passes the prompt and schema to the Ollama service.

I'll adjust the user prompt in `scripts/modules/task-manager/add-task.js` to clarify that the task ID is contextual information, not part of the title to be generated.

I'll change this part of the prompt:
`Create a comprehensive new task (Task #${newTaskId}) for a software development project based on this description: "${prompt}"`

to something like:
`You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.`

This rephrasing should guide the AI to use the ID as context rather than including it directly in the `title` field of the generated JSON object.

Here's the proposed change:

```javascript:scripts/modules/task-manager/add-task.js
// ... existing code ...
			if (manualTaskData?.testStrategy)
				contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`;

			// User Prompt
			const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.

      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}

      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}

      Make sure the details and test strategy are thorough and specific.`;

			// Start the loading indicator - only for text mode
			if (outputFormat === 'text') {
// ... existing code ...
```

This change clarifies the role of `newTaskId` for the AI. Let me know if you'd like to test this or make further adjustments!

```javascript
// ... existing code ...
			if (manualTaskData?.testStrategy)
				contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`;

			// User Prompt
			const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.

      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}

      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}

      Make sure the details and test strategy are thorough and specific.`;

			// Start the loading indicator - only for text mode
			if (outputFormat === 'text') {
// ... existing code ...
```

---

**User**

get the details of task id 88 -- i wonder if we can - in the above place, be smart about passing in the ids, titles, descriptions (but not details) and dependencies of all the other tasks

i don't want it to take a ton of context, but the goal here is to also fill in the dependency field when creating a task. right now it's not being filled in and i have to update all the tasks for it to be populated. so i want it to be fixed at the source in add-task ideally and i want a lightweight but accurate way to pass in the other tasks and their dependencies, and not passing in the actual details of the task and only the above as i explained might be enough.

---

**Cursor**

Let me get the details of task ID 88 first:

Now I'll look at the current implementation of add-task.js to understand how we can improve the context provided to the AI:

Based on the task details and the current implementation of add-task.js, I'll create an improved version that provides more context about other tasks and their dependency relationships without overwhelming the token limit. Here's my proposed change:

```javascript
// ... existing code ...
report('DEBUG: Taking AI task generation path.', 'debug');
// --- Refactored AI Interaction ---
report(`Generating task data with AI with prompt:\n${prompt}`, 'info');

// Create context string for task creation prompt
let contextTasks = '';

// Create a dependency map for better understanding of the task relationships
const taskMap = {};
data.tasks.forEach((t) => {
	// For each task, only include id, title, description, and dependencies
	taskMap[t.id] = {
		id: t.id,
		title: t.title,
		description: t.description,
		dependencies: t.dependencies || [],
		status: t.status
	};
});

if (numericDependencies.length > 0) {
	// If specific dependencies were provided, focus on them
	const dependentTasks = data.tasks.filter((t) =>
		numericDependencies.includes(t.id)
	);
	contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks
		.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
		.join('\n')}`;

	// Add dependency chain information (what these tasks depend on)
	const dependencyChains = [];
	for (const depTask of dependentTasks) {
		if (depTask.dependencies && depTask.dependencies.length > 0) {
			const subDeps = depTask.dependencies.map((subDepId) => {
				const subDepTask = data.tasks.find((t) => t.id === subDepId);
				return subDepTask
					? `Task ${subDepId}: ${subDepTask.title}`
					: `Task ${subDepId}`;
			});
			dependencyChains.push(
				`Task ${depTask.id} depends on: ${subDeps.join(', ')}`
			);
		}
	}

	if (dependencyChains.length > 0) {
		contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`;
	}
} else {
	// If no dependencies provided, show recent and related tasks
	// Get recent tasks (newest first)
	const recentTasks = [...data.tasks].sort((a, b) => b.id - a.id).slice(0, 5);

	// Get tasks that might be related based on simple keyword matching
	const keywords = prompt
		.toLowerCase()
		.split(/\s+/)
		.filter(
			(word) =>
				word.length > 4 &&
				!['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word)
		);

	const relatedTasks =
		keywords.length > 0
			? data.tasks
					.filter(
						(t) =>
							keywords.some(
								(keyword) =>
									t.title.toLowerCase().includes(keyword) ||
									t.description.toLowerCase().includes(keyword)
							) && !recentTasks.some((rt) => rt.id === t.id)
					)
					.slice(0, 3)
			: [];

	if (recentTasks.length > 0) {
		contextTasks = `\nRecent tasks in the project:\n${recentTasks
			.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
			.join('\n')}`;
	}

	if (relatedTasks.length > 0) {
		contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks
			.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
			.join('\n')}`;
	}

	// Add a concise view of the task dependency structure
	contextTasks += '\n\nSummary of task dependencies in the project:';
	const pendingTasks = data.tasks.filter((t) => t.status !== 'done').slice(-10);
	for (const task of pendingTasks) {
		const depsStr =
			task.dependencies && task.dependencies.length > 0
				? task.dependencies.join(', ')
				: 'None';
		contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`;
	}
}

// System Prompt - Enhanced for dependency awareness
const systemPrompt =
	"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.";

// Task Structure Description (for user prompt)
const taskStructureDesc = `
      {
        "title": "Task title goes here",
        "description": "A concise one or two sentence description of what the task involves",
        "details": "In-depth implementation details, considerations, and guidance.",
        "testStrategy": "Detailed approach for verifying task completion."
      }`;

// Add any manually provided details to the prompt for context
let contextFromArgs = '';
if (manualTaskData?.title)
	contextFromArgs += `\n- Suggested Title: "${manualTaskData.title}"`;
if (manualTaskData?.description)
	contextFromArgs += `\n- Suggested Description: "${manualTaskData.description}"`;
if (manualTaskData?.details)
	contextFromArgs += `\n- Additional Details Context: "${manualTaskData.details}"`;
if (manualTaskData?.testStrategy)
	contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`;

// User Prompt
const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.
      
      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}
      
      Based on the information about existing tasks and their dependencies, suggest appropriate dependencies for this task if any are needed. The task IDs mentioned above can be referenced in your implementation details.
      
      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}
      
      Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`;
// ... existing code ...
```

Now let's test the changes to see if they improve the task creation process, especially around dependency handling:

---

**User**

this will probably need to be adjusted so from a structured output pov the ai knows to add the info in that field

---

**Cursor**

You're absolutely right. While our changes improve the context provided to the AI, they don't provide a structured way for the AI to include the dependencies in its output schema. Let's modify the Zod schema to explicitly include a `dependencies` field:

```javascript
// Define Zod schema for the expected AI output object
const AiTaskDataSchema = z.object({
	title: z.string().describe('Clear, concise title for the task'),
	description: z
		.string()
		.describe('A one or two sentence description of the task'),
	details: z
		.string()
		.describe('In-depth implementation details, considerations, and guidance'),
	testStrategy: z
		.string()
		.describe('Detailed approach for verifying task completion'),
	dependencies: z
		.array(z.number())
		.optional()
		.describe(
			'Array of task IDs that this task depends on (must be completed before this task can start)'
		)
});

// ... existing code ...

// Task Structure Description (for user prompt)
const taskStructureDesc = `
      {
        "title": "Task title goes here",
        "description": "A concise one or two sentence description of what the task involves",
        "details": "In-depth implementation details, considerations, and guidance.",
        "testStrategy": "Detailed approach for verifying task completion.",
        "dependencies": [1, 2, 3] // Optional: Array of existing task IDs that this task depends on
      }`;

// ... existing code ...

// User Prompt
const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.
      
      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}
      
      Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on.
      
      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}
      
      Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`;

// ... existing code ...

// Create the new task object
const newTask = {
	id: newTaskId,
	title: taskData.title,
	description: taskData.description,
	details: taskData.details || '',
	testStrategy: taskData.testStrategy || '',
	status: 'pending',
	dependencies: taskData.dependencies?.length
		? taskData.dependencies
		: numericDependencies, // Use AI-suggested dependencies if available, fallback to manually specified
	priority: effectivePriority,
	subtasks: [] // Initialize with empty subtasks array
};
```

Let's make one more small fix - I notice there's still a reference to `numericDependencies` in the success message output that should be adjusted to use the task's actual dependencies:

```javascript
// ... existing code ...
			console.log(
				boxen(
					chalk.white.bold(`Task ${newTaskId} Created Successfully`) +
						'\n\n' +
						chalk.white(`Title: ${newTask.title}`) +
						'\n' +
						chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) +
						'\n' +
						chalk.white(
							`Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}`
						) +
						'\n' +
						(newTask.dependencies.length > 0
							? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) +
								'\n'
							: '') +
						'\n' +
// ... existing code ...
```

Now let's test our changes to make sure they work properly:

---

**User**

looks like it worked. i would like -- in the case of the CLI only, to also show some additional stuff in @add-task.js

we just did a bunch of magic, and it would be too bad not to show it to the user as we do it, without it being too much

(ignore the failed ollama call)

i think there could be a line or two that shows the identified dependencies or something. its sexy stuff, let's make sure the user knows about it elegantly. @ui.js

---

**Cursor**

Let's enhance the CLI experience to elegantly showcase the dependency analysis we're performing. I'll add a small, informative display in add-task.js that shows the intelligent context we're building:

```javascript
// ... existing code ...
// Create a dependency map for better understanding of the task relationships
const taskMap = {};
data.tasks.forEach((t) => {
	// For each task, only include id, title, description, and dependencies
	taskMap[t.id] = {
		id: t.id,
		title: t.title,
		description: t.description,
		dependencies: t.dependencies || [],
		status: t.status
	};
});

// CLI-only feedback for the dependency analysis
if (outputFormat === 'text') {
	console.log(
		boxen(chalk.cyan.bold('Task Context Analysis') + '\n', {
			padding: { top: 0, bottom: 0, left: 1, right: 1 },
			margin: { top: 0, bottom: 0 },
			borderColor: 'cyan',
			borderStyle: 'round'
		})
	);
}

if (numericDependencies.length > 0) {
	// If specific dependencies were provided, focus on them
	const dependentTasks = data.tasks.filter((t) =>
		numericDependencies.includes(t.id)
	);
	contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks
		.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
		.join('\n')}`;

	// Add dependency chain information (what these tasks depend on)
	const dependencyChains = [];
	for (const depTask of dependentTasks) {
		if (depTask.dependencies && depTask.dependencies.length > 0) {
			const subDeps = depTask.dependencies.map((subDepId) => {
				const subDepTask = data.tasks.find((t) => t.id === subDepId);
				return subDepTask
					? `Task ${subDepId}: ${subDepTask.title}`
					: `Task ${subDepId}`;
			});
			dependencyChains.push(
				`Task ${depTask.id} depends on: ${subDeps.join(', ')}`
			);
		}
	}

	if (dependencyChains.length > 0) {
		contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`;
	}

	// Show dependency chains in CLI mode
	if (outputFormat === 'text' && dependentTasks.length > 0) {
		console.log(chalk.gray(`  Explicitly specified dependencies:`));
		dependentTasks.forEach((t) => {
			console.log(chalk.yellow(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
		});

		if (dependencyChains.length > 0) {
			console.log(chalk.gray(`\n  Analyzing dependency chains:`));
			dependencyChains.forEach((chain) => {
				console.log(chalk.cyan(`  • ${truncate(chain, 60)}`));
			});
		}
		console.log(); // Add spacing
	}
} else {
	// If no dependencies provided, show recent and related tasks
	// Get recent tasks (newest first)
	const recentTasks = [...data.tasks].sort((a, b) => b.id - a.id).slice(0, 5);

	// Get tasks that might be related based on simple keyword matching
	const keywords = prompt
		.toLowerCase()
		.split(/\s+/)
		.filter(
			(word) =>
				word.length > 4 &&
				!['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word)
		);

	const relatedTasks =
		keywords.length > 0
			? data.tasks
					.filter(
						(t) =>
							keywords.some(
								(keyword) =>
									t.title.toLowerCase().includes(keyword) ||
									t.description.toLowerCase().includes(keyword)
							) && !recentTasks.some((rt) => rt.id === t.id)
					)
					.slice(0, 3)
			: [];

	if (recentTasks.length > 0) {
		contextTasks = `\nRecent tasks in the project:\n${recentTasks
			.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
			.join('\n')}`;
	}

	if (relatedTasks.length > 0) {
		contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks
			.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
			.join('\n')}`;
	}

	// Add a concise view of the task dependency structure
	contextTasks += '\n\nSummary of task dependencies in the project:';
	const pendingTasks = data.tasks.filter((t) => t.status !== 'done').slice(-10);
	for (const task of pendingTasks) {
		const depsStr =
			task.dependencies && task.dependencies.length > 0
				? task.dependencies.join(', ')
				: 'None';
		contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`;
	}

	// Show keyword-based analysis in CLI mode
	if (outputFormat === 'text') {
		if (keywords.length > 0) {
			console.log(
				chalk.gray(`  Keywords extracted for analysis: ${keywords.join(', ')}`)
			);

			if (relatedTasks.length > 0) {
				console.log(
					chalk.gray(`\n  Potentially related tasks by keyword match:`)
				);
				relatedTasks.forEach((t) => {
					console.log(
						chalk.yellow(`  • Task ${t.id}: ${truncate(t.title, 50)}`)
					);
				});
			}
		}

		// Show the recent tasks used for context
		if (recentTasks.length > 0) {
			console.log(chalk.gray(`\n  Using recent tasks for context:`));
			recentTasks.slice(0, 3).forEach((t) => {
				console.log(chalk.cyan(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
			});
		}

		// Show dependency structure visualization
		if (pendingTasks.length > 0) {
			const depsToShow = Math.min(3, pendingTasks.length);
			console.log(
				chalk.gray(
					`\n  Task dependency patterns analyzed (${depsToShow} example${depsToShow > 1 ? 's' : ''}):`
				)
			);
			pendingTasks.slice(0, depsToShow).forEach((task) => {
				const depsStr =
					task.dependencies && task.dependencies.length > 0
						? chalk.yellow(task.dependencies.join(', '))
						: chalk.gray('None');
				console.log(chalk.blue(`  • Task ${task.id} → [${depsStr}]`));
			});
		}
		console.log(); // Add spacing
	}
}

// System Prompt - Enhanced for dependency awareness
// ... existing code ...
```

Now let's also add a visual indicator before the AI call to make the transition clearer and make the experience more engaging:

```javascript
// ... existing code ...
				console.log(); // Add spacing
			}
		}

		// System Prompt - Enhanced for dependency awareness
		const systemPrompt =
			"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.";

		// Task Structure Description (for user prompt)
		const taskStructureDesc = `
  {
    "title": "Task title goes here",
    "description": "A concise one or two sentence description of what the task involves",
    "details": "In-depth implementation details, considerations, and guidance.",
    "testStrategy": "Detailed approach for verifying task completion.",
    "dependencies": [1, 2, 3] // Optional: Array of existing task IDs that this task depends on
  }`;

		// Add any manually provided details to the prompt for context
		let contextFromArgs = '';
		if (manualTaskData?.title)
			contextFromArgs += `\n- Suggested Title: "${manualTaskData.title}"`;
		if (manualTaskData?.description)
			contextFromArgs += `\n- Suggested Description: "${manualTaskData.description}"`;
		if (manualTaskData?.details)
			contextFromArgs += `\n- Additional Details Context: "${manualTaskData.details}"`;
		if (manualTaskData?.testStrategy)
			contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`;

		// User Prompt
		const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.

  ${contextTasks}
  ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}

  Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on.

  Return your answer as a single JSON object matching the schema precisely:
  ${taskStructureDesc}

  Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`;

		// Start the loading indicator - only for text mode
		if (outputFormat === 'text') {
			// Add a visual transition to show we're moving to AI generation
			console.log(boxen(
				chalk.white.bold('AI Task Generation') +
				`\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` +
				`\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` +
				`\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}`,
				{
					padding: 1,
					borderColor: 'blue',
					borderStyle: 'round',
					margin: { top: 0, bottom: 1 }
				}
			));

			loadingIndicator = startLoadingIndicator(
				`Generating new task with ${useResearch ? 'Research' : 'Main'} AI...\n`
			);
		}

		try {
// ... existing code ...
```

Finally, let's enhance the success message to highlight the AI's dependency analysis and any dependencies added by the AI:

```javascript
// ... existing code ...
				truncate(newTask.description, 47)
			]);

			console.log(chalk.green('✅ New task created successfully:'));
			console.log(table.toString());

			// Helper to get priority color
			const getPriorityColor = (p) => {
				switch (p?.toLowerCase()) {
					case 'high':
						return 'red';
					case 'low':
						return 'gray';
					case 'medium':
					default:
						return 'yellow';
				}
			};

			// Check if AI added new dependencies that weren't explicitly provided
			const aiAddedDeps = newTask.dependencies.filter(
				dep => !numericDependencies.includes(dep)
			);

			// Show success message box
			console.log(
				boxen(
					chalk.white.bold(`Task ${newTaskId} Created Successfully`) +
						'\n\n' +
						chalk.white(`Title: ${newTask.title}`) +
						'\n' +
						chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) +
						'\n' +
						chalk.white(
							`Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}`
						) +
						'\n' +
						(newTask.dependencies.length > 0
							? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) +
								(aiAddedDeps.length > 0
									? chalk.gray(` (${aiAddedDeps.length} auto-detected by AI)`)
									: '') +
								'\n'
							: '') +
						'\n' +
						chalk.white.bold('Next Steps:') +
						'\n' +
// ... existing code ...
```

Let's test the changes to see our enhanced CLI experience in action:

---

**User**

it seems to have worked, but its now the second task that used 1 and 3 as dependencies. across 90 tasks, i find that a bit odd (but not impossible as most tasks are in fact net new)

let's, for the sake of research, also include the details of the other tasks. let's see what happens with the context size

---

**Cursor**

I agree it's interesting that the AI consistently selects tasks 1 and 3 as dependencies. It found these tasks through the keyword matching (showing "Task 1: Implement Task Data Structure" and "Task 3: Implement Basic Task Operations"), but we should provide more comprehensive context to help it make better dependency selections.

Let's enhance the task context by including task details for relevant tasks, not just their titles and descriptions:

```javascript
// ... existing code ...
				taskMap[t.id] = {
					id: t.id,
					title: t.title,
					description: t.description,
					dependencies: t.dependencies || [],
					status: t.status
				};
			});

			// CLI-only feedback for the dependency analysis
			if (outputFormat === 'text') {
				console.log(boxen(
					chalk.cyan.bold('Task Context Analysis') + '\n',
					{
						padding: { top: 0, bottom: 0, left: 1, right: 1 },
						margin: { top: 0, bottom: 0 },
						borderColor: 'cyan',
						borderStyle: 'round'
					}
				));
			}

			if (numericDependencies.length > 0) {
				// If specific dependencies were provided, focus on them
				const dependentTasks = data.tasks.filter((t) =>
					numericDependencies.includes(t.id)
				);
				contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks
					.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
					.join('\n')}`;

				// Add more details about each dependency
				contextTasks += `\n\nDetailed information about dependencies:`;
				for (const depTask of dependentTasks) {
					contextTasks += `\n\n------ Task ${depTask.id}: ${depTask.title} ------\n`;
					contextTasks += `Description: ${depTask.description}\n`;
					contextTasks += `Status: ${depTask.status || 'pending'}\n`;
					contextTasks += `Priority: ${depTask.priority || 'medium'}\n`;
					// Add implementation details but truncate if too long
					if (depTask.details) {
						const truncatedDetails = depTask.details.length > 500
							? depTask.details.substring(0, 500) + '... (truncated)'
							: depTask.details;
						contextTasks += `Implementation Details: ${truncatedDetails}\n`;
					}
				}

				// Add dependency chain information (what these tasks depend on)
				const dependencyChains = [];
				for (const depTask of dependentTasks) {
					if (depTask.dependencies && depTask.dependencies.length > 0) {
						const subDeps = depTask.dependencies.map(subDepId => {
							const subDepTask = data.tasks.find(t => t.id === subDepId);
							return subDepTask ? `Task ${subDepId}: ${subDepTask.title}` : `Task ${subDepId}`;
						});
						dependencyChains.push(`Task ${depTask.id} depends on: ${subDeps.join(', ')}`);
					}
				}

				if (dependencyChains.length > 0) {
					contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`;
				}

				// Show dependency chains in CLI mode
				if (outputFormat === 'text' && dependentTasks.length > 0) {
					console.log(chalk.gray(`  Explicitly specified dependencies:`));
					dependentTasks.forEach(t => {
						console.log(chalk.yellow(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
					});

					if (dependencyChains.length > 0) {
						console.log(chalk.gray(`\n  Analyzing dependency chains:`));
						dependencyChains.forEach(chain => {
							console.log(chalk.cyan(`  • ${truncate(chain, 60)}`));
						});
					}
					console.log(); // Add spacing
				}
			} else {
				// If no dependencies provided, show recent and related tasks
				// Get recent tasks (newest first)
				const recentTasks = [...data.tasks]
					.sort((a, b) => b.id - a.id)
					.slice(0, 5);

				// Get tasks that might be related based on simple keyword matching
				const keywords = prompt.toLowerCase().split(/\s+/).filter(word =>
					word.length > 4 && !['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word)
				);

				// Get related tasks by keyword matching
				const relatedTasks = keywords.length > 0
					? data.tasks.filter(t =>
						keywords.some(keyword =>
							t.title.toLowerCase().includes(keyword) ||
							t.description.toLowerCase().includes(keyword)
						) &&
						!recentTasks.some(rt => rt.id === t.id)
					).slice(0, 5) // Increased from 3 to 5
					: [];

				// Also look for tasks with similar purposes or categories
				const purposeCategories = [
					{pattern: /(command|cli|flag)/i, label: "CLI commands"},
					{pattern: /(task|subtask|add)/i, label: "Task management"},
					{pattern: /(dependency|depend)/i, label: "Dependency handling"},
					{pattern: /(AI|model|prompt)/i, label: "AI integration"},
					{pattern: /(UI|display|show)/i, label: "User interface"}
				];

				const promptCategory = purposeCategories.find(cat => cat.pattern.test(prompt));
				const categoryTasks = promptCategory
					? data.tasks.filter(t =>
						promptCategory.pattern.test(t.title) ||
						promptCategory.pattern.test(t.description) ||
						(t.details && promptCategory.pattern.test(t.details))
					)
					.filter(t =>
						!recentTasks.some(rt => rt.id === t.id) &&
						!relatedTasks.some(rt => rt.id === t.id)
					)
					.slice(0, 3)
					: [];

				// Format basic task overviews
				if (recentTasks.length > 0) {
					contextTasks = `\nRecent tasks in the project:\n${recentTasks
						.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
						.join('\n')}`;
				}

				if (relatedTasks.length > 0) {
					contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks
						.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
						.join('\n')}`;
				}

				if (categoryTasks.length > 0) {
					contextTasks += `\n\nTasks related to ${promptCategory.label}:\n${categoryTasks
						.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
						.join('\n')}`;
				}

				// Add detailed information about the most relevant tasks
				const allDetailedTasks = [...relatedTasks, ...categoryTasks.slice(0, 2), ...recentTasks.slice(0, 2)];
				const uniqueDetailedTasks = Array.from(new Map(allDetailedTasks.map(t => [t.id, t])).values()).slice(0, 5);

				if (uniqueDetailedTasks.length > 0) {
					contextTasks += `\n\nDetailed information about relevant tasks:`;
					for (const task of uniqueDetailedTasks) {
						contextTasks += `\n\n------ Task ${task.id}: ${task.title} ------\n`;
						contextTasks += `Description: ${task.description}\n`;
						contextTasks += `Status: ${task.status || 'pending'}\n`;
						contextTasks += `Priority: ${task.priority || 'medium'}\n`;
						if (task.dependencies && task.dependencies.length > 0) {
							contextTasks += `Dependencies: ${task.dependencies.join(', ')}\n`;
						}
						// Add implementation details but truncate if too long
						if (task.details) {
							const truncatedDetails = task.details.length > 400
								? task.details.substring(0, 400) + '... (truncated)'
								: task.details;
							contextTasks += `Implementation Details: ${truncatedDetails}\n`;
						}
					}
				}

				// Add a concise view of the task dependency structure
				contextTasks += '\n\nSummary of task dependencies in the project:';

				// Focus on pending tasks with the most similar purposes or categories
				// This helps identify patterns in how similar tasks are set up
				const relevantPendingTasks = promptCategory
					? data.tasks
						.filter(t => t.status !== 'done' && (promptCategory.pattern.test(t.title) || promptCategory.pattern.test(t.description)))
						.slice(-10)
					: data.tasks.filter(t => t.status !== 'done').slice(-10);

				for (const task of relevantPendingTasks) {
					const depsStr = task.dependencies && task.dependencies.length > 0
						? task.dependencies.join(', ')
						: 'None';
					contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`;
				}

				// Additional analysis of common patterns
				const commandTasks = data.tasks.filter(t => /command|cli/i.test(t.title) || /command|cli/i.test(t.description));
				if (commandTasks.length > 0 && /command|cli/i.test(prompt)) {
					contextTasks += '\n\nCommon patterns for command implementation tasks:';
					const commandDeps = commandTasks
						.filter(t => t.dependencies && t.dependencies.length > 0)
						.map(t => t.dependencies)
						.flat();

					// Count frequency of each dependency
					const depCounts = {};
					commandDeps.forEach(dep => {
						depCounts[dep] = (depCounts[dep] || 0) + 1;
					});

					// Get most common dependencies for command tasks
					const commonDeps = Object.entries(depCounts)
						.sort((a, b) => b[1] - a[1])
						.slice(0, 3);

					if (commonDeps.length > 0) {
						contextTasks += '\nMost common dependencies for similar tasks:';
						commonDeps.forEach(([depId, count]) => {
							const depTask = data.tasks.find(t => t.id === parseInt(depId));
							if (depTask) {
								contextTasks += `\n- Task ${depId} (used by ${count} similar tasks): ${depTask.title}`;
							}
						});
					}
				}

				// Show keyword-based analysis in CLI mode
				if (outputFormat === 'text') {
					if (keywords.length > 0) {
						console.log(chalk.gray(`  Keywords extracted for analysis: ${keywords.join(', ')}`));

						if (relatedTasks.length > 0) {
							console.log(chalk.gray(`\n  Potentially related tasks by keyword match:`));
							relatedTasks.forEach(t => {
								console.log(chalk.yellow(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
							});
						}
					}

					if (promptCategory && categoryTasks.length > 0) {
						console.log(chalk.gray(`\n  Tasks related to ${promptCategory.label}:`));
						categoryTasks.forEach(t => {
							console.log(chalk.magenta(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
						});
					}

					// Show the recent tasks used for context
					if (recentTasks.length > 0) {
						console.log(chalk.gray(`\n  Using recent tasks for context:`));
						recentTasks.slice(0, 3).forEach(t => {
							console.log(chalk.cyan(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
						});
					}

					// Show dependency structure visualization
					if (relevantPendingTasks.length > 0) {
						const depsToShow = Math.min(3, relevantPendingTasks.length);
						console.log(chalk.gray(`\n  Task dependency patterns analyzed (${depsToShow} example${depsToShow > 1 ? 's' : ''}):`));
						relevantPendingTasks.slice(0, depsToShow).forEach(task => {
							const depsStr = task.dependencies && task.dependencies.length > 0
								? chalk.yellow(task.dependencies.join(', '))
								: chalk.gray('None');
							console.log(chalk.blue(`  • Task ${task.id} → [${depsStr}]`));
						});
					}

					// Add information about which tasks will be provided in detail
					if (uniqueDetailedTasks.length > 0) {
						console.log(chalk.gray(`\n  Providing detailed context for ${uniqueDetailedTasks.length} most relevant tasks:`));
						uniqueDetailedTasks.forEach(t => {
							console.log(chalk.green(`  • Task ${t.id}: ${truncate(t.title, 40)}`));
						});
					}

					console.log(); // Add spacing
				}
			}

			// System Prompt - Enhanced for dependency awareness
// ... existing code ...
```

Now let's modify the task generation display to include context size information and make it more transparent about what's being sent to the AI:

```javascript
// ... existing code ...
			// Add a visual transition to show we're moving to AI generation
			console.log(boxen(
				chalk.white.bold('AI Task Generation') +
				`\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` +
				`\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` +
				`\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}` +
				`\n${chalk.cyan('Detailed tasks: ')}${chalk.yellow(
					numericDependencies.length > 0
						? dependentTasks.length
						: (uniqueDetailedTasks ? uniqueDetailedTasks.length : 0)
				)}` +
				(promptCategory
					? `\n${chalk.cyan('Task category: ')}${chalk.yellow(promptCategory.label)}`
					: '') +
				`\n${chalk.cyan('Dependency analysis depth: ')}${chalk.yellow('Full chain analysis')}`,
				{
					padding: 1,
					borderColor: 'blue',
					borderStyle: 'round',
					margin: { top: 0, bottom: 1 }
				}
			));

			loadingIndicator = startLoadingIndicator(
				`Generating new task with ${useResearch ? 'Research' : 'Main'} AI...\n`
			);
		}

		try {
// ... existing code ...
```

Now, let's update the system prompt to include specific guidance for the AI on how to make better dependency choices:

```javascript
// ... existing code ...
// System Prompt - Enhanced for dependency awareness
const systemPrompt =
	"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" +
	'When determining dependencies for a new task, follow these principles:\n' +
	'1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' +
	'2. Prioritize task dependencies that are semantically related to the functionality being built.\n' +
	'3. Avoid defaulting to early tasks (like tasks #1-3) unless truly necessary foundation work.\n' +
	'4. Consider implementation details of candidate dependent tasks, not just titles.\n' +
	'5. Include the most specific dependencies rather than their parents when appropriate.\n' +
	'6. Focus on technical dependencies rather than organizational ones.';

// Task Structure Description (for user prompt)
// ... existing code ...
```

Let's test the enhanced context and dependency analysis:

---

**User**

error

---

**Cursor**

I see the error - we're trying to use `uniqueDetailedTasks` in our display, but it's only defined in one code branch. Let's fix that:

```javascript
// ... existing code ...
			// CLI-only feedback for the dependency analysis
			if (outputFormat === 'text') {
				console.log(boxen(
					chalk.cyan.bold('Task Context Analysis') + '\n',
					{
						padding: { top: 0, bottom: 0, left: 1, right: 1 },
						margin: { top: 0, bottom: 0 },
						borderColor: 'cyan',
						borderStyle: 'round'
					}
				));
			}

			// Initialize variables that will be used in either branch
			let dependentTasks = [];
			let uniqueDetailedTasks = [];
			let promptCategory = null;

			if (numericDependencies.length > 0) {
				// If specific dependencies were provided, focus on them
				dependentTasks = data.tasks.filter((t) =>
					numericDependencies.includes(t.id)
				);

				// These are our detailed tasks when explicit dependencies are provided
				uniqueDetailedTasks = dependentTasks;

				contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks
					.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
					.join('\n')}`;
// ... existing code ...

			// Add a visual transition to show we're moving to AI generation
			console.log(boxen(
				chalk.white.bold('AI Task Generation') +
				`\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` +
				`\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` +
				`\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}` +
				`\n${chalk.cyan('Detailed tasks: ')}${chalk.yellow(uniqueDetailedTasks.length)}` +
				(promptCategory
					? `\n${chalk.cyan('Task category: ')}${chalk.yellow(promptCategory.label)}`
					: '') +
				`\n${chalk.cyan('Dependency analysis depth: ')}${chalk.yellow('Full chain analysis')}`,
// ... existing code ...
```

Let's also fix the variable that's still defined inside the else branch instead of using our initialization:

```javascript
// ... existing code ...
				const purposeCategories = [
					{pattern: /(command|cli|flag)/i, label: "CLI commands"},
					{pattern: /(task|subtask|add)/i, label: "Task management"},
					{pattern: /(dependency|depend)/i, label: "Dependency handling"},
					{pattern: /(AI|model|prompt)/i, label: "AI integration"},
					{pattern: /(UI|display|show)/i, label: "User interface"}
				];

				promptCategory = purposeCategories.find(cat => cat.pattern.test(prompt));
				const categoryTasks = promptCategory
					? data.tasks.filter(t =>
						promptCategory.pattern.test(t.title) ||
						promptCategory.pattern.test(t.description) ||
						(t.details && promptCategory.pattern.test(t.details))
					)
// ... existing code ...
```

Let's test our fix:

---

**User**

despite ALL that, we still got 1 and 3 -- does that imply our previous implemenation was fine?

we didnt use that many input tokens so im guessing no other tasks were added as dependencies. idk, maybe the issue is the way the keywords/search is working. it should be more fuzzy/smarter or rely more on the LLM even though we definitely would prefer to do as much as we can here to prepare the same information in smaller/condensed/curated format before passing it

but in the end what really matters is to properly capture dependencies. it's possible we dont actually need to -- you can get the get-tasks tool taht you have access to get ALL tasks and make that determination for yourself so you can do a spot check

---

**Cursor**

You're right - despite our enhanced context and guidance, the AI still defaulted to those foundational tasks (1 and 3). It's particularly interesting that the output shows "Detailed tasks: 0" even though we were providing detailed information for 5 tasks.

This suggests a few things:

1. There might still be an issue in how we're tracking `uniqueDetailedTasks` in the code.

2. The model might have a bias toward those early tasks since they are genuinely foundational (Task 1: "Implement Task Data Structure" and Task 3: "Implement Basic Task Operations").

3. Our keyword matching might not be catching the truly relevant semantic connections between tasks.

You've made an excellent point about letting the AI have more direct access to tasks. Here are two approaches we could take:

1. **AI-assisted pre-processing**: We could use an AI call to identify potential dependencies before the main task creation, specifically to analyze relevance.

2. **Direct access approach**: As you suggested, we could rely on the AI's ability to access all tasks directly through tools like `get_tasks`. This approach leverages the model's semantic understanding while giving it full access to the data.

Would you like me to implement the fix for the "Detailed tasks: 0" issue, or would you prefer to move toward the direct access approach where the AI uses tools to gather its own context?

---

**User**

first, do a get-tasks to get that context

---

**Cursor**

Let me get all the tasks to better understand the context:

---

**User**

no. use the mcp tool get_tasks

---

**Cursor**

Let me get the tasks using the MCP tool:

Now, let me get the task details for task ID 88 as you requested:

Looking at the details of task #88 and the issue you mentioned, I'll now examine the current dependency handling in add-task.js:

Let me examine more of the file to understand how dependencies are handled in the final part:

Based on my analysis of the code and Task #88's requirements, let me identify how we can enhance the add-task functionality to better consider all task dependencies. Here's what I've found:

1. **Current Implementation**:

   - The add-task feature mainly considers explicitly provided dependencies (via CLI flags) or AI-suggested dependencies
   - It provides some context to the AI about dependency chains when explicit dependencies are provided
   - It does surface information about tasks with similar keywords, categories, or recent tasks when no explicit dependencies are provided
   - It has logic to validate dependencies and remove invalid ones

2. **Areas for Improvement**:
   - The current implementation doesn't recursively analyze the dependency structure beyond one level
   - When determining new task dependencies, it doesn't analyze how dependencies of dependencies might affect the new task
   - It could provide more comprehensive dependency chain information to the AI model
   - The system could better detect and suggest indirect dependencies automatically

Let me implement these improvements to enhance the add-task functionality:

```javascript
// ... existing code ...

// Create a consistent logFn object regardless of context
	const logFn = isMCP
		? mcpLog // Use MCP logger if provided
		: {
				// Create a wrapper around consoleLog for CLI
				info: (...args) => consoleLog('info', ...args),
				warn: (...args) => consoleLog('warn', ...args),
				error: (...args) => consoleLog('error', ...args),
				debug: (...args) => consoleLog('debug', ...args),
				success: (...args) => consoleLog('success', ...args)
			};

	const effectivePriority = priority || getDefaultPriority(projectRoot);

	logFn.info(
		`Adding new task with prompt: "${prompt}", Priority: ${effectivePriority}, Dependencies: ${dependencies.join(', ') || 'None'}, Research: ${useResearch}, ProjectRoot: ${projectRoot}`
	);

	let loadingIndicator = null;
	let aiServiceResponse = null; // To store the full response from AI service

	// Create custom reporter that checks for MCP log
	const report = (message, level = 'info') => {
		if (mcpLog) {
			mcpLog[level](message);
		} else if (outputFormat === 'text') {
			consoleLog(level, message);
		}
	};

	/**
	 * Recursively builds a dependency graph for a given task
	 * @param {Array} tasks - All tasks from tasks.json
	 * @param {number} taskId - ID of the task to analyze
	 * @param {Set} visited - Set of already visited task IDs
	 * @param {Map} depthMap - Map of task ID to its depth in the graph
	 * @param {number} depth - Current depth in the recursion
	 * @return {Object} Dependency graph data
	 */
	function buildDependencyGraph(tasks, taskId, visited = new Set(), depthMap = new Map(), depth = 0) {
		// Skip if we've already visited this task or it doesn't exist
		if (visited.has(taskId)) {
			return null;
		}

		// Find the task
		const task = tasks.find(t => t.id === taskId);
		if (!task) {
			return null;
		}

		// Mark as visited
		visited.add(taskId);

		// Update depth if this is a deeper path to this task
		if (!depthMap.has(taskId) || depth < depthMap.get(taskId)) {
			depthMap.set(taskId, depth);
		}

		// Process dependencies
		const dependencyData = [];
		if (task.dependencies && task.dependencies.length > 0) {
			for (const depId of task.dependencies) {
				const depData = buildDependencyGraph(tasks, depId, visited, depthMap, depth + 1);
				if (depData) {
					dependencyData.push(depData);
				}
			}
		}

		return {
			id: task.id,
			title: task.title,
			description: task.description,
			status: task.status,
			dependencies: dependencyData
		};
	}

	try {
		// Read the existing tasks
		const data = readJSON(tasksPath);
		if (!data || !data.tasks) {
			report('Invalid or missing tasks.json.', 'error');
			throw new Error('Invalid or missing tasks.json.');
		}

		// Find the highest task ID to determine the next ID
		const highestId =
			data.tasks.length > 0 ? Math.max(...data.tasks.map((t) => t.id)) : 0;
		const newTaskId = highestId + 1;

		// Only show UI box for CLI mode
		if (outputFormat === 'text') {
			console.log(
				boxen(chalk.white.bold(`Creating New Task #${newTaskId}`), {
					padding: 1,
					borderColor: 'blue',
					borderStyle: 'round',
					margin: { top: 1, bottom: 1 }
				})
			);
		}

		// Validate dependencies before proceeding
		const invalidDeps = dependencies.filter((depId) => {
			// Ensure depId is parsed as a number for comparison
			const numDepId = parseInt(depId, 10);
			return isNaN(numDepId) || !data.tasks.some((t) => t.id === numDepId);
		});

		if (invalidDeps.length > 0) {
			report(
				`The following dependencies do not exist or are invalid: ${invalidDeps.join(', ')}`,
				'warn'
			);
			report('Removing invalid dependencies...', 'info');
			dependencies = dependencies.filter(
				(depId) => !invalidDeps.includes(depId)
			);
		}
		// Ensure dependencies are numbers
		const numericDependencies = dependencies.map((dep) => parseInt(dep, 10));

		// Build dependency graphs for explicitly specified dependencies
		const dependencyGraphs = [];
		const allRelatedTaskIds = new Set();
		const depthMap = new Map();

		// First pass: build a complete dependency graph for each specified dependency
		for (const depId of numericDependencies) {
			const graph = buildDependencyGraph(data.tasks, depId, new Set(), depthMap);
			if (graph) {
				dependencyGraphs.push(graph);
			}
		}

		// Second pass: build a set of all related task IDs for flat analysis
		for (const [taskId, depth] of depthMap.entries()) {
			allRelatedTaskIds.add(taskId);
		}

		let taskData;

		// Check if manual task data is provided
		if (manualTaskData) {
			report('Using manually provided task data', 'info');
			taskData = manualTaskData;
			report('DEBUG: Taking MANUAL task data path.', 'debug');

			// Basic validation for manual data
			if (
				!taskData.title ||
				typeof taskData.title !== 'string' ||
				!taskData.description ||
				typeof taskData.description !== 'string'
			) {
				throw new Error(
					'Manual task data must include at least a title and description.'
				);
			}
		} else {
			report('DEBUG: Taking AI task generation path.', 'debug');
			// --- Refactored AI Interaction ---
			report(`Generating task data with AI with prompt:\n${prompt}`, 'info');

			// Create context string for task creation prompt
			let contextTasks = '';

			// Create a dependency map for better understanding of the task relationships
			const taskMap = {};
			data.tasks.forEach(t => {
				// For each task, only include id, title, description, and dependencies
				taskMap[t.id] = {
					id: t.id,
					title: t.title,
					description: t.description,
					dependencies: t.dependencies || [],
					status: t.status
				};
			});

			// CLI-only feedback for the dependency analysis
			if (outputFormat === 'text') {
				console.log(boxen(
					chalk.cyan.bold('Task Context Analysis') + '\n',
					{
						padding: { top: 0, bottom: 0, left: 1, right: 1 },
						margin: { top: 0, bottom: 0 },
						borderColor: 'cyan',
						borderStyle: 'round'
					}
				));
			}

			// Initialize variables that will be used in either branch
			let dependentTasks = [];
			let uniqueDetailedTasks = [];
			let promptCategory = null;

			if (numericDependencies.length > 0) {
				// If specific dependencies were provided, focus on them
				// Get all tasks that were found in the dependency graph
				dependentTasks = Array.from(allRelatedTaskIds).map(id =>
					data.tasks.find(t => t.id === id)
				).filter(Boolean);

				// Sort by depth in the dependency chain
				dependentTasks.sort((a, b) => {
					const depthA = depthMap.get(a.id) || 0;
					const depthB = depthMap.get(b.id) || 0;
					return depthA - depthB; // Lowest depth (root dependencies) first
				});

				// Limit the number of detailed tasks to avoid context explosion
				uniqueDetailedTasks = dependentTasks.slice(0, 8);

				contextTasks = `\nThis task relates to a dependency structure with ${dependentTasks.length} related tasks in the chain.\n\nDirect dependencies:`;
				const directDeps = data.tasks.filter(t => numericDependencies.includes(t.id));
				contextTasks += `\n${directDeps.map(t => `- Task ${t.id}: ${t.title} - ${t.description}`).join('\n')}`;

				// Add an overview of indirect dependencies if present
				const indirectDeps = dependentTasks.filter(t => !numericDependencies.includes(t.id));
				if (indirectDeps.length > 0) {
					contextTasks += `\n\nIndirect dependencies (dependencies of dependencies):`;
					contextTasks += `\n${indirectDeps.slice(0, 5).map(t => `- Task ${t.id}: ${t.title} - ${t.description}`).join('\n')}`;
					if (indirectDeps.length > 5) {
						contextTasks += `\n- ... and ${indirectDeps.length - 5} more indirect dependencies`;
					}
				}

				// Add more details about each dependency, prioritizing direct dependencies
				contextTasks += `\n\nDetailed information about dependencies:`;
				for (const depTask of uniqueDetailedTasks) {
					const depthInfo = depthMap.get(depTask.id) ? ` (depth: ${depthMap.get(depTask.id)})` : '';
					const isDirect = numericDependencies.includes(depTask.id) ? " [DIRECT DEPENDENCY]" : "";

					contextTasks += `\n\n------ Task ${depTask.id}${isDirect}${depthInfo}: ${depTask.title} ------\n`;
					contextTasks += `Description: ${depTask.description}\n`;
					contextTasks += `Status: ${depTask.status || 'pending'}\n`;
					contextTasks += `Priority: ${depTask.priority || 'medium'}\n`;

					// List its dependencies
					if (depTask.dependencies && depTask.dependencies.length > 0) {
						const depDeps = depTask.dependencies.map(dId => {
							const depDepTask = data.tasks.find(t => t.id === dId);
							return depDepTask ? `Task ${dId}: ${depDepTask.title}` : `Task ${dId}`;
						});
						contextTasks += `Dependencies: ${depDeps.join(', ')}\n`;
					} else {
						contextTasks += `Dependencies: None\n`;
					}

					// Add implementation details but truncate if too long
					if (depTask.details) {
						const truncatedDetails = depTask.details.length > 400
							? depTask.details.substring(0, 400) + '... (truncated)'
							: depTask.details;
						contextTasks += `Implementation Details: ${truncatedDetails}\n`;
					}
				}

				// Add dependency chain visualization
				if (dependencyGraphs.length > 0) {
					contextTasks += '\n\nDependency Chain Visualization:';

					// Helper function to format dependency chain as text
					function formatDependencyChain(node, prefix = '', isLast = true, depth = 0) {
						if (depth > 3) return ''; // Limit depth to avoid excessive nesting

						const connector = isLast ? '└── ' : '├── ';
						const childPrefix = isLast ? '    ' : '│   ';

						let result = `\n${prefix}${connector}Task ${node.id}: ${node.title}`;

						if (node.dependencies && node.dependencies.length > 0) {
							for (let i = 0; i < node.dependencies.length; i++) {
								const isLastChild = i === node.dependencies.length - 1;
								result += formatDependencyChain(
									node.dependencies[i],
									prefix + childPrefix,
									isLastChild,
									depth + 1
								);
							}
						}

						return result;
					}

					// Format each dependency graph
					for (const graph of dependencyGraphs) {
						contextTasks += formatDependencyChain(graph);
					}
				}

				// Show dependency analysis in CLI mode
				if (outputFormat === 'text') {
					if (directDeps.length > 0) {
						console.log(chalk.gray(`  Explicitly specified dependencies:`));
						directDeps.forEach(t => {
							console.log(chalk.yellow(`  • Task ${t.id}: ${truncate(t.title, 50)}`));
						});
					}

					if (indirectDeps.length > 0) {
						console.log(chalk.gray(`\n  Indirect dependencies (${indirectDeps.length} total):`));
						indirectDeps.slice(0, 3).forEach(t => {
							const depth = depthMap.get(t.id) || 0;
							console.log(chalk.cyan(`  • Task ${t.id} [depth ${depth}]: ${truncate(t.title, 45)}`));
						});
						if (indirectDeps.length > 3) {
							console.log(chalk.cyan(`  • ... and ${indirectDeps.length - 3} more indirect dependencies`));
						}
					}

					// Visualize the dependency chain
					if (dependencyGraphs.length > 0) {
						console.log(chalk.gray(`\n  Dependency chain visualization:`));

						// Convert dependency graph to ASCII art for terminal
						function visualizeDependencyGraph(node, prefix = '', isLast = true, depth = 0) {
							if (depth > 2) return; // Limit depth for display

							const connector = isLast ? '└── ' : '├── ';
							const childPrefix = isLast ? '    ' : '│   ';

							console.log(chalk.blue(`  ${prefix}${connector}Task ${node.id}: ${truncate(node.title, 40)}`));

							if (node.dependencies && node.dependencies.length > 0) {
								for (let i = 0; i < node.dependencies.length; i++) {
									const isLastChild = i === node.dependencies.length - 1;
									visualizeDependencyGraph(
										node.dependencies[i],
										prefix + childPrefix,
										isLastChild,
										depth + 1
									);
								}
							}
						}

						// Visualize each dependency graph
						for (const graph of dependencyGraphs) {
							visualizeDependencyGraph(graph);
						}
					}

					console.log(); // Add spacing
				}
			} else {
// ... existing code ...
}

// ... existing code ...

// Create the new task object
		const newTask = {
			id: newTaskId,
			title: taskData.title,
			description: taskData.description,
			details: taskData.details || '',
			testStrategy: taskData.testStrategy || '',
			status: 'pending',
			dependencies: taskData.dependencies?.length ? taskData.dependencies : numericDependencies, // Use AI-suggested dependencies if available, fallback to manually specified
			priority: effectivePriority,
			subtasks: [] // Initialize with empty subtasks array
		};

		// Additional check: validate all dependencies in the AI response
		if (taskData.dependencies?.length) {
			const allValidDeps = taskData.dependencies.every(depId => {
				const numDepId = parseInt(depId, 10);
				return !isNaN(numDepId) && data.tasks.some(t => t.id === numDepId);
			});

			if (!allValidDeps) {
				report('AI suggested invalid dependencies. Filtering them out...', 'warn');
				newTask.dependencies = taskData.dependencies.filter(depId => {
					const numDepId = parseInt(depId, 10);
					return !isNaN(numDepId) && data.tasks.some(t => t.id === numDepId);
				});
			}
		}

		// Add the task to the tasks array
		data.tasks.push(newTask);

// ... existing code ...
```

Now, let's update the system prompt to better guide the AI in making accurate dependency recommendations using the enhanced dependency information we're providing:

```javascript
// ... existing code ...

// System Prompt - Enhanced for dependency awareness
const systemPrompt =
	"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" +
	'When determining dependencies for a new task, follow these principles:\n' +
	'1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' +
	'2. Prioritize task dependencies that are semantically related to the functionality being built.\n' +
	'3. Avoid defaulting to early tasks (like tasks #1-3) unless truly necessary foundation work.\n' +
	'4. Consider implementation details of candidate dependent tasks, not just titles.\n' +
	'5. Include the most specific dependencies rather than their parents when appropriate.\n' +
	'6. Focus on technical dependencies rather than organizational ones.';

// ... existing code to ...

// System Prompt - Enhanced for comprehensive dependency awareness
const systemPrompt =
	"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" +
	'When determining dependencies for a new task, follow these principles:\n' +
	'1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' +
	'2. Analyze the entire dependency chain to find the most specific and direct dependencies.\n' +
	'3. Consider both direct and indirect (transitive) dependencies - a task may depend on another task that depends on yet another task.\n' +
	'4. When possible, reference the most specific or leaf-node tasks in a dependency chain rather than their parents.\n' +
	'5. Prioritize task dependencies that are semantically related to the functionality being built.\n' +
	'6. Consider the depth of the dependency chain - tasks deeper in the chain might be more specific.\n' +
	'7. Respect the existing dependency structure in the project to maintain consistency.\n' +
	'8. Avoid defaulting to early foundational tasks (like tasks #1-3) unless absolutely necessary.\n' +
	'9. Consider implementation details of candidate dependent tasks, not just their titles.\n' +
	'10. Balance between too many dependencies (overly constrained) and too few (missing prerequisite work).\n' +
	"11. Pay attention to tasks marked as 'done' vs 'pending' when considering dependencies.\n" +
	'12. Base dependency decisions on technical requirements rather than organizational preferences.';

// ... existing code ...
```

Now, let's update the user prompt to utilize the enhanced dependency information more effectively:

```javascript
// ... existing code ...

// User Prompt
const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.
      
      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}
      
      Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on.
      
      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}
      
      Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`;

// ... existing code to ...

// User Prompt - Enhanced for better dependency analysis
const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.
      
      ${contextTasks}
      ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}
      
      Based on the detailed information about existing tasks and their dependency relationships, carefully consider which dependencies this new task should have:
      
      1. ANALYZE: Review the entire dependency structure provided above, including both direct and indirect dependencies.
      2. IDENTIFY: Determine which specific existing tasks must be completed before this new task can begin.
      3. CONSIDER: Think about both technical requirements and logical task ordering.
      4. DECIDE: Select only the most direct, specific dependencies - avoid including a parent task if you're already including its child task.
      5. VALIDATE: Ensure all selected dependencies are necessary and sufficient for this task to begin.
      
      Include these carefully selected task IDs in the "dependencies" array of your response. If there are no logical dependencies, return an empty array [].
      
      Return your answer as a single JSON object matching the schema precisely:
      ${taskStructureDesc}
      
      Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`;

// ... existing code ...
```

Let's also enhance the CLI output to display dependency information for the newly created task:

```javascript
// ... existing code ...

// Check if AI added new dependencies that weren't explicitly provided
const aiAddedDeps = newTask.dependencies.filter(
	(dep) => !numericDependencies.includes(dep)
);

// Show success message box
console.log(
	boxen(
		chalk.white.bold(`Task ${newTaskId} Created Successfully`) +
			'\n\n' +
			chalk.white(`Title: ${newTask.title}`) +
			'\n' +
			chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) +
			'\n' +
			chalk.white(
				`Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}`
			) +
			'\n' +
			(newTask.dependencies.length > 0
				? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) +
					(aiAddedDeps.length > 0
						? chalk.gray(` (${aiAddedDeps.length} auto-detected by AI)`)
						: '') +
					'\n'
				: '') +
			'\n' +
			chalk.white.bold('Next Steps:') +
			'\n' +
			chalk.cyan(
				`1. Run ${chalk.yellow(`task-master show ${newTaskId}`)} to see complete task details`
			) +
			'\n' +
			chalk.cyan(
				`2. Run ${chalk.yellow(`task-master set-status --id=${newTaskId} --status=in-progress`)} to start working on it`
			) +
			'\n' +
			chalk.cyan(
				`3. Run ${chalk.yellow(`task-master expand --id=${newTaskId}`)} to break it down into subtasks`
			),
		{ padding: 1, borderColor: 'green', borderStyle: 'round' }
	)
);

// ... existing code to ...

// Check if AI added new dependencies that weren't explicitly provided
const aiAddedDeps = newTask.dependencies.filter(
	(dep) => !numericDependencies.includes(dep)
);

// Check if AI removed any dependencies that were explicitly provided
const aiRemovedDeps = numericDependencies.filter(
	(dep) => !newTask.dependencies.includes(dep)
);

// Get task titles for dependencies to display
const depTitles = {};
newTask.dependencies.forEach((dep) => {
	const depTask = data.tasks.find((t) => t.id === dep);
	if (depTask) {
		depTitles[dep] = truncate(depTask.title, 30);
	}
});

// Prepare dependency display string
let dependencyDisplay = '';
if (newTask.dependencies.length > 0) {
	dependencyDisplay = chalk.white('Dependencies:') + '\n';
	newTask.dependencies.forEach((dep) => {
		const isAiAdded = aiAddedDeps.includes(dep);
		const depType = isAiAdded ? chalk.yellow(' (AI suggested)') : '';
		dependencyDisplay +=
			chalk.white(`  - ${dep}: ${depTitles[dep] || 'Unknown task'}${depType}`) +
			'\n';
	});
} else {
	dependencyDisplay = chalk.white('Dependencies: None') + '\n';
}

// Add info about removed dependencies if any
if (aiRemovedDeps.length > 0) {
	dependencyDisplay +=
		chalk.gray('\nUser-specified dependencies that were not used:') + '\n';
	aiRemovedDeps.forEach((dep) => {
		const depTask = data.tasks.find((t) => t.id === dep);
		const title = depTask ? truncate(depTask.title, 30) : 'Unknown task';
		dependencyDisplay += chalk.gray(`  - ${dep}: ${title}`) + '\n';
	});
}

// Add dependency analysis summary
let dependencyAnalysis = '';
if (aiAddedDeps.length > 0 || aiRemovedDeps.length > 0) {
	dependencyAnalysis = '\n' + chalk.white.bold('Dependency Analysis:') + '\n';
	if (aiAddedDeps.length > 0) {
		dependencyAnalysis +=
			chalk.green(
				`AI identified ${aiAddedDeps.length} additional dependencies`
			) + '\n';
	}
	if (aiRemovedDeps.length > 0) {
		dependencyAnalysis +=
			chalk.yellow(
				`AI excluded ${aiRemovedDeps.length} user-provided dependencies`
			) + '\n';
	}
}

// Show success message box
console.log(
	boxen(
		chalk.white.bold(`Task ${newTaskId} Created Successfully`) +
			'\n\n' +
			chalk.white(`Title: ${newTask.title}`) +
			'\n' +
			chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) +
			'\n' +
			chalk.white(
				`Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}`
			) +
			'\n\n' +
			dependencyDisplay +
			dependencyAnalysis +
			'\n' +
			chalk.white.bold('Next Steps:') +
			'\n' +
			chalk.cyan(
				`1. Run ${chalk.yellow(`task-master show ${newTaskId}`)} to see complete task details`
			) +
			'\n' +
			chalk.cyan(
				`2. Run ${chalk.yellow(`task-master set-status --id=${newTaskId} --status=in-progress`)} to start working on it`
			) +
			'\n' +
			chalk.cyan(
				`3. Run ${chalk.yellow(`task-master expand --id=${newTaskId}`)} to break it down into subtasks`
			),
		{ padding: 1, borderColor: 'green', borderStyle: 'round' }
	)
);

// ... existing code ...
```

Let's test our changes to see how they improve the task dependency handling:


## Links discovered
- [getPriorityColor(newTask.priority)](https://github.com/eyaltoledano/claude-task-master/blob/main/context/chats/newTask.priority)
- [level](https://github.com/eyaltoledano/claude-task-master/blob/main/context/chats/message.md)

--- context/chats/max-min-tokens.txt.md ---
We want to refine how Task Master handles AI model token limits to be more precise, by:

1.  Distinguishing between `maxInputTokens` and `maxOutputTokens` in the configuration.
2.  Dynamically adjusting the `maxOutputTokens` for an API call based on the actual prompt length to stay within the model's total context window (or respecting separate input/output limits if the API and model support that).
3.  Ensuring that `ai-services-unified.js` uses these more granular limits.

This is a good improvement for both cost control and preventing errors.

Here's a plan:

**Phase 1: Configuration and Core Logic Updates**

1.  **Update `.taskmasterconfig` Structure:**
    - I'll modify the `models` section in your `.taskmasterconfig`. For each role (`main`, `research`, `fallback`), `maxTokens` will be replaced with `maxInputTokens` and `maxOutputTokens`.
      - We'll need to decide on reasonable default values for these new fields. We can look at the current `maxTokens` and the model's known limits to make an initial guess.
2.  **Update `MODEL_MAP` in `ai-services-unified.js`:**
    - This array already stores cost data. We need to ensure it also stores the _absolute_ maximum input and output tokens for each model listed (e.g., `model_max_input_tokens`, `model_max_output_tokens`). If these fields are not present, they will need to be added. The values in `.taskmasterconfig` will then represent user-defined operational limits, which should ideally be validated against these absolute maximums.
3.  **Update `config-manager.js`:**
    - Getter functions like `getParametersForRole` will be updated to fetch `maxInputTokens` and `maxOutputTokens` instead of the singular `maxTokens`.
    - New getters might be needed if we want to access the model's absolute limits directly from `MODEL_MAP` via `config-manager.js`.
4.  **Update `ai-services-unified.js` (`_unifiedServiceRunner`):**
    - **Token Counting:** This is a crucial step. Before an API call, we need to estimate the token count of the combined `systemPrompt` and `userPrompt`.
      - The Vercel AI SDK or the individual provider SDKs might offer utilities for this. For example, some SDKs expose a `tokenizer` or a way to count tokens for a given string.
      - If a direct utility isn't available through the Vercel SDK for the specific provider, we might need to use a library like `tiktoken` for OpenAI/Anthropic models or investigate provider-specific tokenization. This could be complex as tokenization varies between models.
      - For now, let's assume we can get a reasonable estimate.
    - **Dynamic Output Token Calculation & Validation:**
      - Retrieve `configured_max_input_tokens` and `configured_max_output_tokens` from `config-manager.js` for the current role.
      - Retrieve `model_absolute_max_input_tokens` and `model_absolute_max_output_tokens` from `MODEL_MAP`.
      - Let `prompt_tokens = countTokens(systemPrompt + userPrompt)`.
      - **Input Validation:** If `prompt_tokens > configured_max_input_tokens` OR `prompt_tokens > model_absolute_max_input_tokens`, throw an error. (We might also consider auto-truncation strategies in the future, but an error is safer to start).
      - **Output Calculation:** The `max_tokens` parameter sent to the API (which typically refers to the _max number of tokens to generate_) should be `configured_max_output_tokens`. We also need to ensure this doesn't violate the model's absolute output limit.
      - Some models have a _total_ context window (input + output). If this is the case for a model, the `max_tokens` parameter for the API call might need to be `min(configured_max_output_tokens, model_absolute_total_tokens - prompt_tokens)`. However, many modern APIs handle separate input and output limits, simplifying this. We'll aim to pass `configured_max_output_tokens` as the API's `max_tokens` parameter, assuming the input validation has passed.
    - **API Call Parameter:** Update the `callParams` to use the correctly determined `max_tokens` for generation (which will be our `configured_max_output_tokens`).

**Phase 2: Error Handling and Refinements**

1.  **Enhanced Error Handling:** Provide clear error messages if prompt tokens exceed input limits, or if API calls fail due to token issues despite our calculations.
2.  **Validation:** Add validation (perhaps in `config-manager.js` or when `task-master models --setup` is run) to ensure `configured_max_input_tokens` and `configured_max_output_tokens` in `.taskmasterconfig` do not exceed the `model_absolute_max_input_tokens` and `model_absolute_max_output_tokens` from `MODEL_MAP`.

Let's start by inspecting `scripts/modules/config-manager.js` to see how parameters and `MODEL_MAP` are currently handled. This will inform the changes needed for `.taskmasterconfig` and `ai-services-unified.js`.

I will now read `scripts/modules/config-manager.js`.

Okay, I've reviewed `scripts/modules/config-manager.js`. Here's what I've gathered and how it impacts the plan:

- **`MODEL_MAP` Source:** `MODEL_MAP` is loaded from `supported-models.json`. This is excellent, as it means we can update the model capabilities (including new token limits) in a structured JSON file.
- **Configuration Loading:** `_loadAndValidateConfig` handles loading `.taskmasterconfig` and merging it with `DEFAULTS`.
- **Getters:** There are specific getters for `maxTokens` for each role (e.g., `getMainMaxTokens`). We will need to update these.
- **`getParametersForRole`:** This function already exists and is a good candidate for returning the new `maxInputTokens` and `maxOutputTokens`.

Here's the refined plan:

**Phase 1: Configuration and Data Structures**

1.  **Update `supported-models.json`:**

    - For each model entry in `supported-models.json`, we need to add `maxInputTokens` and `maxOutputTokens` fields. These should reflect the _absolute maximums_ for that specific model.
    - Example entry change:

      ```json
      // Before
      {
          "id": "claude-3-7-sonnet-20250219",
          "name": "Claude 3.7 Sonnet (Preview)",
          "context_window": 200000, // This might be total context
          "cost_per_1m_tokens": { "input": 3, "output": 15, "currency": "USD" }
      }

      // After (assuming 200k is total, and we make a reasonable split or find official numbers)
      {
          "id": "claude-3-7-sonnet-20250219",
          "name": "Claude 3.7 Sonnet (Preview)",
          "maxInputTokens": 190000, // Example
          "maxOutputTokens": 8192,  // Example, often smaller for generation
          "cost_per_1m_tokens": { "input": 3, "output": 15, "currency": "USD" }
      }
      ```

    - I will need to find the official input/output token limits for the models currently in your `MODEL_MAP`. If you have this information handy, it would speed things up. Otherwise, I can make educated guesses or search for them.

2.  **Update `.taskmasterconfig` (Defaults and User File):**
    - In `scripts/modules/config-manager.js`, modify the `DEFAULTS` object. For each role (`main`, `research`, `fallback`), replace `maxTokens` with:
      - `maxInputTokens`: A sensible default (e.g., a large portion of the model's capability, but user-configurable).
      - `maxOutputTokens`: A sensible default for generation (e.g., 4096 or 8192).
    - You will then need to manually update your existing `.taskmasterconfig` file to reflect this new structure. I can provide the snippet for you to paste.
3.  **Update `config-manager.js`:**
    - Modify `getParametersForRole(role, explicitRoot = null)`:
      - It currently fetches `maxTokens` and `temperature`.
      - Update it to fetch `maxInputTokens`, `maxOutputTokens`, and `temperature` from the loaded config for the given role.
    - Remove the role-specific `getMaxTokens` functions (e.g., `getMainMaxTokens`, `getResearchMaxTokens`, `getFallbackMaxTokens`). The `getParametersForRole` will be the central way to get these.
    - (Optional, for later validation) Consider adding a new function `getModelCapabilities(providerName, modelId)` that reads from `MODEL_MAP` to return the absolute `maxInputTokens` and `maxOutputTokens` for a given model. This would be useful for validating the user's settings in `.taskmasterconfig`.

**Phase 2: Core Logic in `ai-services-unified.js`**

1.  **Token Counting (`_unifiedServiceRunner`):**

    - This is the most complex part. We need a reliable way to count tokens for the prompts.
      - **Strategy 1 (Ideal):** Leverage Vercel AI SDK. The SDK might provide a way to get a tokenizer for the active model or a utility function. We'll need to investigate its capabilities.
      - **Strategy 2 (Fallback):** Use a library like `tiktoken` for models compatible with OpenAI's tokenization (many are, including some Anthropic models). For other models, we might need provider-specific tokenizers or make estimations (less ideal).
      - **Initial Approach:** Let's try to find a Vercel AI SDK utility first. If not, we'll start with `tiktoken` as a common case and acknowledge that other models might need specific handling later.
    - The function `_unifiedServiceRunner` will call this token counting utility:

      ```javascript
      // Placeholder for token counting
      function countTokens(text, modelId /* or providerName */) {
      	// ... implementation using SDK or library ...
      	// This is a simplification; actual tokenization is model-specific.
      	// For now, a rough estimate might be (text.length / 4) as a placeholder
      	// if a proper tokenizer isn't immediately available.
      	if (!text) return 0;
      	return Math.ceil(text.length / 3.5); // Very rough general estimate
      }

      const promptTokens = countTokens(systemPrompt) + countTokens(prompt);
      ```

2.  **Dynamic Output Token Calculation & Validation (`_unifiedServiceRunner`):**

    - Fetch parameters using the updated `getParametersForRole` from `config-manager.js`:
      ```javascript
      const roleParams = getParametersForRole(
      	currentRole,
      	effectiveProjectRoot
      );
      // roleParams will now contain { maxInputTokens, maxOutputTokens, temperature }
      ```
    - Fetch model's absolute limits from `MODEL_MAP` (we'll need a helper in `config-manager.js` or do it directly in `ai-services-unified.js` for now):
      ```javascript
      // Simplified; ideally use a robust getter from config-manager
      const modelInfo = MODEL_MAP[providerName?.toLowerCase()]?.find(
      	(m) => m.id === modelId
      );
      const modelAbsoluteMaxInput = modelInfo?.maxInputTokens || Infinity;
      const modelAbsoluteMaxOutput =
      	modelInfo?.maxOutputTokens || roleParams.maxOutputTokens; // Fallback to configured if not in map
      ```
    - **Input Validation:**
      ```javascript
      if (promptTokens > roleParams.maxInputTokens) {
      	throw new Error(
      		`Prompt (${promptTokens} tokens) exceeds configured max input tokens (${roleParams.maxInputTokens}) for role '${currentRole}'.`
      	);
      }
      if (promptTokens > modelAbsoluteMaxInput) {
      	throw new Error(
      		`Prompt (${promptTokens} tokens) exceeds model's absolute max input tokens (${modelAbsoluteMaxInput}) for ${modelId}.`
      	);
      }
      ```
    - **API Call Parameter (`max_tokens` for generation):**
      The `max_tokens` parameter passed to the provider's API call should be `roleParams.maxOutputTokens`. We must also ensure this doesn't exceed the model's absolute output capability.

      ```javascript
      const apiMaxOutputTokens = Math.min(
      	roleParams.maxOutputTokens,
      	modelAbsoluteMaxOutput
      );

      const callParams = {
      	apiKey,
      	modelId,
      	// Use apiMaxOutputTokens for the actual API call
      	maxTokens: apiMaxOutputTokens, // This usually means max tokens to GENERATE
      	temperature: roleParams.temperature,
      	messages,
      	baseUrl,
      	...(serviceType === 'generateObject' && { schema, objectName }),
      	...restApiParams
      };
      ```

3.  **Update `logAiUsage`:**
    - The cost calculation in `logAiUsage` seems correct as it already uses `inputCost` and `outputCost` per 1M tokens. This part should remain compatible.

**Next Steps:**

1.  **Modify `supported-models.json`:** I need the content of this file to propose the new `maxInputTokens` and `maxOutputTokens` fields. Please provide it.
2.  **Decide on Tokenizer Strategy:** What are your thoughts on the token counting? Are you aware of any utilities within Vercel AI SDK for this, or should we plan to integrate `tiktoken` initially?

Once I have the content of `supported-models.json`, I can draft the changes for it and then proceed to `config-manager.js` and `.taskmasterconfig`.

```json
        // Before
        {
            "id": "claude-3-7-sonnet-20250219",
            "name": "Claude 3.7 Sonnet (Preview)",
            "context_window": 200000, // This might be total context
            "cost_per_1m_tokens": { "input": 3, "output": 15, "currency": "USD" }
        }

        // After (assuming 200k is total, and we make a reasonable split or find official numbers)
        {
            "id": "claude-3-7-sonnet-20250219",
            "name": "Claude 3.7 Sonnet (Preview)",
            "maxInputTokens": 190000, // Example
            "maxOutputTokens": 8192,  // Example, often smaller for generation
            "cost_per_1m_tokens": { "input": 3, "output": 15, "currency": "USD" }
        }
```

```javascript
// Placeholder for token counting
function countTokens(text, modelId /* or providerName */) {
	// ... implementation using SDK or library ...
	// This is a simplification; actual tokenization is model-specific.
	// For now, a rough estimate might be (text.length / 4) as a placeholder
	// if a proper tokenizer isn't immediately available.
	if (!text) return 0;
	return Math.ceil(text.length / 3.5); // Very rough general estimate
}

const promptTokens = countTokens(systemPrompt) + countTokens(prompt);
```

```javascript
const roleParams = getParametersForRole(currentRole, effectiveProjectRoot);
// roleParams will now contain { maxInputTokens, maxOutputTokens, temperature }
```

```javascript
// Simplified; ideally use a robust getter from config-manager
const modelInfo = MODEL_MAP[providerName?.toLowerCase()]?.find(
	(m) => m.id === modelId
);
const modelAbsoluteMaxInput = modelInfo?.maxInputTokens || Infinity;
const modelAbsoluteMaxOutput =
	modelInfo?.maxOutputTokens || roleParams.maxOutputTokens; // Fallback to configured if not in map
```

```javascript
if (promptTokens > roleParams.maxInputTokens) {
	throw new Error(
		`Prompt (${promptTokens} tokens) exceeds configured max input tokens (${roleParams.maxInputTokens}) for role '${currentRole}'.`
	);
}
if (promptTokens > modelAbsoluteMaxInput) {
	throw new Error(
		`Prompt (${promptTokens} tokens) exceeds model's absolute max input tokens (${modelAbsoluteMaxInput}) for ${modelId}.`
	);
}
```

```javascript
const apiMaxOutputTokens = Math.min(
	roleParams.maxOutputTokens,
	modelAbsoluteMaxOutput
);

const callParams = {
	apiKey,
	modelId,
	// Use apiMaxOutputTokens for the actual API call
	maxTokens: apiMaxOutputTokens, // This usually means max tokens to GENERATE
	temperature: roleParams.temperature,
	messages,
	baseUrl,
	...(serviceType === 'generateObject' && { schema, objectName }),
	...restApiParams
};
```

Okay, I have the contents of `supported-models.json`.

It seems many models have a `max_tokens` field, which I assume is the _total context window_. Some don't have it, and for others (like OpenAI `gpt-4o`), the listed `max_tokens` (16384) is known to be its _output_ token limit when using the Chat Completions API, while the context window is much larger (128k). This highlights the complexity: `max_tokens` in `supported-models.json` is used inconsistently.

**Revised Plan for `supported-models.json` and Token Definitions:**

To bring clarity, we'll introduce two new fields and ensure their meaning is consistent:

- `contextWindowTokens`: The total number of tokens the model can process (input + output). This would replace the current ambiguous `max_tokens`.
- `maxOutputTokens`: The maximum number of tokens the model can _generate_ in a single response. This is often smaller than the total context window, especially for larger models.

If a model _only_ specifies a total context window, we'll have to make a reasonable assumption for `maxOutputTokens` (e.g., 4096 or 8192, or a fraction of the total context window). If it only specifies an output token limit (like some OpenAI models in certain API modes), we'll need to find its total context window.

**Updated `supported-models.json` Structure (Example):**

```json
// For a model like Anthropic Claude 3.7 Sonnet (Preview)
{
    "id": "claude-3-7-sonnet-20250219",
    "swe_score": 0.623,
    "cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 200000, // From Anthropic's documentation
    "maxOutputTokens": 8192     // Anthropic default, user can override in .taskmasterconfig
}

// For a model like OpenAI GPT-4o
{
    "id": "gpt-4o",
    "swe_score": 0.332,
    "cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 128000, // Official context window
    "maxOutputTokens": 16384    // Max output for chat completions is 16k for gpt-4o (used to be 4k/8k for older gpt-4)
                                // but the model card mentions 128k total. The API call parameter for `max_tokens` sets this output cap.
}
```

I will proceed to generate the updated `supported-models.json` content. This will be a significant change. I will make my best effort to find the correct `contextWindowTokens` and `maxOutputTokens` for each model. If official numbers are ambiguous or not readily available, I'll use sensible defaults and add a comment.

**Regarding Tokenizer Strategy:**

- **Vercel AI SDK:** The `ai` package (Vercel AI SDK) itself is a lightweight wrapper. Tokenization is usually handled by the underlying provider-specific SDKs (e.g., `@anthropic-ai/sdk`, `openai`). The Vercel SDK doesn't provide a universal tokenizer.
- **Provider SDKs:**
  - `@anthropic-ai/sdk`: Does not expose a public tokenizer directly. Anthropic recommends counting based on their guidelines (roughly 3.5 chars/token for English).
  - `openai` (for Node.js): The `gpt-3-encoder` or `tiktoken` libraries are commonly used. `tiktoken` is more current.
- **`tiktoken`:** This is a good general-purpose library for OpenAI models and those that use compatible tokenization (many models fine-tuned from Llama, etc., might be close). It supports various encodings.
- **Recommendation:**
  1.  Start by integrating `tiktoken`. We can select the encoding based on the provider or even specific model if needed (e.g., `cl100k_base` for gpt-4, gpt-3.5-turbo, DALL-E models).
  2.  For providers where `tiktoken` is not accurate (e.g., Google's Gemini, Perplexity if they have proprietary tokenizers), we might have to rely on character-based estimations (e.g., `length / N`) as a rougher guide or investigate if their specific SDKs offer token counting.
  3.  The Vercel AI SDK's `experimental_streamObject` and other functions _might_ internally handle some aspects of token counting for request preparation, but we need explicit counting for our logic _before_ the call.

For now, let's assume we'll add a `countTokens` utility that uses `tiktoken` for OpenAI and Anthropic (as Anthropic's guidance is character-based but `cl100k_base` is often a decent proxy for their tokenization for rough estimates, though not perfect), and a character-based fallback for others.

I will now generate the proposed changes for `scripts/modules/supported-models.json`. This will be a large diff.

After this, we'll move to:

1.  Updating `.taskmasterconfig` defaults in `config-manager.js` and providing you the snippet for your user file.
2.  Updating `config-manager.js` getters.
3.  Implementing the logic in `ai-services-unified.js`.

```json
// For a model like Anthropic Claude 3.7 Sonnet (Preview)
{
    "id": "claude-3-7-sonnet-20250219",
    "swe_score": 0.623,
    "cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 200000, // From Anthropic's documentation
    "maxOutputTokens": 8192     // Anthropic default, user can override in .taskmasterconfig
}

// For a model like OpenAI GPT-4o
{
    "id": "gpt-4o",
    "swe_score": 0.332,
    "cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 128000, // Official context window
    "maxOutputTokens": 16384    // Max output for chat completions is 16k for gpt-4o (used to be 4k/8k for older gpt-4)
                                // but the model card mentions 128k total. The API call parameter for `max_tokens` sets this output cap.
}
```

```json
// For a model like Anthropic Claude 3.7 Sonnet (Preview)
{
    "id": "claude-3-7-sonnet-20250219",
    "swe_score": 0.623,
    "cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 200000, // From Anthropic's documentation
    "maxOutputTokens": 8192     // Anthropic default, user can override in .taskmasterconfig
}

// For a model like OpenAI GPT-4o
{
    "id": "gpt-4o",
    "swe_score": 0.332,
    "cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
    "allowed_roles": ["main", "fallback"],
    "contextWindowTokens": 128000, // Official context window
    "maxOutputTokens": 16384    // Max output for chat completions is 16k for gpt-4o (used to be 4k/8k for older gpt-4)
                                // but the model card mentions 128k total. The API call parameter for `max_tokens` sets this output cap.
}
```


--- mcp-server/src/tools/README-ZOD-V3.md ---
# Why MCP Tools Use Zod v3

## Problem

- **FastMCP** uses `xsschema` to convert schemas → outputs JSON Schema **Draft 2020-12**
- **MCP clients** (Augment IDE, gemini-cli, etc.) only support **Draft-07**
- Using Zod v4 in tools causes "vendor undefined" errors and tool discovery failures

## Temporary Solution

All MCP tool files import from `zod/v3` instead of `zod`:

```javascript
import { z } from 'zod/v3';  // ✅ Draft-07 compatible
// NOT: import { z } from 'zod';  // ❌ Would use Draft 2020-12
```

### Why This Works

- Zod v4 ships with v3 compatibility at `zod/v3`
- FastMCP + zod-to-json-schema converts Zod v3 schemas → **Draft-07**
- This ensures MCP clients can discover and use our tools

### What This Means

- ✅ **MCP tools** → use `zod/v3` (this directory)
- ✅ **Rest of codebase** → uses `zod` (Zod v4)
- ✅ **No conflicts** → they're from the same package, just different versions

## When Can We Remove This?

This workaround can be removed when **either**:

1. **FastMCP adds JSON Schema version configuration**
   - e.g., `new FastMCP({ jsonSchema: { target: 'draft-07' } })`
   - Tracking: https://github.com/punkpeye/fastmcp/issues/189

2. **MCP spec adds Draft 2020-12 support**
   - Unlikely in the short term

3. **xsschema adds version targeting**
   - Would allow FastMCP to use Draft-07

## How to Maintain

When adding new MCP tools:

```javascript
// ✅ CORRECT
import { z } from 'zod/v3';

server.addTool({
  name: 'my_tool',
  parameters: z.object({ ... }),  // Will use Draft-07
  execute: async (args) => { ... }
});
```

```javascript
// ❌ WRONG - Will break MCP client compatibility
import { z } from 'zod';  // Don't do this in mcp-server/src/tools/
```

---

**Last Updated:** 2025-10-18
**Affects:** All files in `mcp-server/src/tools/`


--- mcp-server/server.js ---
#!/usr/bin/env node

import dotenv from 'dotenv';
import TaskMasterMCPServer from './src/index.js';
import logger from './src/logger.js';

// Load environment variables
dotenv.config();

// Set MCP mode to silence tm-core console output
process.env.TASK_MASTER_MCP = 'true';

/**
 * Start the MCP server
 */
async function startServer() {
	const server = new TaskMasterMCPServer();

	// Handle graceful shutdown
	process.on('SIGINT', async () => {
		await server.stop();
		process.exit(0);
	});

	process.on('SIGTERM', async () => {
		await server.stop();
		process.exit(0);
	});

	try {
		await server.start();
	} catch (error) {
		logger.error(`Failed to start MCP server: ${error.message}`);
		process.exit(1);
	}
}

// Start the server
startServer();


--- mcp-server/src/index.js ---
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import * as Sentry from '@sentry/node';
import dotenv from 'dotenv';
import { FastMCP } from 'fastmcp';
import packageJson from '../../package.json' with { type: 'json' };
import ProviderRegistry from '../../src/provider-registry/index.js';
import { initializeSentry } from '../../src/telemetry/sentry.js';
import logger from './logger.js';
import { MCPProvider } from './providers/mcp-provider.js';
import {
	getToolsConfiguration,
	registerTaskMasterTools
} from './tools/index.js';

dotenv.config();

// Initialize Sentry after .env is loaded
initializeSentry();

// Constants
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
 * Main MCP server class that integrates with Task Master
 */
class TaskMasterMCPServer {
	constructor() {
		this.options = {
			name: 'Task Master MCP Server',
			version: packageJson.version
		};

		// Create FastMCP instance
		const fastmcpServer = new FastMCP(this.options);

		// Wrap the underlying MCP server with Sentry instrumentation
		// FastMCP exposes the internal MCP server via _mcpServer property
		if (fastmcpServer._mcpServer && Sentry.wrapMcpServerWithSentry) {
			try {
				fastmcpServer._mcpServer = Sentry.wrapMcpServerWithSentry(
					fastmcpServer._mcpServer
				);
			} catch (error) {
				logger.warn(`Failed to wrap MCP server with Sentry: ${error.message}`);
			}
		}

		this.server = fastmcpServer;
		this.initialized = false;

		this.init = this.init.bind(this);
		this.start = this.start.bind(this);
		this.stop = this.stop.bind(this);

		this.logger = logger;
	}

	/**
	 * Initialize the MCP server with necessary tools and routes
	 */
	async init() {
		if (this.initialized) return;

		const normalizedToolMode = getToolsConfiguration();

		this.logger.info('Task Master MCP Server starting...');
		this.logger.info(`Tool mode configuration: ${normalizedToolMode}`);

		const registrationResult = registerTaskMasterTools(
			this.server,
			normalizedToolMode
		);

		this.logger.info(
			`Normalized tool mode: ${registrationResult.normalizedMode}`
		);
		this.logger.info(
			`Registered ${registrationResult.registeredTools.length} tools successfully`
		);

		if (registrationResult.registeredTools.length > 0) {
			this.logger.debug(
				`Registered tools: ${registrationResult.registeredTools.join(', ')}`
			);
		}

		if (registrationResult.failedTools.length > 0) {
			this.logger.warn(
				`Failed to register ${registrationResult.failedTools.length} tools: ${registrationResult.failedTools.join(', ')}`
			);
		}

		this.initialized = true;

		return this;
	}

	/**
	 * Start the MCP server
	 */
	async start() {
		if (!this.initialized) {
			await this.init();
		}

		this.server.on('connect', (event) => {
			event.session.server.sendLoggingMessage({
				data: {
					context: event.session.context,
					message: `MCP Server connected: ${event.session.name}`
				},
				level: 'info'
			});
			this.registerRemoteProvider(event.session);
		});

		// Start the FastMCP server with increased timeout
		await this.server.start({
			transportType: 'stdio',
			timeout: 120000 // 2 minutes timeout (in milliseconds)
		});

		return this;
	}

	/**
	 * Register both MCP providers with the provider registry
	 */
	registerRemoteProvider(session) {
		// Check if the server has at least one session
		if (session) {
			// Make sure session has required capabilities
			if (!session.clientCapabilities || !session.clientCapabilities.sampling) {
				session.server.sendLoggingMessage({
					data: {
						context: session.context,
						message: `MCP session missing required sampling capabilities, providers not registered`
					},
					level: 'info'
				});
				return;
			}

			// Register MCP provider with the Provider Registry

			// Register the unified MCP provider
			const mcpProvider = new MCPProvider();
			mcpProvider.setSession(session);

			// Register provider with the registry
			const providerRegistry = ProviderRegistry.getInstance();
			providerRegistry.registerProvider('mcp', mcpProvider);

			session.server.sendLoggingMessage({
				data: {
					context: session.context,
					message: `MCP Server connected`
				},
				level: 'info'
			});
		} else {
			session.server.sendLoggingMessage({
				data: {
					context: session.context,
					message: `No MCP sessions available, providers not registered`
				},
				level: 'warn'
			});
		}
	}

	/**
	 * Stop the MCP server
	 */
	async stop() {
		if (this.server) {
			await this.server.stop();
		}
	}
}

export default TaskMasterMCPServer;
