Crear un servidor MCP en Python: guía + Inspector
La promesa de los asistentes de IA siempre ha sido su capacidad para ayudar con tareas del mundo real, pero ha existido una limitación fundamental: la mayoría de los sistemas de IA operan de forma aislada, incapaces de acceder a las fuentes de datos, APIs y herramientas específicas que los hacen verdaderamente útiles para tu caso de uso particular. Ya sea que necesites que una IA consulte la base de datos de tu empresa, interactúe con tu sistema de gestión de proyectos o acceda a datos en tiempo real de APIs especializadas, el enfoque tradicional ha requerido construir integraciones personalizadas para cada plataforma de IA, un proceso lento y fragmentado.
Aquí es donde el Model Context Protocol (MCP) lo cambia todo. En lugar de que los asistentes de IA se limiten a sus datos de entrenamiento o requieran integraciones personalizadas complejas, MCP ofrece una forma estandarizada de conectar sistemas de IA a tus fuentes de datos y herramientas específicas. ¿Necesitas que tu IA acceda a la base de datos de clientes? Construye un servidor MCP. ¿Quieres que interactúe con tu API de gestión de inventario? Crea un servidor MCP. El mismo servidor funciona en distintas plataformas de IA, eliminando la necesidad de reconstruir integraciones para cada sistema.
La adopción de MCP se está acelerando rápidamente en todo el ecosistema de IA. Las principales plataformas están adoptando el protocolo como el estándar para la integración de IA. Claude Desktop y Claude for Code ya ofrecen soporte nativo para MCP, permitiendo a los usuarios conectarse sin problemas a fuentes de datos y herramientas personalizadas. Los principales proveedores de APIs de IA (OpenAI, Anthropic y Google) están añadiendo compatibilidad con MCP a sus APIs de completación, lo que permite a los desarrolladores crear aplicaciones de IA capaces de acceder a sistemas externos a través de interfaces estandarizadas. Este ecosistema en crecimiento significa que los servidores MCP que construyas hoy funcionarán con una gama cada vez mayor de plataformas y aplicaciones de IA.
En este completo tutorial, aprenderás a construir servidores MCP listos para producción usando Python mediante un enfoque iterativo y práctico. Comenzaremos con un servidor mínimo e iremos añadiendo funcionalidades progresivamente, mostrándote exactamente cómo desarrollar, probar y ampliar tu servidor paso a paso. Al final de esta guía, habrás construido un servidor MCP completo de servicio meteorológico con funcionalidades avanzadas que incluyen sampling impulsado por IA, autenticación OAuth y capacidades de despliegue en producción.
Entender MCP
El Model Context Protocol representa un cambio de paradigma en la forma en que concebimos la arquitectura de integración de IA. En esencia, MCP es un protocolo abierto que estandariza cómo las aplicaciones proporcionan contexto a los grandes modelos de lenguaje, pero sus implicaciones van mucho más allá del simple intercambio de datos.
Para entender por qué MCP importa, considera el estado actual de las integraciones de IA. La mayoría de las aplicaciones de IA de hoy operan de forma aislada, con una capacidad limitada para acceder a datos en tiempo real o interactuar con sistemas externos. Cuando los desarrolladores quieren dar a un asistente de IA acceso a una base de datos, un sistema de archivos o un servicio web, normalmente necesitan construir soluciones personalizadas que están fuertemente acopladas a plataformas de IA específicas. Este enfoque genera varios problemas: dependencia de un proveedor, esfuerzo duplicado entre distintas plataformas de IA, preocupaciones de seguridad derivadas del acceso directo a las APIs y sobrecarga de mantenimiento a medida que las APIs evolucionan.
MCP aborda estos desafíos mediante una arquitectura cliente-servidor que introduce una capa intermediaria estandarizada. En lugar de que las aplicaciones de IA accedan directamente a sistemas externos, se comunican a través de servidores MCP que actúan como pasarelas seguras y estandarizadas. Esta arquitectura ofrece varios beneficios clave que la hacen especialmente potente para despliegues empresariales y de producción.
Arquitectura central de MCP
En el corazón de la arquitectura de MCP hay tres participantes principales que trabajan juntos para permitir una integración de IA fluida:
MCP Host: La aplicación de IA que coordina y gestiona las conexiones a múltiples servidores MCP. Aplicaciones de IA populares como Claude Desktop actúan como MCP hosts cuando soportan el protocolo.
MCP Client: Un componente dentro del host que mantiene conexiones dedicadas a servidores MCP individuales, gestionando la comunicación a nivel de protocolo y el ciclo de vida de la conexión.
MCP Server: El componente que expone datos y funcionalidad a los clientes MCP de forma estandarizada. Los servidores pueden ejecutarse localmente (usando el transporte STDIO) o de forma remota (usando el transporte HTTP).
Los tres pilares de MCP
El protocolo define tres primitivas fundamentales que los servidores pueden exponer:
Las herramientas (Tools) son funciones ejecutables que las aplicaciones de IA pueden invocar para realizar acciones. Estas podrían incluir operaciones como consultar una base de datos, enviar un correo electrónico o llamar a una API externa.
Los recursos (Resources) proporcionan información contextual a las aplicaciones de IA sin realizar acciones. Representan datos que la IA puede leer y comprender, como el contenido de archivos o registros de bases de datos.
Los prompts (Prompts) son plantillas reutilizables que ayudan a estructurar las interacciones con los modelos de lenguaje, ofreciendo una forma de encapsular la experiencia de dominio y las mejores prácticas.
Configurar tu entorno de desarrollo
Antes de empezar a construir nuestro servidor MCP, configuremos un entorno de desarrollo adecuado que soporte tanto la iteración rápida como el despliegue en producción. A lo largo de este tutorial usaremos el Model Context Protocol Python SDK.
Requisitos previos
Asegúrate de tener Python 3.10 o superior instalado en tu sistema. Puedes comprobar tu versión de Python con:
python --version
# or
python3 --version
Crear tu proyecto
Crea un nuevo directorio de proyecto y configura un entorno virtual:
# Create project directory
mkdir weather-mcp-server
cd weather-mcp-server
# Create a virtual environment
python -m venv .venv
# Activate the virtual environment
# On macOS/Linux:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate
Instalar las dependencias
Instala el MCP Python SDK y las dependencias adicionales usando pip:
# Upgrade pip to the latest version
pip install --upgrade pip
# Install MCP SDK with CLI tools
pip install "mcp[cli]"
# Install HTTP client for API requests
pip install httpx
# Install JWT library for authentication (we'll use this later)
pip install PyJWT
# Install development dependencies
pip install pytest black isort mypy
Crear un archivo de requisitos
Crea un archivo requirements.txt para llevar el control de tus dependencias:
# Generate requirements file
pip freeze > requirements.txt
Tu requirements.txt debería incluir entradas como:
mcp[cli]
httpx
PyJWT
pytest
black
isort
mypy
Construir tu primer servidor MCP: paso a paso
Ahora construyamos nuestro servidor MCP meteorológico de forma iterativa, comenzando con la implementación más simple posible y añadiendo funcionalidades paso a paso. Este enfoque te ayuda a comprender cada componente y facilita la depuración.
Paso 1: Crear un servidor MCP mínimo
Empecemos con lo mínimo indispensable: un servidor que no hace nada más que responder a los mensajes básicos del protocolo MCP. Crea un archivo llamado weather_server.py:
"""
Step 1: Minimal MCP server that responds to protocol messages
"""
from mcp.server.fastmcp import FastMCP
# Create the MCP server instance
mcp = FastMCP("weather-server")
if __name__ == "__main__":
# Run the server using STDIO transport
mcp.run(transport='stdio')
Prueba este servidor mínimo:
# Start the MCP Inspector to test your server
python -m mcp dev weather_server.py
El MCP Inspector iniciará una interfaz web (normalmente en http://localhost:3000) donde podrás ver que tu servidor está en ejecución y respondiendo a los mensajes del protocolo MCP, aunque todavía no exponga ninguna herramienta.
Paso 2: Añadir tu primera herramienta
Ahora añadamos una herramienta sencilla que devuelva información meteorológica estática:
"""
Step 2: Add a simple weather tool with static data
"""
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
def get_weather(city: str) -> str:
"""Get current weather for a city (demo with static data)"""
# For now, return static data to test the tool mechanism
return f"Weather in {city}: Sunny, 22°C (This is demo data)"
if __name__ == "__main__":
mcp.run(transport='stdio')
Prueba la nueva herramienta en el MCP Inspector. Ahora deberías ver una herramienta get_weather que puedes llamar con distintos nombres de ciudades.
Paso 3: Añadir integración con una API real
Ahora conectemos con una API meteorológica real. Usaremos la API del National Weather Service, que es gratuita y no requiere autenticación:
"""
Step 3: Connect to real weather API
"""
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API"""
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 as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude})"
# Step 2: Get the actual forecast data
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Format the first few periods
periods = forecast_data.get("properties", {}).get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
return f"Forecast for {latitude}, {longitude}:\n" + "\n---\n".join(forecasts)
if __name__ == "__main__":
import sys
mcp.run(transport='stdio')
Prueba esta versión con coordenadas reales (por ejemplo, la ciudad de Nueva York: 40.7128, -74.0060). Ahora deberías obtener datos de pronóstico meteorológico reales.
Paso 4: Añadir validación de entrada y manejo de errores
Hagamos nuestro servidor más robusto añadiendo una validación de entrada y un manejo de errores adecuados:
"""
Step 4: Add input validation and better error handling
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
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 httpx.TimeoutException:
print(f"Request timeout for URL: {url}", file=sys.stderr)
return None
except httpx.HTTPStatusError as e:
print(f"HTTP error {e.response.status_code} for URL: {url}", file=sys.stderr)
return None
except Exception as e:
print(f"Unexpected error for URL {url}: {e}", file=sys.stderr)
return None
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Validate coordinate ranges
if not (-90 <= latitude <= 90):
return "Error: Latitude must be between -90 and 90 degrees"
if not (-180 <= longitude <= 180):
return "Error: Longitude must be between -180 and 180 degrees"
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude}). This location may be outside the US or the service may be unavailable."
# Extract the forecast URL from the points response
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
# Step 2: Get the actual forecast data
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Extract and format forecast periods
forecast_properties = forecast_data.get("properties", {})
periods = forecast_properties.get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
location_info = f"Forecast for {latitude}, {longitude}:\n"
return location_info + "\n---\n".join(forecasts)
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# Validate state code format
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code (e.g., 'CA', 'NY', 'TX')"
state = state.upper()
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather alerts for {state}. The service may be temporarily unavailable."
features = data.get("features", [])
if not features:
return f"No active weather alerts for {state}."
# Format alerts for display
alerts = []
for feature in features:
props = feature.get("properties", {})
event = props.get('event', 'Unknown Event')
area = props.get('areaDesc', 'Unknown Area')
severity = props.get('severity', 'Unknown Severity')
description = props.get('description', 'No description available')
alert_text = f"""
Event: {event}
Area: {area}
Severity: {severity}
Description: {description[:200]}{'...' if len(description) > 200 else ''}
"""
alerts.append(alert_text.strip())
alert_count = len(alerts)
header = f"Found {alert_count} active weather alert{'s' if alert_count != 1 else ''} for {state}:\n"
return header + "\n---\n".join(alerts)
if __name__ == "__main__":
mcp.run(transport='stdio')
Ahora prueba ambas herramientas con distintas entradas, incluidas las no válidas, para ver cómo funciona el manejo de errores.
Paso 5: Añadir recursos para información contextual
Añadamos recursos que proporcionen información contextual sobre estaciones y zonas meteorológicas:
"""
Step 5: Add resources for contextual weather information
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
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 httpx.TimeoutException:
print(f"Request timeout for URL: {url}", file=sys.stderr)
return None
except httpx.HTTPStatusError as e:
print(f"HTTP error {e.response.status_code} for URL: {url}", file=sys.stderr)
return None
except Exception as e:
print(f"Unexpected error for URL {url}: {e}", file=sys.stderr)
return None
# Tools (same as Step 4)
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Validate coordinate ranges
if not (-90 <= latitude <= 90):
return "Error: Latitude must be between -90 and 90 degrees"
if not (-180 <= longitude <= 180):
return "Error: Longitude must be between -180 and 180 degrees"
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude}). This location may be outside the US or the service may be unavailable."
# Extract the forecast URL from the points response
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
# Step 2: Get the actual forecast data
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Extract and format forecast periods
forecast_properties = forecast_data.get("properties", {})
periods = forecast_properties.get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
location_info = f"Forecast for {latitude}, {longitude}:\n"
return location_info + "\n---\n".join(forecasts)
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# Validate state code format
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code (e.g., 'CA', 'NY', 'TX')"
state = state.upper()
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather alerts for {state}. The service may be temporarily unavailable."
features = data.get("features", [])
if not features:
return f"No active weather alerts for {state}."
# Format alerts for display
alerts = []
for feature in features:
props = feature.get("properties", {})
event = props.get('event', 'Unknown Event')
area = props.get('areaDesc', 'Unknown Area')
severity = props.get('severity', 'Unknown Severity')
description = props.get('description', 'No description available')
alert_text = f"""
Event: {event}
Area: {area}
Severity: {severity}
Description: {description[:200]}{'...' if len(description) > 200 else ''}
"""
alerts.append(alert_text.strip())
alert_count = len(alerts)
header = f"Found {alert_count} active weather alert{'s' if alert_count != 1 else ''} for {state}:\n"
return header + "\n---\n".join(alerts)
# Resources for contextual information
@mcp.resource("weather://stations/{state}")
async def get_weather_stations(state: str) -> str:
"""Get information about weather observation stations in a state"""
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code"
state = state.upper()
url = f"{NWS_API_BASE}/stations?state={state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather station information for {state}"
features = data.get("features", [])
if not features:
return f"No weather stations found for {state}"
stations = []
for feature in features[:10]: # Limit to first 10 stations
props = feature.get("properties", {})
name = props.get("name", "Unknown Station")
identifier = props.get("stationIdentifier", "Unknown ID")
elevation = props.get("elevation", {}).get("value", "Unknown")
stations.append(f"- {name} ({identifier}) - Elevation: {elevation}m")
station_count = len(features)
header = f"Weather stations in {state} (showing first 10 of {station_count}):\n"
return header + "\n".join(stations)
if __name__ == "__main__":
mcp.run(transport='stdio')
En el MCP Inspector, ahora deberías ver tanto herramientas como recursos. Los recursos aparecen en una sección aparte y proporcionan información contextual que las aplicaciones de IA pueden usar para comprender mejor los datos meteorológicos.
Probar tu servidor con el MCP Inspector
Antes de integrar tu servidor con asistentes de IA como Claude Desktop, es esencial probarlo a fondo usando el MCP Inspector. El Inspector proporciona una interfaz web para probar servidores MCP, permitiéndote verificar que todas las herramientas y recursos funcionan correctamente.
Iniciar el MCP Inspector
Para probar tu servidor meteorológico con el MCP Inspector, ejecuta el siguiente comando desde el directorio de tu proyecto:
# Make sure you're in your project directory and virtual environment is activated
cd weather-mcp-server
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Start the MCP Inspector with your server
python -m mcp dev weather_server.py
Este comando hará lo siguiente:
- Iniciar tu servidor meteorológico en modo de desarrollo
- Lanzar la interfaz web del MCP Inspector
- Conectar automáticamente el Inspector a tu servidor
Deberías ver una salida similar a:
Starting MCP Inspector...
Server running at: http://localhost:3000
MCP server connected successfully
Usar la interfaz del MCP Inspector
Abre tu navegador web y ve a http://localhost:3000. La interfaz del MCP Inspector ofrece varias secciones para probar tu servidor:
Panel de información del servidor: Muestra el nombre, la versión y el estado de conexión de tu servidor. Deberías ver "weather-server" listado como conectado.
Sección de herramientas: Lista todas las herramientas disponibles con sus descripciones y esquemas de parámetros. Para tu servidor meteorológico, deberías ver:
get_forecast- Get weather forecast for coordinatesget_alerts- Get active weather alerts for a US stateanalyze_weather_trends- AI-powered weather analysis (if you've implemented Step 6)
Sección de recursos: Muestra los recursos disponibles que proporcionan información contextual:
weather://stations/{state}- Weather station information for states
Probar tus herramientas
Probemos cada herramienta de forma sistemática:
Probar la herramienta de pronóstico:
- Haz clic en la herramienta
get_forecasten el Inspector - Introduce coordenadas de prueba:
- Latitude:
40.7128(New York City) - Longitude:
-74.0060
- Latitude:
- Haz clic en "Execute Tool"
- Verifica que recibes un pronóstico meteorológico correctamente formateado con temperatura, viento e información detallada del pronóstico
Probar la herramienta de alertas:
- Haz clic en la herramienta
get_alerts - Introduce un código de estado:
CA(California) - Haz clic en "Execute Tool"
- Comprueba que recibes alertas activas o un mensaje de "No active alerts"
Probar la validación de entrada:
- Prueba con coordenadas no válidas (por ejemplo, latitude:
100, longitude:200) - Prueba con códigos de estado no válidos (por ejemplo,
XYZoCalifornia) - Verifica que tu servidor devuelve mensajes de error apropiados
Probar los recursos
Probar el recurso de estaciones meteorológicas:
- Navega hasta la sección de recursos
- Busca el recurso
weather://stations/{state} - Haz clic en él e introduce un código de estado como
TX - Verifica que recibes una lista de estaciones meteorológicas con nombres, identificadores y elevaciones
Monitorizar los registros del servidor
Mientras pruebas, mantén un ojo en la terminal donde iniciaste el Inspector. Deberías ver mensajes de registro que muestran:
- Solicitudes exitosas a la API del National Weather Service
- Cualquier mensaje de error o advertencia
- Confirmaciones de ejecución de herramientas
Ejemplo de salida de registro:
INFO: Tool 'get_forecast' called with params: {'latitude': 40.7128, 'longitude': -74.0060}
INFO: API request successful: https://api.weather.gov/points/40.7128,-74.0060
INFO: Forecast data retrieved successfully
Resolver problemas comunes
Si te encuentras con problemas durante las pruebas:
El servidor no arranca:
- Comprueba que todas las dependencias estén instaladas:
pip install -r requirements.txt - Verifica que tu entorno virtual esté activado
- Busca errores de sintaxis en tu código
Las herramientas devuelven errores:
- Comprueba tu conexión a internet (el servidor necesita acceder a weather.gov)
- Verifica que la API del National Weather Service sea accesible
- Revisa los mensajes de error en los registros del servidor
No se devuelven datos:
- Prueba con distintas coordenadas (asegúrate de que estén dentro de EE. UU.)
- Comprueba que los códigos de estado sean abreviaturas válidas de dos letras
- Verifica que las respuestas de la API no estén siendo bloqueadas por firewalls
Validar el formato de salida
Asegúrate de que las salidas de tus herramientas estén correctamente formateadas:
- Los pronósticos meteorológicos deben ser legibles para humanos
- La información de las alertas debe incluir todos los detalles relevantes
- Los mensajes de error deben ser claros y accionables
- Todas las respuestas deben ser cadenas de texto válidas (serializables a JSON)
Una vez que hayas probado a fondo tu servidor con el MCP Inspector y confirmado que todas las herramientas y recursos funcionan correctamente, estarás listo para integrarlo con asistentes de IA como Claude Desktop.
Registrar tu servidor en Claude Desktop
Ahora que tienes un servidor MCP funcional, configurémoslo para que funcione con Claude Desktop. Esto implica editar el archivo de configuración de Claude Desktop para registrar tu servidor.
Localizar el archivo de configuración
El archivo de configuración de Claude Desktop se encuentra en distintas rutas según tu sistema operativo:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Windows:
%APPDATA%\Claude\claude_desktop_config.json
Linux:
~/.config/Claude/claude_desktop_config.json
Configurar tu servidor
Crea o edita el archivo de configuración para incluir tu servidor meteorológico. Esta es la configuración básica:
{
"mcpServers": {
"weather-server": {
"command": "python",
"args": ["weather_server.py"],
"cwd": "/path/to/your/weather-mcp-server"
}
}
}
Reemplaza /path/to/your/weather-mcp-server con la ruta real a tu directorio de proyecto.
Configuración alternativa usando el entorno virtual
Si quieres usar explícitamente el intérprete de Python de tu entorno virtual:
{
"mcpServers": {
"weather-server": {
"command": "/path/to/your/weather-mcp-server/.venv/bin/python",
"args": ["weather_server.py"],
"cwd": "/path/to/your/weather-mcp-server"
}
}
}
En Windows, la ruta sería:
{
"mcpServers": {
"weather-server": {
"command": "C:\\path\\to\\your\\weather-mcp-server\\.venv\\Scripts\\python.exe",
"args": ["weather_server.py"],
"cwd": "C:\\path\\to\\your\\weather-mcp-server"
}
}
}
Probar la integración
- Guarda el archivo de configuración
- Reinicia Claude Desktop por completo (cierra y vuelve a abrir)
- Inicia una nueva conversación
- Prueba a pedirle a Claude que obtenga información meteorológica de una ubicación
¡Deberías ver a Claude usando tus herramientas meteorológicas para proporcionar información del tiempo en tiempo real!
Resolver problemas de integración con Claude Desktop
Si tu servidor no aparece en Claude Desktop:
- Comprueba la sintaxis del archivo de configuración - Usa un validador de JSON para asegurar un formato correcto
- Verifica las rutas de los archivos - Asegúrate de que todas las rutas en la configuración sean absolutas y correctas
- Comprueba los permisos - Asegúrate de que Claude Desktop pueda ejecutar tu entorno de Python
- Revisa los registros - Claude Desktop puede mostrar mensajes de error en su interfaz
- Prueba primero con el MCP Inspector - Verifica siempre que tu servidor funciona con el Inspector antes de configurar Claude Desktop
Añadir funcionalidades avanzadas
Ahora añadamos algunas funcionalidades avanzadas para hacer nuestro servidor más potente y listo para producción.
Paso 6: Añadir MCP Sampling
El sampling de MCP permite a tu servidor solicitar completaciones de IA al cliente, habilitando un análisis inteligente de los datos meteorológicos:
"""
Step 6: Add MCP sampling
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP, Context
from mcp.server.session import ServerSession
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
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 as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
# Previous tools (get_forecast, get_alerts) - same as Step 5
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# [Previous implementation from Step 5]
# ... (keeping this concise for the tutorial)
pass
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# [Previous implementation from Step 5]
# ... (keeping this concise for the tutorial)
pass
# New AI-powered tool using sampling
@mcp.tool()
async def analyze_weather_trends(
state: str,
ctx: Context[ServerSession, None]
) -> str:
"""Analyze weather alert trends for a state using AI-powered analysis"""
# First, gather current weather alert data
alerts_data = await get_alerts(state)
if "No active weather alerts" in alerts_data or "Error:" in alerts_data:
return f"No weather alerts available for analysis in {state}"
# Use sampling to analyze the weather data
analysis_prompt = f"""
Analyze the following weather alert data for {state} and provide insights about:
1. The types of weather events currently affecting the region
2. The severity and geographic distribution of alerts
3. Potential impacts on daily activities and safety
4. Any notable patterns or unusual weather conditions
Weather Alert Data:
{alerts_data}
Provide a concise but comprehensive analysis that would be helpful for emergency management and public safety planning.
"""
try:
# Request AI analysis through sampling
response = await ctx.request_sampling(
messages=[{
"role": "user",
"content": {
"type": "text",
"text": analysis_prompt
}
}],
modelPreferences={
"intelligencePriority": 0.8, # High intelligence for analysis
"speedPriority": 0.4, # Moderate speed requirement
"costPriority": 0.3 # Cost is less important for analysis
},
systemPrompt="You are a meteorological analyst with expertise in weather pattern analysis and emergency management.",
maxTokens=500
)
return f"Weather Trend Analysis for {state}:\n\n{response.content.text}"
except Exception as e:
return f"Unable to generate weather analysis: {str(e)}"
if __name__ == "__main__":
mcp.run(transport='stdio')
Paso 7: Añadir autenticación para el despliegue en producción
Para los despliegues en producción, querrás añadir autenticación. Así es como añadir una autenticación básica mediante bearer token:
"""
Step 7: Add authentication for production deployment
"""
import os
import sys
import httpx
import jwt
from datetime import datetime
from mcp.server.fastmcp import FastMCP, Context
from mcp.server.session import ServerSession
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
JWT_SECRET = os.getenv("JWT_SECRET", "your-secret-key")
class AuthenticationError(Exception):
"""Custom exception for authentication failures"""
pass
def verify_bearer_token(token: str) -> dict:
"""Verify and decode a JWT bearer token"""
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
# Check token expiration
if datetime.utcnow().timestamp() > payload.get("exp", 0):
raise AuthenticationError("Token has expired")
return payload
except jwt.InvalidTokenError as e:
raise AuthenticationError(f"Invalid token: {str(e)}")
def require_authentication(func):
"""Decorator for tools that require authentication"""
async def wrapper(*args, **kwargs):
# In a real implementation, you'd extract the auth header from the request context
# For this tutorial, we'll simulate authentication
# Check if running in authenticated mode
if os.getenv("REQUIRE_AUTH", "false").lower() == "true":
# In production, extract token from request headers
token = os.getenv("AUTH_TOKEN")
if not token:
return "Authentication required: Please provide a valid bearer token"
try:
user_context = verify_bearer_token(token)
kwargs['user_context'] = user_context
except AuthenticationError as e:
return f"Authentication failed: {str(e)}"
return await func(*args, **kwargs)
return wrapper
# Previous API helper function
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
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 as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
# Authenticated tools
@mcp.tool()
@require_authentication
async def get_secure_forecast(
latitude: float,
longitude: float,
user_context: dict = None
) -> str:
"""Get weather forecast with authentication and audit logging"""
user_id = user_context.get("sub", "unknown") if user_context else "anonymous"
print(f"Forecast request from user {user_id} for {latitude}, {longitude}", file=sys.stderr)
# Use the same forecast logic as before
# [Implementation details omitted for brevity]
return f"Authenticated forecast for {latitude}, {longitude} (User: {user_id})"
if __name__ == "__main__":
# Determine transport based on environment
transport = os.getenv("MCP_TRANSPORT", "stdio")
if transport == "http":
# Production HTTP deployment with authentication
port = int(os.getenv("PORT", 8000))
host = os.getenv("HOST", "0.0.0.0")
print(f"Starting secure MCP server on {host}:{port}", file=sys.stderr)
mcp.run(transport="http", host=host, port=port)
else:
# Development STDIO deployment
print("Starting MCP server in STDIO mode", file=sys.stderr)
mcp.run(transport="stdio")
Consideraciones para el despliegue en producción
Al desplegar tu servidor MCP en producción, ten en cuenta estos factores importantes:
Configuración del entorno
Usa variables de entorno para la configuración:
# .env file for production
MCP_TRANSPORT=http
HOST=0.0.0.0
PORT=8000
REQUIRE_AUTH=true
JWT_SECRET=your-production-secret-key
NWS_API_USER_AGENT=your-production-app/1.0
Despliegue con Docker
Crea un Dockerfile para un despliegue en contenedores:
FROM python:3.11-slim
WORKDIR /app
# Copy requirements and install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy project files
COPY weather_server.py ./
# Expose port
EXPOSE 8000
# Run the server
CMD ["python", "weather_server.py"]
Construye y ejecuta el contenedor de Docker:
# Build the image
docker build -t weather-mcp-server .
# Run the container
docker run -p 8000:8000 -e MCP_TRANSPORT=http weather-mcp-server
Monitorización y registro
Implementa un registro adecuado para producción:
import logging
import sys
# Configure logging for production
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/mcp-server.log'),
logging.StreamHandler(sys.stderr)
]
)
logger = logging.getLogger(__name__)
# Use logger throughout your application
logger.info("Server starting up")
logger.error("API request failed", exc_info=True)
Resolver problemas comunes
Problemas de registro con STDIO
El problema más común es escribir en stdout en servidores STDIO:
# Wrong - breaks the protocol
print("Debug message")
# Correct - use stderr
print("Debug message", file=sys.stderr)
# Better - use logging
import logging
logging.basicConfig(stream=sys.stderr)
logger = logging.getLogger(__name__)
logger.info("Debug message")
Errores de serialización JSON
Asegúrate de que todos los valores de retorno de las herramientas sean serializables a JSON:
# Wrong - returns complex object
@mcp.tool()
def bad_tool():
return SomeComplexObject()
# Correct - returns string
@mcp.tool()
def good_tool():
result = SomeComplexObject()
return str(result) # or result.to_dict() if available
Problemas de autenticación
Para servidores HTTP, verifica tu configuración de autenticación:
# Debug authentication setup
def debug_auth():
required_vars = ["JWT_SECRET", "AUTH_TOKEN"]
for var in required_vars:
if not os.getenv(var):
print(f"Missing environment variable: {var}", file=sys.stderr)
Próximos pasos y temas avanzados
Con tu servidor MCP meteorológico completo, estás listo para explorar patrones más avanzados:
Ampliar tu servidor
Considera añadir estas funcionalidades:
- Datos meteorológicos históricos de APIs adicionales
- Integración de mapas meteorológicos con recursos de imágenes
- Alertas en tiempo real usando conexiones WebSocket
- Predicciones con machine learning usando sampling para el análisis
Patrones arquitectónicos avanzados
Explora estos patrones para despliegues complejos:
- Arquitecturas multiservidor con dominios especializados
- Composición de servidores combinando múltiples servidores MCP
- Despliegues distribuidos entre regiones de nube
- Integración de microservicios con sistemas existentes
Referencias
[1] Introducción de Anthropic al Model Context Protocol
[2] Documentación del Model Context Protocol
[3] Model Context Protocol Python SDK
[4] Guía oficial para construir servidores MCP
[5] Resumen de la arquitectura de MCP
Prueba tu servidor MCP en el navegador
Pega la URL de un servidor MCP y mira todas las herramientas, recursos y prompts que expone, con esquemas completos y el registro de peticiones. Gratis, sin instalación y sin registro.