Files
leo-claude-mktplace/plugins/debug-mcp/skills/server-patterns.md
lmiranda 2d51df7a42 feat(marketplace): command consolidation + 8 new plugins (v8.1.0 → v9.0.0) [BREAKING]
Phase 1b: Rename all ~94 commands across 12 plugins to /<noun> <action>
sub-command pattern. Git-flow consolidated from 8→5 commands (commit
variants absorbed into --push/--merge/--sync flags). Dispatch files,
name: frontmatter, and cross-reference updates for all plugins.

Phase 2: Design documents for 8 new plugins in docs/designs/.

Phase 3: Scaffold 8 new plugins — saas-api-platform, saas-db-migrate,
saas-react-platform, saas-test-pilot, data-seed, ops-release-manager,
ops-deploy-pipeline, debug-mcp. Each with plugin.json, commands, agents,
skills, README, and claude-md-integration. Marketplace grows from 12→20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 14:52:11 -05:00

2.8 KiB

MCP Server Patterns Skill

Standard patterns for building Python MCP servers compatible with Claude Code.

Directory Structure

mcp-servers/<name>/
├── mcp_server/
│   ├── __init__.py           # Package marker
│   ├── config.py             # Configuration loader
│   ├── server.py             # Entry point (MCP server setup)
│   └── tools/
│       ├── __init__.py       # Tool registration
│       └── <category>.py     # Tool implementations grouped by domain
├── tests/
│   ├── __init__.py
│   └── test_tools.py
├── requirements.txt
└── README.md

The FastMCP decorator pattern provides the simplest server implementation:

# server.py
from mcp.server.fastmcp import FastMCP
from .config import load_config

mcp = FastMCP("server-name")
config = load_config()

# Import tools to register them
from .tools import category  # noqa: F401

if __name__ == "__main__":
    mcp.run()
# tools/category.py
from ..server import mcp, config

@mcp.tool()
def my_tool(param: str) -> str:
    """Tool description."""
    return f"Result for {param}"

Configuration Loader Pattern

# config.py
import os
from pathlib import Path
from dotenv import load_dotenv

def load_config() -> dict:
    # System-level config
    sys_config = Path.home() / ".config" / "claude" / "<name>.env"
    if sys_config.exists():
        load_dotenv(sys_config)

    # Project-level overrides
    project_env = Path.cwd() / ".env"
    if project_env.exists():
        load_dotenv(project_env, override=True)

    config = {
        "api_url": os.getenv("<NAME>_API_URL"),
        "api_token": os.getenv("<NAME>_API_TOKEN"),
    }

    # Validate required
    missing = [k for k, v in config.items() if v is None]
    if missing:
        raise ValueError(f"Missing config: {', '.join(missing)}")

    return config

Entry Point Configuration

In .mcp.json:

{
  "mcpServers": {
    "<name>": {
      "command": "mcp-servers/<name>/.venv/bin/python",
      "args": ["-m", "mcp_server.server"],
      "cwd": "mcp-servers/<name>"
    }
  }
}

The -m flag runs the module as a script, using __main__.py or the if __name__ == "__main__" block.

Requirements

Minimum dependencies for an MCP server:

mcp>=1.0.0
python-dotenv>=1.0.0

For HTTP-based integrations add:

httpx>=0.24.0

Testing Pattern

# tests/test_tools.py
import pytest
from mcp_server.tools.category import my_tool

def test_my_tool():
    result = my_tool("test")
    assert "test" in result

Startup Logging

Always log initialization status to stderr:

import sys

def log(msg):
    print(msg, file=sys.stderr)

log(f"MCP Server '{name}' initialized: {len(tools)} tools registered")