Construir un servidor MCP propio toma menos de 50 líneas en Python. Aquí un ejemplo real: exponer una API interna de inventario como tool para Claude.
Prerrequisitos
- Python 3.10+ y
uv. - SDK oficial:
uv add mcp.
Estructura mínima
mi_servidor/
pyproject.toml
src/
__init__.py
server.py
server.py — 40 líneas
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("inventario-empresa")
API_BASE = "https://api.miempresa.cl/v1"
TOKEN = "..."
@mcp.tool()
async def buscar_producto(nombre: str) -> dict:
"""Busca un producto en el inventario por nombre."""
async with httpx.AsyncClient() as c:
r = await c.get(f"{API_BASE}/productos", params={"q": nombre},
headers={"Authorization": f"Bearer {TOKEN}"})
return r.json()
@mcp.tool()
async def stock(sku: str) -> dict:
"""Devuelve el stock actual por SKU."""
async with httpx.AsyncClient() as c:
r = await c.get(f"{API_BASE}/stock/{sku}",
headers={"Authorization": f"Bearer {TOKEN}"})
return r.json()
if __name__ == "__main__":
mcp.run()
Configurarlo en Claude Desktop
{
"mcpServers": {
"inventario": {
"command": "uv",
"args": ["--directory", "/ruta/mi_servidor", "run", "server.py"]
}
}
}
Probar
Reinicia Claude Desktop y pregunta: “¿Hay stock de SKU-123?”. Claude llamará automáticamente a stock("SKU-123").
Buenas prácticas
- Validación: usa Pydantic para los inputs.
- Errores: lanza
McpError; el cliente los muestra al usuario. - Logs: usa
logging, noprint(rompe stdio). - Tests: el SDK incluye
mcp.clientpara tests in-process. - Distribuir: publica en PyPI o un registry privado; instalable con
uvx tu-paquete.