In this article
Cómo crear un servidor MCP en Node.js para ofrecer documentación actualizada de la API
Si apenas estás comenzando con la programación por instrucciones (vibe coding), conectando servidores MCP como integraciones y explorando el mundo de la IA agéntica, estás en el lugar indicado. En este tutorial, quiero mostrarte cómo crear un servidor MCP básico en Node.js con el SDK oficial de Anthropic para Model Context Protocol (MCP).
Un servidor MCP para consultar documentación actualizada de la API de Node.js
Nuestro servidor MCP obtendrá la documentación de la API oficial de Node.js (https://nodejs.org/api/) en formato JSON y la ofrecerá como herramientas que pueden invocar clientes MCP, como los implementados por Claude Desktop, Cursor, Qodo y otros.
Esto es útil porque el entorno de ejecución de Node.js recibe actualizaciones periódicas y ofrece compatibilidad con nuevos métodos y utilidades, pero los LLM no se entrenan con los datos más recientes. Aunque los LLM puedan navegar por la web, quizá decidan no hacerlo para responder una pregunta cuyos datos ya conocen por su entrenamiento, a menos que se haya indicado específicamente a la aplicación anfitriona (como Cursor) que lo haga.
Así que vamos a crear un servidor MCP que exponga herramientas específicas para cada módulo principal integrado de Node.js y cada sección de la estructura de la documentación de la API, y permita que los clientes MCP las invoquen.

Los archivos del proyecto del servidor MCP
Comenzamos con los archivos básicos del proyecto del servidor MCP, como los metadatos de dependencias y otros elementos en package.json:
{
"name": "mcp-server-nodejs-docs",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"description": "A MCP server that provides documentation for Node.js core modules API",
"scripts": {
"start": "node index.js --debug"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0",
"pino": "^9.6.0",
"zod": "^3.24.4"
}
}Después de crear el archivo package.json con el contenido anterior, ejecuta npm install para descargar las dependencias.
Inicializar un servidor MCP en Node.js con el SDK de TypeScript
A continuación, crea un archivo index.js y agrega el siguiente contenido:
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { initializeDocumentationServer } from './server/documentation-server.js';
// Create an MCP server
const server = new McpServer({
name: "Node.js API Documentation",
version: "1.0.0",
capabilities: {
resources: {},
tools: {},
},
});
// Initialize the server with Node.js API documentation
async function startServer() {
try {
await initializeDocumentationServer(server);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
} catch (error) {
console.error(`Fatal error during server initialization. Check logs for details.`);
process.exit(1);
}
}
// Start the server
startServer();El código anterior comienza con la sintaxis de shebang de UNIX de Node.js, #!/usr/bin/env node, para que el archivo sea ejecutable si quieres ejecutarlo desde la línea de comandos como un ejecutable, por ejemplo, ./index.js. Sin embargo, esto no es obligatorio.
A continuación, importamos la definición del servidor MCP desde el SDK de TypeScript, el tipo de transporte STDIO y el código auxiliar que inicializa el servidor de documentación, que veremos en un momento. Luego creamos el servidor MCP y lo conectamos al tipo de transporte STDIO del proceso.
Obtener datos y preparar las herramientas del servidor MCP
¿Qué contiene ./server/documentation-server.js?
Así se definen las herramientas para los servidores MCP:
// Math tool to find the maximum of two numbers
server.tool(
"math-find-maximum-two-numbers",
{
number1: z.number(),
number2: z.number()
},
async ({ number1, number2 }) => ({
content: [{
type: "text",
text: Math.max(number1, number2))
}]
})
);Sin embargo, no queremos llamar manualmente a estas funciones server.tool() para cada módulo integrado de Node.js, sino recorrerlos todos de manera programática.
Para hacerlo, primero tenemos que obtener la referencia de la documentación de la API de Node.js como datos JSON.
En la función initializeDocumentationServer, recibimos la variable server (la instancia del servidor MCP), que luego podemos pasar a los distintos métodos que crean definiciones de herramientas en él.
import { fetchNodeApiDocs } from '../services/api-docs-service.js';
import { createModuleTool, createSearchTool, createListTool } from '../tools/documentation-tools.js';
export async function initializeDocumentationServer(server) {
const apiDocs = await fetchNodeApiDocs();
// Remove entries without Class or Method
const originalCount = apiDocs.modules?.length;
apiDocs.modules = apiDocs.modules.filter(module =>
module?.classes?.length > 0 || module?.methods?.length > 0
);
// Create tools for each module
apiDocs.modules.forEach(module => {
createModuleTool(server, module);
});
// Create search and list tools
createSearchTool(server, apiDocs.modules);
createListTool(server, apiDocs.modules);
}Para obtener la documentación de la API de Node.js, esta es la implementación de la función fetchNodeAPIDocs del archivo ../services/api-docs-service.js:
const url = 'https://nodejs.org/docs/latest/api/all.json';
export async function fetchNodeApiDocs() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
// TODO later implement with logging etc
throw error;
}
}
export function findModuleByName(modules, searchName) {
const normalizedSearch = normalizeModuleName(searchName);
return modules.find(module =>
normalizeModuleName(module.name) === normalizedSearch ||
normalizeModuleName(module.textRaw) === normalizedSearch ||
(module.displayName && normalizeModuleName(module.displayName) === normalizedSearch)
);
}
export function normalizeModuleName(name) {
return name.toLowerCase().replace(/[_\s-]/g, '');
}Al obtener la documentación, también ponemos a disposición una función para encontrar fácilmente módulos por nombre y compararlos con una de las propiedades de nombre o patrones que existen en el objeto JSON devuelto por la URL https://nodejs.org/docs/latest/api/all.json.
Definición de las herramientas del servidor MCP
Ahora podemos procesar de forma programática todos los módulos principales de Node.js del archivo JSON y exponer cada uno como una herramienta independiente.
A continuación, se muestra el código de ./tools/documentation-tools.js, que incluye todas las funciones mencionadas en el archivo documentation-server.js:
import { z } from "zod";
import { findModuleByName } from '../services/api-docs-service.js';
function createModuleDocumentation(module, { class: classQuery, method: methodQuery } = {}) {
let content = `# ${module.textRaw}\n\n`;
if (module.desc) {
content += `## Description\n${formatContent(module.desc)}\n\n`;
}
const formatItems = (items, title, query) => {
if (!items || items.length === 0) return '';
const filteredItems = query
? items.filter(item =>
item.textRaw.toLowerCase().includes(query.toLowerCase()) ||
(item.desc && item.desc.toLowerCase().includes(query.toLowerCase()))
)
: items;
if (filteredItems.length === 0) return '';
let sectionContent = `## ${title}\n\n`;
filteredItems.forEach(item => {
sectionContent += `### ${item.textRaw}\n`;
if (item.desc) sectionContent += `${formatContent(item.desc)}\n\n`;
});
return sectionContent;
};
content += formatItems(module.classes, 'Classes', classQuery);
content += formatItems(module.methods, 'Methods', methodQuery);
content += formatItems(module.modules, 'Submodules');
return content;
}
export function createModuleTool(server, module) {
const { name, textRaw } = module;
const toolName = `node-${name.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-')}`;
server.tool(
toolName,
{
class: z.string().optional(),
method: z.string().optional()
},
async (params) => {
try {
const content = createModuleDocumentation(module, params);
return { content: [{ type: "text", text: content }] };
} catch (error) {
// TODO
throw error;
}
}
);
}
export function createSearchTool(server, modules) {
server.tool(
"node-search",
{ module: z.string().optional() },
async (params) => {
const moduleName = params?.module;
const foundModule = moduleName ? findModuleByName(modules, moduleName) : null;
if (!foundModule) {
let listContent = 'Available Node.js core modules and their methods:\n\n';
modules.forEach(module => {
listContent += formatModuleSummary(module);
});
return { content: [{ type: "text", text: listContent }] };
}
const content = createModuleDocumentation(foundModule);
return { content: [{ type: "text", text: content }] };
}
);
}
export function createListTool(server, modules) {
server.tool(
"node-list",
{},
async () => {
const content = formatModulesList(modules);
return { content: [{ type: "text", text: content }] };
}
);
}
function formatModuleSummary(module) {
let content = `## ${module.displayName || module.textRaw} (${module.name})\n`;
if (module.methods && module.methods.length > 0) {
content += `### Methods\n`;
module.methods.forEach(method => {
content += `- ${method.textRaw}\n`;
});
} else {
content += `_No methods found_\n`;
}
return content + '\n';
}
function formatModulesList(modules) {
const modulesList = modules.map(module => ({
name: module.name,
displayName: module.displayName || module.textRaw,
description: module.desc || 'No description available'
}));
return `# Available Node.js Modules\n\n${modulesList.map(m =>
`## ${m.displayName}\n*Name:* ${m.name}\n*Description:* ${formatContent(m.description)}\n`
).join('\n')}`;
}
export function formatContent(content) {
if (!content) return '';
return content.replace(/\n/g, '\n\n');
}Depurar el servidor MCP de Node.js con MCP Inspector
Para comprobar si este servidor funciona correctamente y ver exactamente cómo se definen nuestras herramientas, podemos usar MCP Inspector de Anthropic.
Agrega lo siguiente a la propiedad scripts del archivo package.json:
{
"scripts": {
"debug": "npx @modelcontextprotocol/inspector node index.js --debug"
}
}A continuación, instala el paquete npm de Anthorpic @modelcontextprotocol/inspector como parte de las dependencias de desarrollo del proyecto:
npm install @modelcontextprotocol/inspector --save-devPor último, iniciemos MCP Inspector con el siguiente comando:
npm run debugAbre la dirección de MCP Inspector para ver todas las herramientas expuestas y sus definiciones:

¿Qué sigue para los servidores MCP?
El código fuente completo de un servidor MCP funcional para la documentación de la API de Node.js está disponible en este repositorio de GitHub: https://github.com/snyk-labs/mcp-server-nodejs-api-docs. Está actualizado e incluye registro de eventos y recursos del servidor MCP expuestos, además de ejemplos más complejos para crear servidores MCP.
Si buscas servidores MCP a los que conectarte, no te pierdas las barreras de seguridad de IA de Snyk con Snyk presenta un servidor MCP como parte de Snyk CLI. Así podrás adoptar un enfoque más proactivo al programar con instrucciones (vibe coding) y crear aplicaciones con asistentes de código con IA.
Pídele a Snyk que audite el código que sugiera tu asistente de código de IA generativa cuando recomiende dependencias de código abierto y código, así de fácil:
snyk mcp -t stdio --experimentalAdemás, no olvides que instalar y conectar servidores MCP puede introducir riesgos de seguridad, ejecutar código arbitrario y causar otros problemas.
Regístrate en Snyk API & Web
Empieza a usar hoy nuestro motor DAST diseñado para desarrolladores
Encuentra y expón vulnerabilidades automáticamente y a escala con el motor DAST de Snyk impulsado por IA. Adelanta la seguridad con automatización y orientación para corregir problemas, integradas sin fricciones en tu ciclo de vida de desarrollo de software.