llm-toolkit
Construye tu propio servidor MCP (y despliégalo)
Un servidor MCP completo y funcional que convierte una API de LLM en herramientas MCP, diseñado para ser enseñado. Se ejecuta localmente sobre stdio para Claude Desktop / Claude Code, y de forma remota sobre HTTP una vez que lo despliegues.
Respaldado por Groq — inferencia rápida, API compatible con OpenAI, nivel gratuito que soporta a una sala llena de estudiantes usándolo intensamente durante un taller.
Todo está en un solo archivo: server.py. ~170 líneas incluyendo comentarios.
Parte 0 — ¿Qué es MCP, en un minuto
MCP (Model Context Protocol) es una forma estándar de darle nuevas capacidades a un cliente de IA. Escribes un servidor; cualquier cliente MCP puede usarlo.
Un servidor puede exponer tres cosas:
Primitiva | Qué es | Quién la controla |
Tool | Una función que el modelo puede llamar | El modelo decide |
Resource | Datos de solo lectura que el cliente puede obtener | El cliente/app decide |
Prompt | Una plantilla de prompt reutilizable | El usuario la elige |
Dos transportes:
stdio — el cliente lanza tu servidor como un subproceso y se comunica a través de stdin/stdout. Local únicamente. Sin redes. Así es como funciona el 90% de los servidores MCP.
streamable HTTP — tu servidor es un servicio web en una URL. Esto es lo que despliegas para que otras personas (o clientes alojados) puedan usarlo.
El mismo server.py hace ambas cosas. Ese es todo el truco.
Parte 1 — Qué estamos construyendo
llm-toolkit: un servidor MCP que le da a cualquier cliente MCP cuatro herramientas impulsadas por LLM.
Herramienta | Hace |
| Haz una pregunta, elige conciso / detallado / para niños |
| Texto → N viñetas |
| Traduce, preservando markdown y bloques de código |
| Texto no estructurado → JSON estructurado |
Además de un recurso (config://server-info) y un prompt (code_review) para que los estudiantes
vean las tres primitivas.
Parte 2 — Ejecútalo localmente
Configuración
python -m venv .venvWindows: .\venv\Scripts\activate — macOS/Linux: source .venv/bin/activate
pip install -r requirements.txtObtén una clave gratuita en console.groq.com → API Keys. Luego copia
.env.example a .env y pégala:
cp .env.example .env.env está en gitignore. El servidor lo carga automáticamente desde su propio directorio, por lo que
funciona sin importar desde dónde lo lance el cliente.
Inspecciónalo antes de conectarlo
El Inspector MCP es la mejor herramienta de enseñanza: muestra la lista de herramientas y te permite llamar a las herramientas manualmente, sin necesidad de un cliente de IA.
npx @modelcontextprotocol/inspector python server.pyAbre la URL impresa, presiona Connect, luego List Tools. Verás las cuatro.
Parte 3 — Conéctalo a un cliente
Claude Code
claude mcp add llm-toolkit -e GROQ_API_KEY=gsk_... -- python /absolute/path/to/server.pyO confirma un .mcp.json en la raíz de tu proyecto para que todo el equipo lo tenga — consulta
.mcp.json.example.
Claude Desktop
Edita claude_desktop_config.json:
macOS —
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows —
%APPDATA%\Claude\claude_desktop_config.json
Pega el bloque mcpServers de .mcp.json.example, luego cierra y vuelve a abrir completamente
Claude Desktop. Las herramientas aparecen bajo el icono de herramientas.
Solo rutas absolutas. La razón #1 por la que un servidor MCP local "no aparece" es una ruta relativa — el directorio de trabajo del cliente no es el tuyo. Usa la ruta completa tanto para el binario de python (
.venv/bin/python) como paraserver.py.
Parte 4 — Despliégalo
Cambia al modo HTTP con una bandera:
python server.py --httpEl servidor ahora está en http://localhost:8000/mcp. Envía ese mismo comando en un contenedor.
Opción A — Render, sin Docker (recomendado)
Render tiene un entorno de ejecución nativo de Python. Sin Dockerfile, sin compilación de contenedor. Instala
requirements.txt y ejecuta tu comando de inicio directamente. Este es el camino más rápido desde
la laptop a una URL pública.
Paso 1 — sube el código a GitHub.
git init && git add -A && git commit -m "MCP server"Crea un repositorio vacío en github.com/new, luego:
git remote add origin https://github.com/<you>/llm-toolkit-mcp.git && git push -u origin mainPaso 2 — crea el servicio.
Panel de Render → New → Web Service → conecta el repositorio. Render lee
render.yaml y se configura solo:
Configuración | Valor |
Runtime | Python (no Docker) |
Build command |
|
Start command |
|
Paso 3 — establece la clave. Panel → Environment → añade GROQ_API_KEY. Está marcada
como sync: false en render.yaml, por lo que vive solo en el panel, nunca en git.
Paso 4 — despliega. Tu endpoint público es https://<tu-app>.onrender.com/mcp.
Sin health check a propósito.
GET /mcpabre un flujo SSE que permanece abierto por diseño. Un health check apuntando a él se cuelga, y Render interpreta el tiempo de espera como un servicio muerto y lo reinicia en bucle. ConhealthCheckPathomitido, Render solo verifica que el proceso enlace$PORT— la verificación correcta para este servidor.
Las instancias del nivel gratuito se duermen después de ~15 min de inactividad. La primera llamada después de un sueño toma ~30–50s mientras se despierta. Algunos clientes MCP agotan el tiempo de espera antes de eso e informan que el servidor está roto. Caliéntalo con un curl antes de que comience la clase.
Opción B — Otros hosts sin Docker
Host | Cómo |
Railway | Conecta el repositorio. Nixpacks detecta automáticamente Python. Establece el comando de inicio en |
Hugging Face Spaces | Gratuito, sin sueño. Docker Space, o Gradio Space con un |
Google Cloud Run |
|
Cualquier VPS |
|
Opción C — Fly.io
fly launch --no-deployfly secrets set GROQ_API_KEY=gsk_...fly deployEndpoint: https://<tu-app>.fly.dev/mcp
Opción D — Cualquier host de contenedores
El Dockerfile se mantiene para los hosts que quieran un contenedor. Funciona en
Railway, Cloud Run, ECS, un VPS:
docker build -t llm-toolkit-mcp .docker run -p 8000:8000 -e GROQ_API_KEY=gsk_... llm-toolkit-mcpVerifica el despliegue
Un curl prueba que el servidor está vivo y hablando MCP:
curl -X POST https://your-app.onrender.com/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'Deberías recibir un bloque serverInfo nombrando llm-toolkit.
Conecta un cliente al servidor desplegado
claude mcp add --transport http llm-toolkit https://your-app.onrender.com/mcpLos estudiantes pegan esa línea y al instante tienen tus cuatro herramientas. Ese es el momento culminante de todo el taller — sin instalación, sin clave, sin Python en su máquina.
Compartirlo públicamente — lee esto primero
Un servidor MCP desplegado sin autenticación está abierto a todo internet. Cualquiera que aprenda la URL puede llamar a tus herramientas, y cada llamada gasta tu cuota de Groq.
Para un taller, eso suele estar bien, y el nivel gratuito de Groq es lo que lo hace estar bien: cuando la cuota se agota, recibes errores HTTP 429, no una factura. El modo de fallo es "las herramientas dejan de responder", no "factura sorpresa".
Deja de estar bien en el momento en que pones una clave de pago detrás. Luego añade autenticación antes de
compartir la URL — el parámetro auth del SDK de MCP, o una puerta de enlace API al frente.
Dos hábitos que vale la pena mantener de cualquier manera:
Trata la URL como semisecreta. Compártela en clase, no la publiques públicamente.
Rota la clave después del taller. Es un clic en el panel.
Parte 5 — Cosas que vale la pena enseñar explícitamente
El docstring es la API. El modelo elige herramientas leyendo el docstring y las indicaciones de tipo. Un docstring vago significa una herramienta que nunca se llama. Esto es lo que tiene mayor impacto en todo el archivo.
Una función es dueña del proveedor. Cada herramienta llama a call_llm(). Cambiar Groq por
OpenAI, Anthropic, o un Ollama local significa editar esa única función — las cuatro herramientas nunca cambian.
Haz una demostración en vivo; causa una fuerte impresión.
Devuelve errores como cadenas, no los lances. call_llm captura GroqError y devuelve
el mensaje como texto. El cliente le muestra al usuario un error real en lugar de una llamada a herramienta muerta.
stateless_http=True significa que no hay sesiones fijas, por lo que el servidor escala detrás de un balanceador
de carga. Desactívalo solo si añades estado por sesión.
Nunca confirmes la clave. .env está en gitignore, render.yaml usa sync: false,
Fly usa fly secrets.
Los servidores HTTP públicos están abiertos por defecto. Este no tiene autenticación — está bien para una demo,
no para producción. Los despliegues reales añaden OAuth a través del parámetro auth del SDK, o se sientan
detrás de una puerta de enlace API.
La deriva de versiones es real. MCP Python SDK 2.0 renombró FastMCP a MCPServer. La mayoría de los
tutoriales en línea todavía muestran FastMCP y fallarán en una instalación nueva. Buen momento para
enseñar a leer el paquete instalado en lugar de confiar en una publicación de blog.
Parte 6 — Ejercicios para la clase
Añade una herramienta
sentiment(text). (Copiasummarize, cambia el prompt del sistema.)Haz que
ask_llmacepte un argumentomax_tokensy observa cómo el esquema se actualiza automáticamente en el Inspector.Apunta
call_llma un proveedor diferente sin tocar ninguna herramienta.Añade un recurso
config://usageque informe cuántas llamadas a herramientas ha servido el proceso. (Pista: un contador a nivel de módulo.)Rompe un docstring a propósito, luego pídele al modelo que use esa herramienta. Observa cómo falla al seleccionar la herramienta. Esa es la lección.
Parte 7 — Conseguir que otras personas lo usen
Entregar las herramientas a otra persona son tres problemas separados: accesible, conectable, descubrible. Resuélvelos en ese orden.
1. Accesible. Un servidor en localhost es utilizable por exactamente una persona. Despliégalo
(Parte 4) y tendrás una URL pública. Nada de lo siguiente funciona hasta que esto esté hecho.
2. Conectable. Dale a la gente USING-IT.md — una página independiente con
configuración de copiar y pegar para Claude Code, Claude Desktop y Cursor, además de una tabla
de solución de problemas. Para un taller, la ruta remota es la que se debe usar: los estudiantes pegan una línea y
tienen herramientas funcionales sin Python, sin repositorio y sin clave API propia.
3. Descubrible. Solo si quieres que extraños lo encuentren, no solo tu clase:
Canal | Qué obtienes |
Temas de GitHub | Tráfico de búsqueda gratuito |
El registro oficial de MCP | Listado en las interfaces "explorar servidores" del cliente |
Listas de la comunidad | PR para añadir tu repositorio |
Smithery / Glama y directorios similares | Botones de instalación alojados |
Los requisitos del registro cambian rápidamente — consulta la documentación actual del registro MCP para conocer el formato del manifiesto antes de publicar.
Una nota sobre el límite honesto. La gente adopta un servidor MCP cuando hace algo que ya no pueden hacer. Este envuelve un LLM genérico, que la mayoría de los clientes ya tienen incorporado — perfecto para enseñar el protocolo, débil como producto. Un servidor que accede a tu base de datos, tu API interna, o tus datos propietarios es el que consigue usuarios reales. Vale la pena decirlo en voz alta a la clase.
Parte 8 — Qué lo hace listo para producción
La versión del taller y la versión de producción difieren en aspectos que no tienen nada que ver con MCP. Esta es la lista, y cada elemento existe debido a un fallo que realmente ocurrió mientras se construía este servidor.
Protegiendo la clave
Un endpoint MCP público es un endpoint de gasto público: cada llamada te cuesta a ti.
Guarda | Variable de entorno | Por defecto | Motivo |
Autenticación Bearer |
| vacío = abierto | Bloquear el acceso una vez que haya una clave de pago detrás |
Límite de tasa |
| 30/IP | Un script no puede agotar tu cuota |
Límite de entrada |
| 20000 | Una novela pegada se rechaza antes de que cueste tokens |
Límite de cuerpo |
| 1 MB | Los payloads sobredimensionados mueren antes de analizarse |
La autenticación está desactivada por defecto para que el servidor permanezca abierto para un taller con una clave gratuita. Actívala antes de apuntar una clave de pago a una URL pública:
MCP_AUTH_TOKEN=$(python -c "import secrets;print(secrets.token_urlsafe(32))") python server.py --httpLos clientes envían entonces Authorization: Bearer <token>.
Sobreviviendo al proveedor
Los modelos se retiran sin previo aviso. Groq eliminó llama-3.3-70b-versatile durante el desarrollo: funcionaba a las 07:15 y daba un 404 una hora después. Todas las herramientas se rompieron a la vez, y un 404 se lee como "tu servidor está roto", no como "el proveedor se movió".
MODEL_CHAIN soluciona esto: en un error de modelo no encontrado, la llamada pasa al siguiente modelo en lugar de fallar. Otros errores (una clave incorrecta, un límite de tasa) fallan rápidamente, porque reintentarlos en cinco modelos solo pierde tiempo.
Los tiempos de espera (LLM_TIMEOUT_SECONDS) y los reintentos (LLM_MAX_RETRIES) se entregan a los SDK del proveedor, que ya implementan la retirada correctamente.
Comprobaciones de salud
/health devuelve JSON simple. Nunca hagas una comprobación de salud a /mcp — es un flujo SSE que permanece abierto por diseño, por lo que el sondeo se cuelga, la plataforma declara muerto el servicio y obtienes un bucle de reinicio que parece un fallo. Esto costó un ciclo de depuración real aquí.
Registro
Todo va a stderr, nunca a stdout. En modo stdio, stdout transporta el flujo JSON-RPC, por lo que un solo print() extraviado corrompe el protocolo. Esta es la forma más común de romper un servidor MCP mientras se depura.
El middleware a nivel MCP registra cada método con su duración y funciona para ambos transportes.
Pruebas e IC
pytest tests/ se ejecuta sin conexión, sin clave API y no gasta nada. Cubre la caducidad de la ventana del limitador de tasa, los límites de entrada, la alternativa de modelo, la preservación del esquema de herramientas y la validación de configuración.
GitHub Actions ejecuta el conjunto en 3.11 y 3.12, inicia el servidor y escanea todo el historial de git en busca de claves API comprometidas — el fallo que es irrecuperable, porque una clave enviada es pública en el momento en que llega.
Limitaciones conocidas
Vale la pena ser honesto con una clase sobre lo que aún falta:
El límite de tasa es por proceso. Escala a N instancias y permites N veces el límite. Cambia a Redis antes de que importe.
Un token compartido, no claves por usuario. Está bien para una clase, no para clientes.
Sin medición de uso. No puedes saber quién gastó qué.
Los arranques en frío del nivel gratuito aún tardan 30–50s después de la inactividad.
Mapa de archivos
Archivo | Por qué existe |
| Todo el servidor — herramientas, recurso, prompt |
|
|
| Contenedor para cualquier host |
| Despliegue con un clic en Render |
| Despliegue en Fly.io |
| Qué variables de entorno existen |
| Configuración de cliente para copiar |
| Página independiente para entregar a los usuarios |
| Autenticación, límite de tasa, límites de tamaño, registro |
| Conjunto de pruebas sin conexión, no necesita clave API |
| IC: pruebas, comprobación de inicio, escaneo de secretos |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for AI dialogue using various LLM models via AceDataCloud
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aihunter9892/mcpserver'
If you have feedback or need assistance with the MCP directory API, please join our Discord server