Cómo Construir Tu Primer Servidor MCP: Tutorial Paso a Paso

Requisitos previos
Antes de comenzar, asegúrate de tener estos elementos listos:
- Python 3.10 o superior instalado.
- Conocimientos básicos de funciones de Python y código asíncrono.
- uv (gestor de paquetes Python rápido) – instálalo con
curl -LsSf https://astral.sh/uv/install.sh | sh. - Un cliente MCP como Claude Desktop (descárgalo desde claude.ai/download y mantenlo actualizado).
- Un editor de texto o IDE.
No se requiere experiencia previa con MCP. Construiremos un servidor MCP de clima práctico que permita a la IA consultar alertas y pronósticos meteorológicos en tiempo real en EE. UU. mediante la API del Servicio Meteorológico Nacional.
Paso234 1: Configurar el entorno
Crea un directorio de proyecto limpio e inicialízalo con uv:
mkdir weather-mcp-server
cd weather-mcp-server
uv init
uv venv
source .venv/bin/activate # En Windows: .venv\Scripts\activate
uv add "mcp[cli]" httpx
Esto instala el SDK oficial de Python para MCP (FastMCP) y httpx para las llamadas a la API. Tu proyecto ahora tiene un pyproject.toml y un entorno virtual.
Resultado esperado: Una nueva carpeta .venv y las dependencias listadas en uv.lock.
Paso 2: Crear el código del servidor MCP
Crea el archivo principal:
touch weather.py
Pega este código completo y listo para ejecutar en weather.py:
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
# Inicializar el servidor MCP
mcp = FastMCP("weather")
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
# Función auxiliar para llamar a la API del NWS de forma segura
async def make_nws_request(url: str) -> dict[str, Any] | None:
headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception:
return None
# Formatear las alertas meteorológicas de forma legible para la IA
def format_alert(feature: dict) -> str:
props = feature["properties"]
return f"""
Evento: {props.get("event", "Desconocido")}
Área: {props.get("areaDesc", "Desconocida")}
Gravedad: {props.get("severity", "Desconocida")}
Descripción: {props.get("description", "No hay descripción disponible")}
Instrucciones: {props.get("instruction", "No se proporcionaron instrucciones específicas")}
"""
# Herramienta 1: Obtener alertas meteorológicas activas para un estado de EE. UU.
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Obtiene las alertas meteorológicas actuales para un estado de EE. UU. (ej. "CA" o "TX")."""
url = f"{NWS_API_BASE}/alerts/active/area/{state.upper()}"
data = await make_nws_request(url)
if not data or "features" not in data:
return "No se pudieron obtener las alertas o no se encontraron alertas."
if not data["features"]:
return f"No hay alertas activas para {state.upper()}."
alerts = [format_alert(f) for f in data["features"]]
return "\n---\n".join(alerts)
Herramienta 2: Obtener pronóstico de 5 días para cualquier lat/long
@mcp.tool() async def get_forecast(latitude: float, longitude: float) -> str: """Obtener pronóstico del tiempo para una latitud y longitud específicas.""" points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}" points_data = await make_nws_request(points_url) if not points_data: return "No se puede obtener datos de pronóstico para esta ubicación." forecast_url = points_data["properties"]["forecast"] forecast_data = await make_nws_request(forecast_url) if not forecast_data: return "No se puede obtener el pronóstico detallado." periods = forecast_data["properties"]["periods"][:5] forecasts = [] for period in periods: forecast = f""" {period["name"]}: Temperatura: {period["temperature"]}°{period["temperatureUnit"]} Viento: {period["windSpeed"]} {period["windDirection"]} Pronóstico: {period["detailedForecast"]} """ forecasts.append(forecast) return "\n---\n".join(forecasts)
def main(): mcp.run(transport="stdio")
if name == "main": main()
**Conceptos clave explicados:**
- Los decoradores `@mcp.tool()` convierten funciones asíncronas regulares en herramientas MCP que la IA puede descubrir y llamar.
- El servidor se ejecuta sobre **stdio** (entrada/salida estándar) – el valor por defecto para servidores MCP locales.
- Todo el registro de eventos debe ir a stderr (FastMCP maneja esto automáticamente).
## Paso就比较 3: Probar el Servidor Localmente
Ejecuta el servidor:
```bash
uv run weather.py
Salida esperada: La terminal permanece abierta y silenciosa (esto es normal para servidores stdio). Solo verás mensajes JSON-RPC cuando un cliente MCP se conecte.
Deja esta terminal en ejecución para el siguiente paso.
Paso 4: Conectar el Servidor MCP a Claude Desktop
- Abre Claude Desktop.
- Crea o edita el archivo de configuración en:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
Añade esta entrada exacta (reemplaza /ABSOLUTE/PATH/TO/weather-mcp-server con la ruta real de tu carpeta):
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"/ABSOLUTE/PATH/TO/weather-mcp-server",
"run",
"weather.py"
]
}
}
}
- Cierra completamente Claude Desktop (Cmd+Q en macOS o cierra desde la bandeja del sistema en Windows) y reinícialo.
- En Claude, haz clic en "Add files, connectors, and more" → pasa el cursor sobre Connectors → deberías ver "weather" en la lista.
Paso 5: Usa Tu Servidor MCP con la IA
Prueba estos mensajes en Claude Desktop:
- "¿Qué alertas meteorológicas activas hay en Texas?"
- "Dame el pronóstico para San Francisco (usa lat 37.77, long -122.41)."
- "Verifica las alertas en California y dime si necesito prepararme para algo."
Claude descubrirá automáticamente las herramientas, pedirá tu aprobación la primera vez y devolverá resultados formateados.
Comportamiento esperado: La IA llama a tus herramientas en segundo plano y muestra respuestas en lenguaje natural.
Problemas comunes y solución de problemas
-
El servidor no aparece en Claude:
- Verifica nuevamente que el JSON sea válido (sin comas finales).
- Usa una ruta absoluta en la configuración.
- Reinicia Claude completamente.
- Revisa los registros:
~/Library/Logs/Claude/mcp*.log(macOS) o el equivalente en Windows.
-
Errores de API o sin datos:
- La API del NWS solo funciona para ubicaciones en EE. UU.
- Usa códigos de estado de dos letras (CA, TX, etc.).
- Las coordenadas deben ser latitud/longitud válidas.
-
“Comando no encontrado”:
- Asegúrate de que uv esté en tu PATH y que el entorno virtual esté activado.
- Ejecuta
uv --versionpara verificar la instalación.
-
Tiempo de espera agotado o respuesta lenta:
- Aumenta el tiempo de espera en
make_nws_requestsi es necesario. - El NWS tiene límites de velocidad – evita saturarlo en producción.
- Aumenta el tiempo de espera en
-
Problemas de permisos:
- En macOS, otorga acceso completo al disco a Claude Desktop en Configuración del Sistema → Privacidad y Seguridad.
Próximos pasos
- Añade más herramientas: Crea herramientas para bases de datos, GitHub, Slack o tus propias APIs usando el mismo patrón
@mcp.tool(). - Añade recursos y prompts: Usa
mcp.resource()ymcp.prompt()para datos tipo archivo e instrucciones reutilizables. - Implementa remotamente: Cambia al transporte HTTP/SSE y aloja en AWS Lambda, Vercel o cualquier servidor (FastMCP admite
stateless_http=True). /Lenguajes**: Prueba los SDKs oficiales de TypeScript, Go o Rust para la misma funcionalidad. - Comparte tu servidor: Publica el repositorio para que otros puedan agregarlo mediante
npxo Docker.
Ahora tienes un servidor MCP completamente funcional que cualquier cliente de IA compatible puede usar. Experimenta, amplía las herramientas y ¡empieza a crear poderosas integraciones de IA hoy mismo!