Nivel : Avanzado
Crear un servidor MCP: principios y pasos con el SDK oficial
Crear un servidor MCP consiste en escribir un pequeño programa que expone sus funciones, sus datos o sus plantillas de instrucciones de forma estándar, para que cualquier aplicación de IA compatible pueda descubrirlos y usarlos. Con el SDK oficial, un primer servidor útil cabe en unas treinta líneas de Python: este tutorial le acompaña desde la instalación hasta la conexión con un asistente, y después por las reglas de seguridad.
Qué va a construir
Vamos a crear un servidor «notas» que da a una IA acceso de lectura a una carpeta de notas en formato Markdown en su ordenador. Ofrecerá los tres componentes del protocolo: una herramienta de búsqueda, un recurso para leer una nota y un prompt listo para resumirla.
Requisitos previos:
- conocimientos básicos de Python y del uso de una terminal;
- Python 3.11 o una versión posterior, como exige la página de instalación del SDK;
- la herramienta
uv, que gestiona el entorno y las dependencias; - una aplicación anfitriona compatible con MCP, aquí Claude Desktop, para la prueba final.
Si el Model Context Protocol todavía le resulta confuso, empiece por nuestra explicación de MCP, el Model Context Protocol: papeles de anfitrión, cliente y servidor, transportes y seguridad.
Los tres componentes, en código
Un servidor MCP no inventa nada: describe funciones y datos para que el modelo sepa cuándo y cómo utilizarlos. En el SDK de Python, cada componente corresponde a un decorador colocado sobre una función normal.
| Componente | Decorador de Python | Quién lo activa | En nuestro servidor |
|---|---|---|---|
| Herramienta | @mcp.tool() | El modelo, con permiso del usuario | Buscar notas que contienen una palabra |
| Recurso | @mcp.resource(...) | La aplicación | Leer el contenido de una nota |
| Prompt | @mcp.prompt() | El usuario | Pedir un resumen estructurado |
Las herramientas son el componente que más usan los agentes: son la versión estandarizada de la llamada a herramientas que los grandes modelos ya saben hacer. El nombre de la función se convierte en el nombre de la herramienta, el docstring en su descripción y las anotaciones de tipo en el esquema de los parámetros.
Elegir un SDK
El sitio oficial clasifica los SDK por niveles según su grado de completitud, su soporte del protocolo y el compromiso de mantenimiento. Esta es la situación a 22 de octubre de 2026:
| Nivel | Lenguajes |
|---|---|
| Nivel 1 | TypeScript, Python, C#, Go, Rust, Ruby |
| Nivel 2 | Java |
| Nivel 3 | Swift, PHP, Kotlin |
Todos permiten crear servidores que exponen herramientas, recursos y prompts, en local o a distancia. Este tutorial usa Python; más abajo encontrará una variante en TypeScript.
Paso 1: preparar el proyecto
Instale uv si aún no lo tiene (el tutorial oficial indica el comando para cada sistema), cree el proyecto y añada el SDK con sus herramientas de línea de comandos:
uv init notas-mcp
cd notas-mcp
uv add "mcp[cli]"
La opción cli añade el comando mcp, que sirve entre otras cosas para abrir el Inspector. Después cree un archivo servidor.py y una carpeta notas en su directorio personal, con dos o tres archivos .md para hacer pruebas.
Paso 2: escribir el servidor
Este es el servidor completo. Sigue la estructura del tutorial oficial: una instancia de MCPServer, funciones decoradas y un arranque en modo stdio.
import logging
from pathlib import Path
from mcp.server import MCPServer
logger = logging.getLogger(__name__)
mcp = MCPServer("notas")
CARPETA = (Path.home() / "notas").resolve()
@mcp.tool()
def buscar_notas(palabra: str) -> list[str]:
"""Lista las notas Markdown cuyo texto contiene la palabra clave."""
logger.info("Búsqueda: %s", palabra)
return [
f.name
for f in CARPETA.glob("*.md")
if palabra.lower() in f.read_text(encoding="utf-8").lower()
]
@mcp.resource("notas://{nombre}")
def leer_nota(nombre: str) -> str:
"""Devuelve el contenido de una nota de la carpeta."""
ruta = (CARPETA / nombre).resolve()
if ruta.parent != CARPETA:
raise ValueError("Acceso denegado fuera de la carpeta de notas")
return ruta.read_text(encoding="utf-8")
@mcp.prompt()
def resumir_nota(nombre: str) -> str:
"""Prepara una petición de resumen de una nota."""
return f"Resume la nota {nombre} en cinco viñetas, primero las decisiones."
if __name__ == "__main__":
mcp.run()
Hay tres detalles importantes. Primero, el docstring no es decorativo: es lo que el modelo lee para decidir si llama a la herramienta, así que redáctelo como una instrucción precisa. Segundo, el recurso comprueba que el archivo pedido permanece dentro de la carpeta autorizada, lo que bloquea una petición del tipo ../../.ssh/config. Tercero, mcp.run() sin argumentos usa el transporte stdio, el que esperan las aplicaciones de escritorio.
Paso 3: no escriba nunca en la salida estándar
Es el error más frecuente. En modo stdio, el anfitrión y el servidor intercambian sus mensajes JSON-RPC por la entrada y la salida estándar. La documentación oficial es tajante: escribir en la salida estándar corrompe esos mensajes y rompe el servidor. Basta un simple print() de depuración.
Use el módulo logging, que escribe en la salida de errores, como en nuestro código. En TypeScript, la regla equivalente es sustituir console.log() por console.error(). Con un servidor HTTP, la restricción desaparece.
Paso 4: probar con el Inspector
Antes de conectar el servidor a un asistente, pruébelo por separado. El SDK incluye un comando que lo arranca y abre el Inspector, una interfaz de pruebas oficial:
uv run mcp dev servidor.py
En el Inspector, compruebe que aparecen la herramienta, el recurso y el prompt, llame a buscar_notas con una palabra presente en sus archivos y luego intente leer una nota que no existe para ver cómo se devuelve el error. Para pruebas automatizadas, la documentación del SDK explica cómo abrir un Client en memoria sobre su servidor con pytest, sin red.
Paso 5: conectar el servidor a Claude Desktop
Abra el archivo de configuración claude_desktop_config.json de Claude Desktop (el tutorial oficial indica dónde está en macOS, Windows y Linux) y declare su servidor bajo la clave mcpServers:
{
"mcpServers": {
"notas": {
"command": "uv",
"args": ["--directory", "/RUTA/ABSOLUTA/A/notas-mcp", "run", "servidor.py"]
}
}
}
La ruta debe ser absoluta; en Windows, duplique las barras invertidas o use barras normales. Si la aplicación no encuentra uv, indique su ruta completa en command. Cierre la aplicación por completo (cerrar la ventana no basta, advierte la documentación), vuelva a abrirla y compruebe que «notas» aparece en el menú de conectores. Por último, pregunte: «¿Qué notas hablan del presupuesto?»
Si algo falla, consulte los registros de la aplicación: cada servidor tiene un archivo que recoge su salida de errores y, por tanto, sus mensajes de logging.
Póngase a prueba Su servidor funciona en el Inspector, pero falla en cuanto Claude Desktop lo llama. Había añadido un print() para seguir las búsquedas. ¿Qué relación hay?
En modo stdio, print() escribe en la salida estándar, el mismo canal que transporta los mensajes del protocolo. El texto de depuración se mezcla con los mensajes JSON-RPC y el anfitrión ya no puede leerlos. Sustitúyalo por logger.info(), que escribe en la salida de errores, y encontrará esas líneas en el registro del servidor.
Variante: un servidor remoto por HTTP
Para compartir un servidor entre varias aplicaciones o compañeros, pase al transporte Streamable HTTP. Según la documentación del SDK de Python consultada el 22 de octubre de 2026, basta con cambiar la última línea:
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Por defecto, el servidor escucha entonces en la dirección local 127.0.0.1, puerto 8000, en la ruta /mcp. Publicarlo en Internet exige después autenticación (la especificación recomienda OAuth), HTTPS y una reflexión sobre los permisos de cada usuario. El antiguo transporte SSE está obsoleto.
¿Y en TypeScript?
El tutorial oficial sigue el mismo enfoque con el paquete @modelcontextprotocol/server y la biblioteca de validación zod. Un punto clave de la versión actual: a serveStdio se le pasa una función que crea una instancia nueva del servidor en cada llamada.
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "notas", version: "1.0.0" });
server.registerTool(
"buscar_notas",
{
description: "Lista las notas que contienen una palabra clave",
inputSchema: z.object({ palabra: z.string() }),
},
async ({ palabra }) => ({
content: [{ type: "text", text: "Buscando " + palabra }],
}),
);
return server;
}
serveStdio(createServer);
Según la documentación, un servidor conectado a la antigua con server.connect(new StdioServerTransport()) todavía compila, pero solo atiende a los clientes de la era 2025.
Reglas de seguridad desde el primer servidor
Un servidor MCP le da manos a una IA. La especificación recuerda que las herramientas equivalen a ejecutar código y que el anfitrión debe obtener el consentimiento del usuario antes de llamarlas. En el lado del servidor, adopte cuatro reflejos:
- El mínimo privilegio. Exponga una carpeta, no todo el disco; lectura, no escritura, mientras no sea necesario.
- La validación de las entradas. Los parámetros vienen de un modelo y, por tanto, indirectamente de textos que usted no controla: verifique rutas, identificadores y tamaños.
- La desconfianza hacia el contenido devuelto. Una nota o un correo leído por su herramienta puede contener una inyección de prompt, es decir, instrucciones ocultas que intentan desviar al agente.
- La confirmación humana para las acciones sensibles. Para cualquier herramienta que envíe, pague o borre, mantenga a un humano en el circuito.
Nuestra guía para proteger un agente de IA detalla estas medidas.
Usar su servidor desde un agente
Un servidor MCP no sirve solo para los asistentes de escritorio: la mayoría de los frameworks de agentes saben consumirlo. El Claude Agent SDK, el OpenAI Agents SDK o Mastra pueden cargar su servidor «notas» sin código de integración específico.
| Herramienta | Tipo | Licencia | MCP | Multiagente | Nivel |
|---|---|---|---|---|---|
| Claude Agent SDK | Código | proprietary | Sí | Sí | Intermedio |
| OpenAI Agents SDK | Código | MIT | Sí | Sí | Intermedio |
| LangGraph | Código | MIT | Sí | Sí | Avanzado |
| Mastra | Código | Apache-2.0 | Sí | Sí | Intermedio |
| goose | Low-code | Apache-2.0 | Sí | Sí | Principiante |
Para elegir, consulte nuestra comparativa de frameworks de agentes de IA o el comparador de frameworks, que puede filtrar por MCP. El servidor encaja después en la arquitectura descrita en nuestra guía para crear un agente de IA, del no-code al código. Una vez en marcha, mida si el agente llama a las herramientas adecuadas en el momento adecuado: es el tema de nuestro artículo sobre la evaluación de un agente de IA.
Preguntas frecuentes
¿Hace falta ser desarrollador para crear un servidor MCP?
Se necesitan nociones de programación, por ejemplo en Python o TypeScript. El SDK oficial se encarga del trabajo del protocolo: usted escribe funciones normales y el SDK genera su descripción para la IA. Si no programa, utilice servidores existentes o una herramienta no-code compatible con MCP.
¿Qué lenguaje elegir para un primer servidor MCP?
El que mejor domine entre los SDK oficiales. Python y TypeScript cuentan con el tutorial oficial más detallado y forman parte del nivel más alto, junto con C#, Go, Rust y Ruby. Como el protocolo es el mismo, un servidor en Python funciona con un cliente escrito en cualquier otro lenguaje.
¿Un servidor MCP tiene que funcionar en Internet?
No. Para un uso personal, lo más sencillo es un servidor local, que la aplicación de IA lanza en su ordenador y que se comunica por la entrada y la salida estándar. El transporte HTTP sirve cuando varias personas o aplicaciones deben acceder al mismo servidor a distancia.
¿Mi antiguo servidor hecho con FastMCP sigue funcionando?
La versión 2 del SDK de Python cambió el nombre de la clase FastMCP por MCPServer y sigue la especificación del 28 de julio de 2026. La documentación oficial ofrece una guía de migración. Pruebe su servidor en el Inspector tras la actualización y antes de volver a desplegarlo.