In this article
Comment créer un serveur MCP dans Node.js pour fournir une documentation API à jour
Si vous débutez avec le vibe coding, que vous souhaitez connecter des serveurs MCP en tant qu’intégrations et découvrir l’univers de l’IA agentique, vous êtes au bon endroit. Dans ce tutoriel, je vous montre comment créer un serveur MCP de base dans Node.js à l’aide du SDK officiel Anthropic Model Context Protocol (MCP).
Un serveur MCP pour une documentation de l’API Node.js à jour
Notre serveur MCP récupérera la documentation au format JSON depuis la documentation API officielle de Node.js (https://nodejs.org/api/) et la mettra à disposition sous forme d’outils appelables par des clients MCP, comme ceux intégrés à Claude Desktop, Cursor, Qodo et d’autres.
L’environnement d’exécution Node.js est régulièrement mis à jour et prend en charge de nouvelles méthodes et utilitaires, mais les LLM ne sont pas entraînés sur les données les plus récentes. Même lorsqu’ils peuvent parcourir le Web, ils peuvent choisir de ne pas le faire pour répondre à une question dont la réponse figure déjà dans leurs données d’entraînement, sauf si l’application hôte (comme Cursor) a été expressément invitée à le faire.
Nous allons donc créer un serveur MCP qui expose des outils dédiés à chacun des modules principaux intégrés à Node.js et des sections de la structure de la documentation API, afin que les clients MCP puissent les appeler.

Les fichiers du projet de serveur MCP
Commençons par les fichiers de base du projet de serveur MCP, notamment les métadonnées de dépendances et autres dans 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"
}
}Après avoir créé le fichier package.json avec le contenu ci-dessus, exécutez npm install pour récupérer les dépendances.
Initialiser un serveur MCP dans Node.js à l’aide du SDK TypeScript
Créez ensuite un fichier index.js et ajoutez-y le contenu suivant :
#!/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();Le code ci-dessus commence par la syntaxe UNIX shebang de Node.js, #!/usr/bin/env node, qui permet de rendre le fichier exécutable si vous souhaitez le lancer directement en ligne de commande, par exemple avec ./index.js. Ce n’est toutefois pas obligatoire.
Nous importons ensuite la définition du serveur MCP depuis le SDK TypeScript, le type de transport STDIO et le code d’initialisation d’un serveur de documentation auxiliaire, que nous détaillerons dans un instant. Puis, nous créons le serveur MCP et le connectons au transport STDIO du processus.
Récupérer les données et préparer les outils du serveur MCP
Que contient ./server/documentation-server.js ?
Voici comment définir des outils pour les serveurs 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))
}]
})
);Cependant, nous ne voulons pas appeler manuellement ces fonctions server.tool() pour chaque module Node.js intégré. Nous préférons parcourir l’ensemble des modules par programmation.
Pour ce faire, nous devons d’abord récupérer la référence de la documentation API Node.js sous forme de données JSON.
Dans la fonction initializeDocumentationServer, nous recevons la variable server (l’instance du serveur MCP), que nous pouvons ensuite transmettre aux différentes méthodes qui créent des définitions d’outils.
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);
}Pour récupérer la documentation API Node.js, voici l’implémentation de la fonction fetchNodeAPIDocs dans le fichier ../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, '');
}Lors de la récupération de la documentation, nous mettons également à disposition une fonction qui permet de rechercher facilement les modules par nom et de faire correspondre ce nom à l’une des propriétés ou conventions de nommage présentes dans l’objet JSON renvoyé par l’URL https://nodejs.org/docs/latest/api/all.json.
Définir les outils du serveur MCP
Nous pouvons maintenant traiter par programmation tous les modules principaux de Node.js à partir du fichier JSON et exposer un outil distinct pour chacun d’eux.
Voici le code de ./tools/documentation-tools.js, qui contient toutes les fonctions référencées dans le fichier 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');
}Déboguer le serveur MCP Node.js avec MCP Inspector
Pour vérifier que ce serveur fonctionne correctement et voir précisément à quoi ressemble la définition de nos outils, nous pouvons utiliser MCP Inspector d’Anthropic.
Ajoutez ce qui suit à la propriété scripts de votre fichier package.json :
{
"scripts": {
"debug": "npx @modelcontextprotocol/inspector node index.js --debug"
}
}Installez ensuite le package npm d’Anthropic @modelcontextprotocol/inspector parmi les dépendances de développement du projet :
npm install @modelcontextprotocol/inspector --save-devEnfin, lançons MCP Inspector en exécutant la commande suivante :
npm run debugAccédez à l’adresse de MCP Inspector pour voir tous les outils exposés et leurs définitions :

Et maintenant, que faire avec les serveurs MCP ?
Le code source complet d’un serveur MCP opérationnel pour la documentation API Node.js est disponible dans ce dépôt GitHub : https://github.com/snyk-labs/mcp-server-nodejs-api-docs. Il est à jour et inclut également la journalisation ainsi que des ressources de serveur MCP exposées, pour des exemples plus complexes de création de serveurs MCP.
Si vous cherchez des serveurs MCP auxquels vous connecter, ne passez pas à côté des garde-fous de sécurité IA de Snyk avec Snyk présente un serveur MCP, intégré à Snyk CLI. Vous pourrez ainsi adopter une approche plus proactive du vibe coding et du développement d’applications avec des assistants de code IA.
Demandez à Snyk d’auditer le code généré par votre assistant de code GenAI lorsqu’il suggère des dépendances open source ou du code. C’est aussi simple que ceci :
snyk mcp -t stdio --experimentalN’oubliez pas non plus que l’installation et la connexion de serveurs MCP peuvent introduire des risques de sécurité, exécuter du code arbitraire et entraîner d’autres problèmes.
Inscrivez-vous à Snyk API & Web
Adoptez dès aujourd’hui notre moteur DAST pensé pour les développeurs
Détectez et mettez en évidence automatiquement les vulnérabilités à grande échelle grâce au moteur DAST de Snyk basé sur l’IA. Intégrez la sécurité dès le début du cycle avec une automatisation et des conseils de correction qui s’intègrent parfaitement à votre SDLC.