IronMCP Framework Starter
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@IronMCP Framework Startercreate a new tool for subscriber data balance"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
IronMCP Framework Starter
Starter empresarial para crear servidores MCP en Node.js + TypeScript con:
Transporte
stdiopara clientes locales.Transporte
httpcon Streamable HTTP stateless.Configuracion por YAML + variables de entorno.
Logs estructurados con Pino.
REST client centralizado con autenticacion.
Validadores de codigo y seguridad.
Contrato obligatorio para tools: schema, auth, timeout, auditoria e idempotencia.
Skill para crear tools con ayuda de una IA siguiendo las convenciones del framework.
Tool
get_weatherpara consultar el clima por ciudad y resolver ubicaciones ambiguas.
Requisitos
Node.js
22.22.1+(rama 22),24.xo26+npm
>=10
Related MCP server: Kroki MCP
Inicio rapido
npm install
cp .env.example .env
# Configura MCP_AUTH_TOKEN en .env con un token aleatorio antes de arrancar HTTP.
npm run validatePara probar HTTP:
npm run dev:httpEn otra terminal:
bash scripts/smoke-http.shHealth check HTTP normal:
curl http://127.0.0.1:3000/healthzPara probar STDIO con MCP Inspector:
npm run build
npm run mcp:inspect:stdioProbar con un túnel de VS Code
Con el servidor activo en el puerto 3000, reenvía ese puerto desde el panel Ports de VS Code. Los túneles son privados de forma predeterminada: Postman o un cliente externo puede recibir una redirección al login de GitHub. Si necesitas acceso sin esa sesión, cambia Port Visibility > Public durante la prueba. Un puerto público permite que cualquiera con la URL acceda al servicio; conserva la autenticación MCP para las tools protegidas.
Autoriza el hostname exacto del túnel en .env, sin protocolo ni ruta, y reinicia el servidor:
HTTP_HOST=127.0.0.1
HTTP_ALLOWED_HOSTS=your-tunnel-3000.use2.devtunnels.msEl servidor mantiene la validación de Host y permite también localhost; no es necesario escuchar en 0.0.0.0. Si cambia la dirección del túnel, actualiza la lista. En Postman configura mcp_url como https://your-tunnel-3000.use2.devtunnels.ms/mcp. Para comprobar únicamente el estado, usa GET https://your-tunnel-3000.use2.devtunnels.ms/healthz. Deja VS Code y el servidor ejecutándose mientras pruebas.
Probar la tool REST autenticada
El proyecto trae una tool llamada call_secure_api. Por defecto llama a https://httpbin.org/bearer, que espera un header Authorization: Bearer <token>.
Edita .env:
API_AUTH_TYPE=bearer-env
API_TOKEN=demo-token
API_BASE_URL=https://httpbin.orgLuego ejecuta:
npm run dev:http
bash scripts/smoke-http.sh examples/http/call-secure-api.jsonClima actual: get_weather
Consulta condiciones actuales modeladas por Open-Meteo para uso no comercial, sin API key. El servicio gratuito tiene límites de uso; consulta sus condiciones. Los datos requieren atribución CC BY 4.0, incluida en la salida de la tool. Las condiciones actuales proceden de modelos meteorológicos y pueden diferir de una observación local.
Parámetros de entrada:
Parámetro | Obligatorio | Descripción |
| Sí | Nombre de la ciudad, de 2 a 120 caracteres, sin país ni región. |
| No | Código ISO del país de dos letras, por ejemplo |
| No | Entero positivo elegido entre los candidatos de una respuesta anterior. |
La búsqueda exige coincidencia del nombre sin distinguir mayúsculas ni acentos. No acepta URLs ni rutas.
La tool requiere un principal autenticado con weather:read. Para habilitarla,
añade tú ese scope a MCP_AUTH_SCOPES, conservando los permisos que necesites para
las otras tools. Por ejemplo, para habilitar las tools incluidas:
MCP_AUTH_SCOPES=external-api:read,billing:read,weather:readReinicia el servidor con npm run dev:http después de cambiar la configuración. Si ya está ejecutándose, detenlo antes con Ctrl+C. La integración no modifica .env, tokens ni los permisos concedidos a los clientes existentes.
Usa context.restClient con dos destinos públicos fijos y sin headers de
autenticación externos: https://geocoding-api.open-meteo.com/v1/search y
https://api.open-meteo.com/v1/forecast. Estos destinos solo permiten GET a esas
rutas; no reutilizan API_TOKEN, API_KEY ni cambian API_BASE_URL. Conservan
cancelación, timeout, bloqueo de redirecciones y límite de respuesta del cliente.
Ejemplo: tools/call. Envía el JSON con
POST /mcp, Bearer MCP y headers Content-Type: application/json y
Accept: application/json, text/event-stream. El transporte es stateless, no
requiere sesión y puede devolver eventos SSE. GET /healthz solo consulta el
estado HTTP. La colección Postman
incluye la petición Clima actual — requiere weather:read, usando {{mcp_url}} y {{mcp_token}}. Vuelve a importar la colección actualizada si todavía no aparece.
Body JSON de ejemplo:
{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "Madrid",
"countryCode": "ES"
}
}
}Una consulta resuelta devuelve result.status: "ok" junto con city, country,
temperatureC, feelsLikeC y description en español, además de attribution
al nivel superior. Ante homónimos devuelve result.status: "needs_clarification",
un mensaje y candidates con ciudad, país, región si existe y locationId.
Repite la llamada con city y el locationId elegido; añadir solo el país puede
seguir siendo ambiguo. No consulta el clima hasta resolver la ubicación. Si la
búsqueda alcanza el límite de 100 resultados, marca truncated: true y solicita
precisión. Las ciudades ausentes, respuestas inválidas y fallos del proveedor se
propagan como errores MCP, sin fabricar datos meteorológicos.
Seguridad y permisos
HTTP requiere MCP_AUTH_TOKEN cuando MCP_AUTH_ENABLED=true; debe tener entre 32 y 256 caracteres ASCII sin espacios. Genera un token aleatorio con openssl rand -hex 32. Si falta o es inválido, el servidor falla al iniciar. El cliente debe enviar Authorization: Bearer <token>. Para el script de prueba, exporta MCP_AUTH_TOKEN en la terminal antes de ejecutar bash scripts/smoke-http.sh.
MCP_AUTH_SCOPES define los permisos del token, separados por comas (por ejemplo, external-api:read,billing:read). Cada tool comprueba sus permisos antes de ejecutar el handler. Si se desactiva la autenticación HTTP, solo se pueden ejecutar tools públicas. En STDIO, el proceso local es un cliente de confianza y recibe únicamente los scopes configurados.
La autenticación permite 10 intentos fallidos por dirección remota en una ventana de 60 segundos. Después devuelve 429 con Retry-After, incluso si el siguiente token es correcto, hasta finalizar la ventana. El registro tiene un máximo de 1024 direcciones y no confía en X-Forwarded-For. El límite vive en cada proceso; detrás de un proxy, las peticiones comparten la dirección de ese proxy.
HTTP opera sin sesiones: cada petición crea y cierra su servidor MCP; no se devuelve mcp-session-id. Se admiten hasta 100 peticiones simultáneas con un plazo máximo de 30 segundos.
Al vencer el timeout o cancelar una petición MCP, el framework aborta context.signal y el context.restClient asociado. Las tools deben consumir ese cliente del contexto. Para otras operaciones asíncronas, pasa context.signal a las APIs que admitan cancelación y comprueba context.signal?.throwIfAborted() antes de efectos posteriores. JavaScript no puede interrumpir de forma forzada código que ignora la señal; cancelar una petición tampoco revierte operaciones ya ejecutadas por la API externa.
RestClient usa por defecto rutas relativas del origen configurado en API_BASE_URL, bloquea URLs absolutas y redirecciones, y limita cada respuesta a 2 MiB. La integración de clima utiliza servicios públicos con destinos y rutas fijos, sin reenviar las credenciales de esa API. Los headers y parámetros de consulta no se escriben en los logs REST. La tool de demostración call_secure_api solo permite /bearer; para otros endpoints crea una tool con rutas y permisos específicos.
Scripts principales
npm run dev:stdio # arranca MCP por STDIO
npm run dev:http # arranca MCP por HTTP en /mcp
npm run build # compila TypeScript
npm run typecheck # valida tipos
npm run lint # ESLint
npm run format:check # Prettier check
npm run test # Vitest
npm run secrets:check # Secretlint
npm run knip # dependencias/codigo muerto
npm run mcp:validate # validador propio del estandar MCP
npm run validate # quality gate completoEstructura
src/
framework/
auth/ # proveedores de autenticacion
rest/ # REST client estandar
transports/ # STDIO y HTTP
config.ts # unico lugar permitido para process.env
create-mcp-server.ts # registro estandarizado de tools
errors.ts # errores normalizados
logger.ts # Pino; stderr cuando transport=stdio
types.ts # contrato de tools
tools/
health.tool.ts
call-secure-api.tool.ts
get-subscriber-balance.tool.ts
get-weather.tool.tsReglas del estandar
El validador propio tools/mcp-validate.mjs falla el build si detecta:
console.*ensrc/.process.envfuera desrc/framework/config.ts.fetch(fuera desrc/framework/rest/rest-client.ts.import directo de
axios.tools sin
inputSchema,timeoutMs,auth,audit,idempotentohandler.posibles secretos hardcodeados en
config/default.yamlo.env.example.
Crear tools con ayuda de una IA
La skill del repositorio está en .agents/skills/create-mcp-tool/SKILL.md. AGENTS.md indica a los agentes que la lean cuando se les solicite crear o ampliar una tool. Incluye el flujo de implementación, registro, permisos, cancelación, pruebas y ejemplos HTTP/Postman.
Puedes pedir: «Crea una tool para consultar un cliente usando GET /customers/{customerId}, con scope customers:read; implementa y valida el cambio». Incluye el contrato real de entrada y respuesta del endpoint. En clientes que permitan invocar skills por nombre, también puedes usar $create-mcp-tool.
La tool get_weather se agregó usando este flujo: la IA implementó la consulta por ciudad, su registro, las pruebas y los ejemplos a partir de la skill. Para otras tools, proporciona su propósito y el contrato de la integración que necesitas.
Si tu asistente no descubre skills ni lee AGENTS.md automáticamente, indícale que abra el SKILL.md anterior. El ejemplo completo de código y pruebas está en references/example.md; no se registra ninguna tool de demostración en el servidor por agregar esta guía.
Crear una nueva tool
Copia src/tools/health.tool.ts y cambia:
export const myTool = defineTool({
name: "my_tool",
title: "My Tool",
description: "Descripcion clara para el modelo.",
inputSchema: {
id: z.string(),
},
timeoutMs: 5000,
idempotent: true,
auth: {
required: true,
scopes: ["my-domain:read"],
},
audit: {
category: "read",
pii: false,
},
async handler(input, context) {
return context.restClient.get(`/items/${input.id}`);
},
});Luego registra la tool en src/tools/index.ts.
Notas importantes sobre STDIO
Cuando transport=stdio, el servidor MCP usa stdin/stdout para JSON-RPC. Por eso este starter manda logs a stderr y prohibe console.log en src/.
Siguiente paso sugerido
Cuando este starter ya funcione para tu equipo, el siguiente paso es convertir src/framework en paquete interno, por ejemplo @company/mcp-framework, y crear un CLI create-mcp que genere nuevos MCPs con esta misma estructura.
Crear una nueva tool: consultar balance de datos móviles
Esta guía muestra cómo crear una tool MCP que consume este endpoint REST:
GET /api/v2.0/mobile/upselling/subscribers/{subscriberId}/balances/data?_format=json&load_roaming=false&onlinetetheringquota=falseLa tool se llamará:
get_subscriber_data_balanceImportante: nunca colocar el Bearer token directamente en el código. El token debe ir en
.env.
1. Configurar variables de entorno
Editar el archivo .env:
API_BASE_URL=https://www.juliomorales.dev/apirest
API_AUTH_TYPE=bearer-env
API_TOKEN=TU_TOKEN_AQUI2. Crear el archivo de la tool
Crear el archivo:
src/tools/get-subscriber-data-balance.tool.tsAgregar este código:
import * as z from "zod/v4";
import { defineTool } from "../framework/types.js";
const getSubscriberDataBalanceInputSchema = z.object({
subscriberId: z.string().min(8).describe("Número de suscriptor. Ejemplo: 50230448966"),
});
export function createGetSubscriberDataBalanceTool() {
return defineTool({
name: "get_subscriber_data_balance",
title: "Get Subscriber Data Balance",
description:
"Consulta el balance de datos móviles disponibles, usados y vencimiento de un suscriptor Guatemala.",
inputSchema: {
subscriberId: z.string().min(8).describe("Número de suscriptor. Ejemplo: 50230448966"),
},
outputSchema: {
description: z.string().optional(),
remainingValue: z.number().optional(),
remainingFormatted: z.string().optional(),
usedValue: z.number().optional(),
usedFormatted: z.string().optional(),
reservedValue: z.number().optional(),
reservedFormatted: z.string().optional(),
expiresAt: z.string().optional(),
expiresIn: z.string().optional(),
includedApps: z.array(z.string()).optional(),
onlineTetheringFormatted: z.string().optional(),
raw: z.unknown(),
},
timeoutMs: 10000,
idempotent: true,
auth: {
required: true,
scopes: ["upselling:read", "balances:read"],
},
audit: {
category: "external-api",
pii: true,
},
async handler(input, context) {
const parsedInput = getSubscriberDataBalanceInputSchema.parse(input);
const response = await context.restClient.get<{
data?: {
local?: {
description?: {
value?: string;
formattedValue?: string;
};
summaryRemainingValue?: {
value?: number;
formattedValue?: string;
};
summaryReservedAmount?: {
value?: number;
formattedValue?: string;
};
summaryUsedValue?: {
value?: number;
formattedValue?: string;
};
summaryDateValue?: {
value?: string;
formattedValue?: string;
};
includedApps?: {
tags?: {
value?: string[];
};
};
onlineTethering?: {
label?: string;
value?: number;
};
};
};
}>(
`/api/v2.0/mobile/upselling/subscribers/${encodeURIComponent(
parsedInput.subscriberId,
)}/balances/data?_format=json&load_roaming=false&onlinetetheringquota=false`,
{
headers: {
Referer: "https://www.juliomorales.dev/",
Accept: "application/json, text/plain, */*",
},
},
);
const local = response.data?.local;
return {
description: local?.description?.formattedValue ?? local?.description?.value,
remainingValue: local?.summaryRemainingValue?.value,
remainingFormatted: local?.summaryRemainingValue?.formattedValue,
usedValue: local?.summaryUsedValue?.value,
usedFormatted: local?.summaryUsedValue?.formattedValue,
reservedValue: local?.summaryReservedAmount?.value,
reservedFormatted: local?.summaryReservedAmount?.formattedValue,
expiresAt: local?.summaryDateValue?.value,
expiresIn: local?.summaryDateValue?.formattedValue,
includedApps: local?.includedApps?.tags?.value,
onlineTetheringFormatted: local?.onlineTethering?.label,
raw: response,
};
},
});
}3. Registrar la tool
Editar:
src/tools/index.tsDebe quedar similar a esto:
import { callSecureApiTool } from "./call-secure-api.tool.js";
import { createGetSubscriberBalanceTool } from "./get-subscriber-balance.tool.js";
import { createGetSubscriberDataBalanceTool } from "./get-subscriber-data-balance.tool.js";
import { healthTool } from "./health.tool.js";
export function createTools() {
return [
healthTool,
callSecureApiTool,
createGetSubscriberBalanceTool(),
createGetSubscriberDataBalanceTool(),
];
}4. Crear ejemplo HTTP para probar
Crear el archivo:
examples/http/call-subscriber-data-balance.jsonCon este contenido:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_subscriber_data_balance",
"arguments": {
"subscriberId": "50230448966"
}
}
}5. Validar el código
Ejecutar:
npm run validateSi todo está correcto, debe pasar:
mcp:validate
typecheck
lint
format:check
test
secrets:check6. Levantar el servidor HTTP
npm run dev:http7. Probar la tool
En otra terminal:
bash scripts/smoke-http.sh examples/http/call-subscriber-data-balance.jsonLa respuesta debe incluir información como:
{
"description": "30GB + REDES SOCIALES + MUSICA + SPORTS",
"remainingFormatted": "15.48 GB",
"usedFormatted": "14.52 GB",
"reservedFormatted": "30 GB",
"expiresIn": "11 días, 10 horas",
"includedApps": ["WHATSAPP Incluido", "Redes Sociales", "Entretenimiento"]
}Reglas importantes para developers
No usar
fetchdirecto.No usar
axiosdirecto.No colocar tokens en código.
Siempre usar
RestClient.Siempre validar input con Zod dentro del
handler.Toda tool debe tener:
namedescriptioninputSchemaoutputSchematimeoutMsauthauditidempotent
Siempre ejecutar:
npm run validateConventional Commits
IronMCP utiliza Conventional Commits.
Ejemplos:
git commit -m "feat: add MCP authentication middleware"
git commit -m "fix: resolve HTTP transport issue"
git commit -m "docs: update README"
git commit -m "refactor: simplify tool registration"
❤️ Support IronMCP
If IronMCP helps you build better MCP servers, consider supporting the project.
Your contribution helps maintain the framework, add new features, improve documentation, and keep the project open source.
Donate via PayPal
Or send a donation directly to:
info@nworldt.netEvery contribution, no matter the size, helps keep IronMCP growing.
Thank you for your support! 🚀
Knip conserva los exports del framework usados dentro de su propio archivo. El preset de Secretlint se declara en ignoreDependencies porque se carga dinámicamente desde .secretlintrc.json; secrets:check valida su ejecución.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
A MCP server built for developers enabling Git based project management with project and personal…
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
One OAuth connector for your team's remote MCP servers, with Tool Packs, guardrails and logs.
Related MCP Servers
- FlicenseBqualityDmaintenanceAn MCP server framework featuring dynamic tool loading and a modular one-tool-per-file architecture for rapid development. It supports both Stdio and HTTP transport modes, offering automated test generation and centralized configuration management.11-
- AlicenseNot gradedqualityDmaintenanceA production-ready MCP server scaffold that features built-in authentication, Docker support, and a comprehensive CI/CD release pipeline. It provides a standardized template for deploying servers with multi-transport support and configurable read-only modes.MIT
- AlicenseNot gradedqualityDmaintenanceA modular framework for building and running multiple MCP servers with file operations, system information, and extensible tool/prompt/resource support.MIT
- AlicenseNot gradedqualityDmaintenanceA flexible, extensible framework for building MCP servers with API key authentication, user management, and dynamic tool sharing.7 npm11MIT