Crear su propio servidor MCP en 30 minutos

Puede crear un servidor MCP con unas treinta líneas de Python y el SDK oficial: usted escribe funciones con anotaciones de tipo, y el SDK deduce el esquema de los parámetros y gestiona el protocolo. Calcule 30 minutos para tener un primer servidor con dos herramientas y un recurso, probarlo en Inspector y conectarlo a Claude, Cursor o VS Code. Este tutorial utiliza la versión 2 del SDK de Python, publicada el 28 de julio de 2026 (v2.3.0 a fecha del 2 de octubre de 2026).
Qué va a construir
Un servidor «Notes» que dará a su asistente de IA acceso de solo lectura a una carpeta de notas en Markdown:
- una herramienta
chercher_notesque devuelve las notas que contienen una palabra; - una herramienta
lire_noteque devuelve el contenido de una nota; - un recurso
notes://listecon la lista de archivos.
Elegir el acceso de solo lectura tiene un motivo: es la regla básica para un primer servidor. Una herramienta que escribe, elimina o envía algo puede activarse por error, o por una inyección de prompt oculta en un documento que el agente haya leído.
Si estos términos son nuevos para usted, el artículo Servidor MCP: qué es y qué servidores conviene conocer explica los conceptos básicos. También encontrará la definición de servidor MCP en el glosario.
Requisitos previos
- Python 3.11 o una versión posterior, como exige el SDK v2.
- uv, el gestor de paquetes de Python recomendado por la documentación del SDK. También puede usar
pip. - Una aplicación anfitriona compatible con MCP para la prueba final: Claude Desktop, Claude Code, Cursor o VS Code con GitHub Copilot.
- Una carpeta con algunos archivos
.mdpara hacer las pruebas.
Los tres componentes de un servidor MCP
La documentación del SDK de Python los distingue según quién decide utilizarlos:
| Componente | Quién lo activa | Equivalente web | Ejemplo |
|---|---|---|---|
| Herramienta (tool) | El modelo | Petición POST: actúa y puede modificar datos | Buscar en una base de datos, crear un ticket |
| Recurso (resource) | La aplicación anfitriona | Petición GET: lee sin modificar nada | El contenido de un archivo |
| Prompt | El usuario | Comando guardado | Un comando «/resumir» |
El servidor nunca se comunica directamente con el modelo: el cliente MCP, integrado en la aplicación anfitriona, es quien le transmite las llamadas.
Paso 1: crear el proyecto
uv init serveur-notes
cd serveur-notes
uv add "mcp[cli]"
La opción [cli] instala el comando mcp (mcp dev, mcp run, mcp install), además del SDK. Si utiliza pip: pip install "mcp[cli]".
Paso 2: escribir el servidor
Cree el archivo server.py:
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
# Carpeta expuesta en modo de solo lectura. No se puede acceder a nada fuera de ella.
NOTES = Path.home() / "notes"
mcp = MCPServer("Notes")
def _fichier(nom: str) -> Path:
"""Chemin d'une note, refusé s'il sort du dossier NOTES."""
chemin = (NOTES / nom).resolve()
if not chemin.is_relative_to(NOTES.resolve()) or chemin.suffix != ".md":
raise ToolError(f"Note refusée : {nom!r}")
if not chemin.is_file():
raise ToolError(f"Aucune note nommée {nom!r}")
return chemin
@mcp.tool()
def chercher_notes(mot: str) -> list[str]:
"""Liste les notes Markdown qui contiennent ce mot (sans tenir compte des majuscules)."""
mot = mot.lower()
return sorted(
f.name for f in NOTES.glob("*.md")
if mot in f.read_text(encoding="utf-8", errors="ignore").lower()
)
@mcp.tool()
def lire_note(nom: str) -> str:
"""Renvoie le contenu complet d'une note, par exemple « reunion-lundi.md »."""
return _fichier(nom).read_text(encoding="utf-8", errors="ignore")
@mcp.resource("notes://liste")
def liste() -> str:
"""Toutes les notes disponibles, une par ligne."""
return "\n".join(sorted(f.name for f in NOTES.glob("*.md")))
if __name__ == "__main__":
mcp.run()
Conviene fijarse en tres puntos:
- Las anotaciones de tipo definen el esquema. Basta con
mot: str: el SDK genera el esquema JSON que el cliente muestra al modelo. Usted no tiene que escribir la validación ni el análisis de las peticiones. - La docstring es la descripción que lee el modelo para elegir la herramienta. Redáctela con cuidado: de ella depende que el modelo invoque la herramienta en el momento adecuado.
_fichierimpide salir de la carpeta. Sin esta comprobación, un nombre como../.ssh/id_rsapermitiría leer cualquier archivo de su cuenta. Es el fallo más frecuente de los servidores que acceden al disco.
Si viene de la versión 1 del SDK, tenga en cuenta que FastMCP ahora se llama MCPServer y que la importación mcp.server.fastmcp ya no existe. La guía de migración recoge los demás cambios.
Paso 3: probarlo en Inspector
uv run mcp dev server.py
El comando inicia MCP Inspector y muestra una dirección local que debe abrir en el navegador. Compruebe lo siguiente:
- En la pestaña Tools,
chercher_notesylire_noteaparecen con su descripción y un campo de entrada. - Al llamar a
lire_notecon../secret.md, recibe el error «Note refusée». - En la pestaña Resources,
notes://listedevuelve la lista de sus archivos.
Pruebe siempre el servidor por separado antes de conectarlo: aquí resulta mucho más fácil interpretar un error que a través de una aplicación anfitriona.
Paso 4: conectarlo a su asistente
Todas las aplicaciones anfitrionas siguen el mismo procedimiento: ejecutan el servidor como un proceso y se comunican con él mediante la entrada y la salida estándar, con el transporte stdio. Por tanto, basta con indicarles el comando de inicio, siempre con una ruta absoluta:
uv run --with "mcp[cli]" mcp run /chemin/absolu/vers/server.py
Claude Desktop — el SDK escribe la configuración por usted:
uv run mcp install server.py
Cierre Claude Desktop por completo, no solo la ventana, y vuelva a abrirlo.
Claude Code — basta con un comando:
claude mcp add notes -- uv run --with "mcp[cli]" mcp run /chemin/absolu/vers/server.py
Escriba /mcp en una sesión para comprobar que notes está conectado.
Cursor — archivo .cursor/mcp.json en la raíz del proyecto:
{
"mcpServers": {
"notes": {
"command": "uv",
"args": ["run", "--with", "mcp[cli]", "mcp", "run", "/chemin/absolu/vers/server.py"]
}
}
}
VS Code — archivo .vscode/mcp.json; la clave es servers y cada entrada declara su tipo:
{
"servers": {
"notes": {
"type": "stdio",
"command": "uv",
"args": ["run", "--with", "mcp[cli]", "mcp", "run", "/chemin/absolu/vers/server.py"]
}
}
}
Estos comandos y archivos proceden de la página Connect to a real host de la documentación oficial. Para instalar un servidor ya existente, en lugar de uno propio, consulte Instalar un servidor MCP en Claude, ChatGPT o Cursor.
Paso 5: probarlo con una tarea real
Pídale a su asistente: «Busque en mis notas qué se decidió sobre el presupuesto y resúmalo». Debería llamar a chercher_notes con «presupuesto» y después a lire_note para leer los archivos encontrados. También debería pedirle autorización antes de cada llamada si su aplicación anfitriona está configurada para ello. Mantenga activada esta confirmación hasta haber observado el comportamiento del servidor durante varios días.
Problemas frecuentes
| Síntoma | Causa probable | Solución |
|---|---|---|
| El servidor no aparece en la aplicación anfitriona | Se ha indicado una ruta relativa a server.py | Utilice la ruta absoluta y reinicie la aplicación |
| La aplicación anfitriona muestra «command not found: uv» | La aplicación inicia el servidor con un PATH mínimo | Sustituya uv por su ruta absoluta (which uv o where uv) |
| Nada cambia después de modificar la configuración | La aplicación lee su configuración al iniciarse | Cierre la aplicación por completo y vuelva a abrirla |
| El servidor falla en la primera llamada | Un print() escribe en la salida estándar, reservada al protocolo cuando se usa stdio | Envíe los registros a la salida de error (sys.stderr) o utilice logging |
ImportError: mcp.server.fastmcp | El código se escribió para el SDK v1 | Cambie la importación a from mcp.server import MCPServer |
Ejecute también el comando de inicio manualmente: un servidor stdio que funciona correctamente no muestra nada y queda a la espera. Una traza de error o un cierre inmediato revelan el problema de fondo.
Para seguir avanzando
- Compartirlo:
uv run mcp run server.py --transport streamable-httppublica el mismo servidor por HTTP enhttp://localhost:8000/mcp. Antes de exponerlo a Internet, añada autenticación —el SDK admite OAuth— y limite las acciones que puede realizar cada herramienta. - Probarlo automáticamente: el SDK proporciona un
Clientque se conecta directamente al objetomcpen memoria, sin procesos ni puertos. Resulta práctico para las pruebas conpytest. - Publicarlo: el registro oficial de MCP incluye servidores públicos; nuestro directorio de servidores MCP los recoge junto con la actividad de sus repositorios y un nivel de riesgo.
- Elegir uno en lugar de programarlo: quizá ya exista un servidor para lo que necesita. La guía Elegir un servidor MCP explica cómo comprobar que sigue recibiendo mantenimiento y que es seguro. El artículo MCP y skills maliciosos: qué revisar antes de instalar detalla los riesgos que conviene detectar.
Lista de comprobación antes de usarlo a diario
- El servidor funciona por separado (
mcp dev) y cada herramienta tiene una docstring clara - Las rutas, direcciones o consultas aceptadas se limitan a lo estrictamente necesario
- Ninguna herramienta elimina, envía ni realiza pagos sin confirmación humana
- No hay ningún secreto, como una clave de API o una contraseña, escrito en
server.py: se proporcionan mediante variables de entorno - La ruta a
server.pyen la configuración de la aplicación anfitriona es absoluta - Ha completado el diagnóstico de seguridad de agentes de IA para revisar toda su configuración
Preguntas frecuentes
¿Hay que saber programar para crear un servidor MCP?
Necesita conocer los fundamentos de Python o TypeScript: escribir una función, instalar un paquete y ejecutar un script. El SDK oficial se encarga del protocolo, del esquema de los parámetros y de la validación: bastan unas treinta líneas para crear un servidor útil.
¿Python o TypeScript para un servidor MCP?
Ambos SDK son oficiales y los mantiene el proyecto Model Context Protocol. Elija el lenguaje de la herramienta que quiera exponer: Python para scripts de datos o automatización, y TypeScript si su código actual está en Node.js. El protocolo es el mismo; el cliente no percibe ninguna diferencia.
¿Pueden otras personas utilizar mi servidor MCP?
En local, con el transporte stdio, solo lo ejecuta su equipo. Para compartirlo, publique el mismo código mediante Streamable HTTP en una dirección web, con autenticación. El SDK proporciona el transporte, pero el alojamiento, el control de acceso y la seguridad siguen siendo responsabilidad suya.
¿Qué diferencia hay entre una herramienta y un recurso MCP?
Una herramienta es una función que el modelo decide invocar para realizar una acción o buscar información, como una petición POST. Un recurso es un dato que la aplicación carga en el contexto del modelo sin efectos secundarios, como una petición GET. Un tercer tipo, el prompt, es una plantilla de mensaje que el usuario activa por su nombre.