Skip to content

Latest commit

 

History

History
375 lines (269 loc) · 10.2 KB

File metadata and controls

375 lines (269 loc) · 10.2 KB

MCP Server Development Guide

This guide explains how to set up a fast, productive development workflow for the Katana MCP Server using hot-reload capabilities.

Prerequisites

  1. Install uv (if not already installed):

    curl -LsSf https://astral.sh/uv/install.sh | sh

    Or see uv installation docs

  2. Python 3.12+ (for hot-reload mode)

  3. Find your uv path: Run which uv (usually ~/.local/bin/uv)

Quick Start

HTTP Development Mode (recommended)

Hot-reload with HTTP transport — ideal for testing with Claude.ai co-work or any HTTP MCP client:

# From the repo root
uv run poe dev

The server starts on http://0.0.0.0:8765/mcp with automatic reload on file changes.

For Claude.ai co-work, you also need an HTTPS tunnel (Claude.ai requires HTTPS + public URL):

# Terminal 1: MCP server with hot-reload
uv run poe dev

# Terminal 2: HTTPS tunnel
ngrok http 8765
# → Paste the https:// URL into Claude.ai > Customize > Connectors

stdio Development Mode

Hot-reload with stdio transport — for Claude Desktop:

uv run poe dev-stdio

Or with mcp-hmr for fine-grained module reloading (preserves connection state):

cd katana_mcp_server
uv pip install mcp-hmr
uv run mcp-hmr katana_mcp.server:mcp

MCP Inspector (visual debugging)

Launches a web UI for testing tools interactively:

uv run poe dev-inspect

Production Mode (Standard Install)

For release testing and production use:

cd katana_mcp_server
uv build
pipx install --force dist/katana_mcp_server-*.whl

Development Modes

Command Transport Hot Reload Use Case
poe dev streamable-http Yes Claude.ai co-work, HTTP
poe dev-stdio stdio Yes Claude Desktop, Claude Code
poe dev-inspect Inspector UI Yes Visual tool debugging
mcp-hmr stdio Yes (fast) Fine-grained module reload
katana-mcp-server stdio (default) No Production

Claude Desktop Configuration

You can configure Claude Desktop to support both modes simultaneously.

Configuration File Location

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Example Configuration

{
  "mcpServers": {
    "katana-erp-dev": {
      "command": "/absolute/path/to/katana-openapi-client/.venv/bin/mcp-hmr",
      "args": ["katana_mcp.server:mcp"],
      "cwd": "/absolute/path/to/katana-openapi-client/katana_mcp_server",
      "env": {
        "KATANA_API_KEY": "your-api-key-here"
      }
    },
    "katana-erp": {
      "command": "katana-mcp-server",
      "env": {
        "KATANA_API_KEY": "your-api-key-here"
      }
    }
  }
}

Important:

  • Replace /absolute/path/to/ with your actual repository path
  • The .venv/bin/mcp-hmr executable is created when you run uv pip install mcp-hmr
  • On Windows, use .venv\\Scripts\\mcp-hmr.exe instead

Switching Between Modes

  • Development: Use @katana-erp-dev in Claude Desktop
  • Production: Use @katana-erp in Claude Desktop
  • Both can be enabled at the same time

Tip: Use development mode while coding, then test against production mode before creating a PR.

Development Workflow

Typical Iteration Cycle

# 1. Start development server (once)
cd katana_mcp_server
uv run mcp-hmr katana_mcp.server:mcp

# 2. Use the MCP server in Claude Desktop
#    - Chat with Claude
#    - Test your tools
#    - Notice a bug or want to add a feature

# 3. Edit code in your editor
#    - Modify src/katana_mcp/tools/inventory.py
#    - Add logging, fix bugs, improve error handling
#    - Save the file

# 4. Test immediately in Claude Desktop
#    - No restart needed!
#    - Try the tool again
#    - See your changes instantly

# 5. Iterate until satisfied
#    - Keep editing and saving
#    - Changes apply in real-time

What Gets Hot-Reloaded?

Reloads automatically:

  • Tool implementations (src/katana_mcp/tools/*.py)
  • Helper functions
  • Request/response models
  • Business logic

Requires restart:

  • server.py changes (FastMCP initialization)
  • Lifespan context changes
  • New dependencies in pyproject.toml

Adding Debug Logging

Hot reload makes debugging much faster:

# Before (in src/katana_mcp/tools/foundation/inventory.py)
async def _check_inventory_impl(
    request: CheckInventoryRequest, context: Context
) -> list[StockInfo]:
    services = get_services(context)
    # ... fetch variants from cache, look up stock per variant ...

# After (add logging - save file - test immediately!)
from katana_mcp.logging import get_logger
logger = get_logger(__name__)

async def _check_inventory_impl(
    request: CheckInventoryRequest, context: Context
) -> list[StockInfo]:
    logger.info(
        "inventory_check_started",
        sku_count=sum(1 for x in request.skus_or_variant_ids if isinstance(x, str)),
        variant_id_count=sum(1 for x in request.skus_or_variant_ids if isinstance(x, int)),
    )
    services = get_services(context)
    # ... rest of function

Save → Test in Claude Desktop → See logs immediately!

How mcp-hmr Works

mcp-hmr (Model Context Protocol Hot Module Replacement) provides:

  1. Fine-grained reloading: Only reloads changed modules, not the entire process
  2. Preserved state: Keeps connections alive, database pools intact
  3. Fast feedback: See changes in seconds, not minutes
  4. Standard Python: Uses importlib machinery, no magic

Technical Details

  • Watches file system for changes to .py files
  • Uses Python's import hooks to reload modified modules
  • Preserves the FastMCP server instance and lifespan context
  • Updates tool registrations without restarting the server

Testing Your Changes

Unit Tests (Always Run First)

# Run tests before committing
uv run poe test

# Pre-commit hooks will also run tests automatically
git commit -m "feat(mcp): add new inventory tool"

Integration Testing Workflow

  1. Development mode: Iterate rapidly with hot reload
  2. Production mode: Verify the installed package works
  3. Claude Desktop: Test actual tool usage
  4. Automated tests: Ensure everything passes
# After development, test the full cycle
uv run poe test                    # Unit tests pass
uv build                           # Build package
pipx install --force dist/*.whl    # Install for real
# Test in Claude Desktop with production config

Troubleshooting

Hot Reload Not Working

Problem: Changes don't appear after saving

Solutions:

  1. Check that you saved the file
  2. Verify mcp-hmr is installed: uv run --extra dev mcp-hmr --version
  3. Look for error messages in the terminal running the server
  4. Some changes (like server.py) require a full restart

Module Import Errors

Problem: ModuleNotFoundError or ImportError

Solutions:

  1. Ensure you're running from the correct directory: cd katana_mcp_server
  2. Verify dependencies are installed: uv sync --extra dev
  3. Check that the file path in the command is correct: src/katana_mcp/server.py:mcp

Claude Desktop Not Finding Server

Problem: MCP server doesn't appear in Claude Desktop

Solutions:

  1. Verify claude_desktop_config.json path is correct
  2. Check JSON syntax (use a validator if needed)
  3. Restart Claude Desktop after config changes
  4. Verify cwd path is absolute and correct
  5. Check that KATANA_API_KEY is set in env

Permission Errors

Problem: PermissionError when running server

Solutions:

  1. Ensure the repository directory is writable
  2. Check that .env file has correct permissions
  3. On Unix: chmod 600 .env to secure API key file

Best Practices

1. Use Development Mode for All Coding

# Start dev server once, keep it running all day
uv run mcp-hmr katana_mcp.server:mcp

2. Test in Production Mode Before PR

# Before creating a PR, verify production install
uv build
pipx install --force dist/*.whl
# Test in Claude Desktop with production config

3. Keep Tests Passing

# Pre-commit hooks run automatically, but you can run manually:
uv run poe test          # Just tests
uv run poe check         # Full validation (lint + test + format)

4. Use Descriptive Logging

# Good: Helps debug issues
logger.info(f"Processing inventory check for SKU: {request.sku}")
logger.debug(f"Client config: base_url={client.base_url}, timeout={client.timeout}")
logger.warning(f"SKU not found: {request.sku}, returning empty stock")

# Bad: Not helpful
logger.info("Doing a thing")
logger.debug("Debug message")

5. Structure for Testability

# Good: Separate implementation from FastMCP decorator
async def _check_inventory_impl(request, context) -> StockInfo:
    \"\"\"Implementation with full business logic.\"\"\"
    # ... implementation

@mcp.tool()
async def check_inventory(request, context) -> StockInfo:
    \"\"\"FastMCP tool wrapper - minimal logic here.\"\"\"
    return await _check_inventory_impl(request, context)

This allows testing _check_inventory_impl directly with mocks.

Additional Resources

Getting Help


Happy coding! 🚀 The hot-reload workflow will dramatically speed up your development iteration time.