Files
gh-cskiro-claudex/skills/claude-code/mcp-server-creator/reference/language-guides/python.md
2025-11-29 18:16:40 +08:00

1.8 KiB

Python MCP Server Best Practices (FastMCP)

Setup

uv init mcp-server-name
uv add "mcp[cli]"

Implementation

  • ✓ Use type hints (FastMCP reads them!)
  • ✓ Write detailed docstrings (becomes tool descriptions)
  • ✓ Use async functions for I/O
  • ✓ Handle exceptions gracefully
  • ✓ Log to stderr only in STDIO mode

Tool Definition

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("server-name")

@mcp.tool()
async def search_database(query: str, limit: int = 10) -> str:
    """
    Search the database for records matching the query.

    Args:
        query: Search terms to match against records
        limit: Maximum number of results to return (default: 10)

    Returns:
        JSON string of matching records
    """
    results = await db.search(query, limit=limit)
    return json.dumps(results)

Resource Definition

@mcp.resource("db://tables/{table_name}/schema")
async def get_table_schema(table_name: str) -> str:
    """Get the schema for a database table."""
    schema = await db.get_schema(table_name)
    return json.dumps(schema)

Critical Rules

STDIO Transport

import sys

# WRONG - corrupts JSON-RPC
print("Debug info")

# CORRECT - safe for STDIO
print("Debug info", file=sys.stderr)

# Or use logging
import logging
logging.basicConfig(level=logging.INFO, stream=sys.stderr)

Error Handling

@mcp.tool()
async def risky_operation(param: str) -> str:
    """Perform an operation that might fail."""
    try:
        result = await external_api.call(param)
        return str(result)
    except Exception as e:
        logging.error(f"Operation failed: {e}")
        raise ValueError(f"Operation failed: {e}")

Run

# With uv
uv run main.py

# Direct
python main.py