# MCP Tools Development

> Comprehensive guide for creating and modifying AIDB MCP tools with agent optimization

- Skill: `ai-debugger-inc/mcp-tools-development` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add ai-debugger-inc/mcp-tools-development`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ai-debugger-inc/mcp-tools-development/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: ai-debugger-inc (https://skillmd.com/u/ai-debugger-inc)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ai-debugger-inc/mcp-tools-development

---


# MCP Tools Development Skill

This skill guides you through creating and modifying MCP tools for the AI Debugger (AIDB). MCP tools are the primary interface between AI agents and the debugging system - they must be fast, accurate, and clear.

## Core Philosophy: Agent Optimization

MCP tools are **user-facing products**. Every response is read by an AI agent with limited context. Your goal:

1. **Accuracy**: Responses must contain correct information (line numbers, values, state)
1. **Clarity**: Summaries must be clear and actionable, not verbose
1. **Speed**: Operations must be fast (agents iterate rapidly)
1. **No Junk**: No unnecessary fields, no bloated payloads, no redundant data

**Context windows are sacred** - every token matters.

## Quick Start

### When to Use This Skill

Invoke this skill when:

- Creating a new MCP tool (e.g., `aidb.watch` for watchpoints)
- Modifying existing tool behavior
- Fixing MCP response issues
- Optimizing tool performance
- Debugging tool handler errors

## Related Skills

When developing MCP tools, you may also need:

- **dap-protocol-guide** - MCP tools use DAP types for all debugging operations
- **testing-strategy** - MCP tools tested with DebugInterface for content accuracy
- **code-reuse-enforcement** - Must use existing constants/enums from core package

### MCP Architecture Overview

**For complete MCP server architecture**, see:

- `docs/developer-guide/overview.md` - System architecture showing MCP layer integration
- `src/aidb_mcp/` - MCP server implementation

```
User Request
    ↓
MCP Server (src/aidb_mcp/server/)
    ↓
Handler Registry (src/aidb_mcp/handlers/registry.py)
    ↓
Tool Handler (src/aidb_mcp/handlers/{category}/)
    ↓
DebugService (src/aidb/service/)
    ↓
Response Builder (src/aidb_mcp/responses/)
    ↓
MCP Response
```

**Key Components:**

- **Tool Definitions** (`src/aidb_mcp/tools/definitions.py`): Tool schemas and metadata
- **Handler Registry** (`src/aidb_mcp/handlers/registry.py`): Dispatcher to handlers
- **Tool Handlers** (`src/aidb_mcp/handlers/{category}/`): Business logic
- **Response Builders** (`src/aidb_mcp/responses/`): Standardized response construction
- **Decorators** (`src/aidb_mcp/core/decorators.py`): Common handler functionality

## Resource Files

For detailed guidance, see these resources:

- **[Tool Architecture](resources/tool-architecture.md)** - Tool structure, handlers, decorators
- **[Handler Decorators](resources/handler-decorators-reference.md)** - @with_execution_context, @require_initialized_session
- **[Composition Patterns](resources/handler-composition-patterns.md)** - @timed, best practices, performance
- **[Testing MCP Tools](resources/testing-mcp-tools.md)** - E2E and integration testing

## Code Reuse: Don't Reinvent

Before writing new code, check these shared modules:

### Constants and Enums

**File:** `src/aidb_mcp/core/constants.py`

```python
from aidb_mcp.core.constants import (
    ToolName,           # Tool names (INSPECT, STEP, EXECUTE, etc.) - class
    SessionAction,      # Session actions (START, STOP, STATUS, etc.) - Enum
    InspectTarget,      # Inspection targets (LOCALS, GLOBALS, STACK, etc.) - Enum
    StepAction,         # Step actions (INTO, OVER, OUT) - Enum
    ExecutionAction,    # Execution actions (RUN, CONTINUE) - Enum
    ErrorCode,          # Standardized error codes - Enum (in exceptions.py)
    ResponseStatus,     # Response statuses (OK, ERROR, WARNING) - class
    ParamName,          # Common parameter names - class
    ResponseFieldName,  # Response field names - class
    MCPResponseField,   # MCP protocol field names - class
)
```

**Note:** Some constants use classes instead of Enums for flexibility. Never use magic strings - always use constants.

### Exception Types

**File:** `src/aidb_mcp/core/exceptions.py`

```python
from aidb_mcp.core.exceptions import (
    ErrorCode,          # Error codes enum
    ErrorCategory,      # Error categories (VALIDATION, SESSION, etc.)
    ErrorRecovery,      # Recovery strategies
    classify_error,     # Classify exception by type/message
    get_recovery_strategy,     # Get recovery options
    get_suggested_actions,     # Get user-friendly actions
)
```

**Use these for error handling** - don't create new exception types unless necessary.

### Performance Types

**File:** `src/aidb_mcp/core/performance_types.py`

```python
from aidb_mcp.core.performance_types import (
    SpanType,           # Performance span types
    PerformanceSpan,    # Span data class
    TimingFormat,       # Output formats
)
```

**Use for performance tracking** - consistent metrics across tools.

## Quick Patterns

### Creating a New Tool (Step-by-Step)

> **Note:** Examples below use placeholder names (`YOUR_TOOL`, `YourResponse`). See actual implementations in `src/aidb_mcp/handlers/execution/stepping.py` and `src/aidb_mcp/responses/execution.py`.

**1. Define the tool schema** (`src/aidb_mcp/tools/definitions.py`):

```python
Tool(
    name=ToolName.YOUR_TOOL,  # Use constant from core/constants.py
    description="Clear, concise description.\n\nActions:\n- 'action1': What it does",
    inputSchema={
        "type": "object",
        "properties": {
            ParamName.ACTION: {"type": "string", "enum": ["action1", "action2"]},
            ParamName.SESSION_ID: {"type": "string"},
        },
    },
)
```

**2. Create the handler** (`src/aidb_mcp/handlers/your_category/handler.py`):

```python
from aidb_logging import get_mcp_logger as get_logger
from aidb_mcp.core.decorators import with_execution_context
from aidb_mcp.responses.errors import ErrorResponse

@with_execution_context(track_variables=True)
async def handle_your_tool(args: dict[str, Any]) -> dict[str, Any]:
    """Handle your tool operation."""
    action = args.get(ParamName.ACTION)
    api = args.get("_api")

    try:
        result = await api.your_operation()
        return YourResponse(summary=f"Performed {action}", data={"result": result}).to_mcp_response()
    except Exception as e:
        return ErrorResponse(summary="Operation failed", error_code=ErrorCode.AIDB_ERROR.value, error_message=str(e)).to_mcp_response()
```

**3. Register the handler** (`src/aidb_mcp/handlers/your_category/__init__.py`):

```python
from .handler import handle_your_tool

HANDLERS = {ToolName.YOUR_TOOL: handle_your_tool}
```

**4. Add to registry** (`src/aidb_mcp/handlers/registry.py`):

```python
from .your_category import HANDLERS as YOUR_HANDLERS

TOOL_HANDLERS = {**SESSION_HANDLERS, **YOUR_HANDLERS}
```

**5. Create response class** (`src/aidb_mcp/responses/your_response.py`):

```python
from dataclasses import dataclass
from aidb_mcp.core.constants import MCPResponseField

@dataclass
class YourResponse:
    summary: str
    data: dict[str, Any]

    def to_mcp_response(self) -> dict[str, Any]:
        return {
            MCPResponseField.SUCCESS: True,
            MCPResponseField.SUMMARY: self.summary,
            MCPResponseField.DATA: self.data,
        }
```

### Modifying an Existing Tool

**1. Locate:** Tool definitions in `src/aidb_mcp/tools/definitions.py`, handlers in `src/aidb_mcp/handlers/{category}/`

**2. Update schema** (if adding parameters) in `definitions.py`

**3. Update handler** to extract new parameter and validate

**4. Update response** to include new fields if needed

## Common Decorators

### `@with_execution_context`

Captures debugging context and adds to response. Use when tool modifies execution state.

```python
@with_execution_context(include_after=True, track_variables=False)
async def handle_your_tool(args: dict[str, Any]) -> dict[str, Any]:
    pass  # Context automatically added
```

### `@with_thread_safety`

Ensures thread-safe access to shared resources. From `aidb_mcp.core.decorator_primitives`.

### `@timed`

Tracks operation performance. From `aidb_mcp.core.performance`.

## Response Construction

### Response Builders

Use `ExecutionStateBuilder` and `CodeSnapshotBuilder` from `aidb_mcp.responses.builders` to avoid duplication.

### Response Deduplication

Use `ResponseDeduplicator.deduplicate()` from `aidb_mcp.responses.deduplicator` to remove duplicate fields.

### Response Size Limiting

Use `ResponseLimiter` from `aidb_mcp.core.response_limiter`:

- `limit_stack_frames(frames, max_frames=10)`
- `limit_variables(variables, max_vars=50)`
- `limit_code_context(lines, current_line, context_lines=5)`

### Compact Mode (Agent-Optimized Responses)

By default (`AIDB_MCP_VERBOSE=0`), responses are optimized for AI agents:

- **init**: Returns minimal `{language, framework, ready}` instead of full examples/tips
- **session_start**: Excludes `next_steps` guidance (agents learn from schema descriptions)
- **inspect (locals/globals)**: Variables use compact format `{"varName": {"v": "value", "t": "type", "varRef": N}}`

Set `AIDB_MCP_VERBOSE=1` for human-friendly responses with full details and guidance.

**Implementation pattern:**

```python
from aidb_common.config.runtime import ConfigManager

if ConfigManager().is_mcp_verbose():
    # Return full format
else:
    # Return compact format
```

## Validation

### Parameter Validation

Use `ErrorResponse` for missing/invalid parameters. Use `validate_action(action, EnumClass)` from `aidb_mcp.tools.actions` for action validation.

### Session Validation

Use `@require_initialized_session` decorator from `aidb_mcp.core.decorator_primitives` to auto-validate session and inject `_api`, `_context`, `_session_id`.

## Error Handling

Use `classify_error()` and `get_suggested_actions()` from `aidb_mcp.core.exceptions` to provide user-friendly error messages with recovery suggestions. Always include `suggested_actions` in error responses.

## Testing Your Tool

Use `DebugInterface` from `tests._helpers.debug_interface` for E2E tests. Validate three dimensions:

1. **Structure**: Response matches MCP protocol
1. **Content accuracy**: Data reflects actual debug state
1. **Efficiency**: No bloat (essential fields only)

See **[Testing MCP Tools](resources/testing-mcp-tools.md)** for comprehensive testing guidance.

## Best Practices

### DO

- Use constants from `core/constants.py` instead of magic strings
- Use existing exception types from `core/exceptions.py`
- Use response builders to avoid duplication
- Limit response size with `ResponseLimiter`
- Provide clear, actionable error messages
- Track performance with `@timed` decorator
- Write E2E tests that validate content accuracy
- Set breakpoints at session start to avoid race conditions:
  ```python
  # ✅ CORRECT
  await api.start_session(program=file, breakpoints=[{"line": 10}])
  ```

### DON'T

- Return verbose summaries (agents need concise guidance)
- Include unnecessary fields in responses
- Use magic strings for field names or error codes
- Create new exception types without checking existing ones
- Skip input validation
- Ignore performance implications
- Test only structure (validate content accuracy too)

## Common Pitfalls

1. **Bloated Responses**: Include only essential fields the agent needs for next action
1. **Verbose Summaries**: Keep concise and actionable (e.g., "Retrieved 5 local variables at line 42")
1. **Poor Error Messages**: Provide user-friendly guidance with suggested actions, not technical errors

## Summary

**Internal Documentation**: For MCP server implementation details, see `src/aidb_mcp/` and `docs/developer-guide/overview.md` for system architecture.

MCP tools are the user-facing product of AIDB. Every tool must be:

1. **Accurate** - Correct line numbers, values, state
1. **Clear** - Concise summaries, actionable next steps
1. **Fast** - Optimized operations, limited responses
1. **Clean** - No junk fields, no redundant data

Use the resources linked above for deep dives into specific topics. Always prioritize agent experience - context windows are precious.

