NestJS MCP Server Module

Un módulo de NestJS para construir servidores MCP que exponen herramientas y recursos para IA, con soporte para múltiples tipos de transporte.

Documentación

Módulo de Servidor MCP para NestJS

CI Code Coverage NPM Version NPM Downloads NPM License

Un módulo de NestJS para exponer sin esfuerzo herramientas, recursos y prompts para IA, desde tus aplicaciones NestJS utilizando el Protocolo de Contexto de Modelo (MCP).

Con @rekog/mcp-nest defines herramientas, recursos y prompts de una manera familiar en NestJS y aprovechas todo el poder de la inyección de dependencias para utilizar tu código existente en la construcción de servidores MCP complejos listos para empresas.

Características

  • 🚀 Soporte para todos los tipos de transporte:
    • HTTP Streamable
    • HTTP+SSE
    • STDIO
  • 🔍 Descubrimiento y registro automático de tool, resource y prompt
  • 💯 Validación de llamadas a herramientas basada en Zod
  • 📊 Notificaciones de progreso
  • 🔒 Autenticación basada en guards
  • 🌐 Acceso a la información de solicitudes HTTP dentro de los Recursos MCP (Herramientas, Recursos, Prompts)

Instalación

npm install @rekog/mcp-nest @modelcontextprotocol/sdk zod

Inicio Rápido

1. Importar Módulo

// app.module.ts
import { Module } from '@nestjs/common';
import { McpModule } from '@rekog/mcp-nest';
import { GreetingTool } from './greeting.tool';

@Module({
  imports: [
    McpModule.forRoot({
      name: 'my-mcp-server',
      version: '1.0.0',
    }),
  ],
  providers: [GreetingTool],
})
export class AppModule {}

2. Definir Herramientas y Recursos

// greeting.tool.ts
import type { Request } from 'express';
import { Injectable } from '@nestjs/common';
import { Tool, Resource, Context } from '@rekog/mcp-nest';
import { z } from 'zod';
import { Progress } from '@modelcontextprotocol/sdk/types';

@Injectable()
export class GreetingTool {
  constructor() {}

  @Tool({
    name: 'hello-world',
    description:
      'Returns a greeting and simulates a long operation with progress updates',
    parameters: z.object({
      name: z.string().default('World'),
    }),
  })
  async sayHello({ name }, context: Context, request: Request) {
    const userAgent = request.get('user-agent') || 'Unknown';
    const greeting = `Hello, ${name}! Your user agent is: ${userAgent}`;
    const totalSteps = 5;
    for (let i = 0; i < totalSteps; i++) {
      await new Promise((resolve) => setTimeout(resolve, 100));

      // Send a progress update.
      await context.reportProgress({
        progress: (i + 1) * 20,
        total: 100,
      } as Progress);
    }

    return {
      content: [{ type: 'text', text: greeting }],
    };
  }

  @Resource({
    uri: 'mcp://hello-world/{userName}',
    name: 'Hello World',
    description: 'A simple greeting resource',
    mimeType: 'text/plain',
  })
  // Different from the SDK, we put the parameters and URI in the same object.
  async getCurrentSchema({ uri, userName }) {
    return {
      content: [
        {
          uri,
          text: `User is ${userName}`,
          mimeType: 'text/plain',
        },
      ],
    };
  }
}

¡Ya está!

[!TIP] El ejemplo anterior muestra cómo se acceden a los encabezados HTTP Request dentro de las Herramientas MCP. Esto es útil para identificar usuarios, agregar lógica específica del cliente y muchos otros casos de uso. Para más ejemplos, consulta las Pruebas de Autenticación.

Inicio Rápido para STDIO

La diferencia principal es que debes proporcionar la opción transport al importar el módulo.

McpModule.forRoot({
  name: 'playground-stdio-server',
  version: '0.0.1',
  transport: McpTransportType.STDIO,
});

El resto es igual; puedes definir herramientas, recursos y prompts como de costumbre. Un ejemplo de una aplicación NestJS independiente que utiliza el transporte STDIO es el siguiente:

async function bootstrap() {
  const app = await NestFactory.createApplicationContext(AppModule, {
    logger: false,
  });
  return app.close();
}

void bootstrap();

Luego, puedes usar el servidor MCP con un Cliente Stdio MCP (ver ejemplo), o después de compilar tu proyecto, puedes usarlo con la siguiente configuración de Cliente MCP:

{
  "mcpServers": {
    "greeting": {
      "command": "node",
      "args": [
        "<path to dist js file>",
      ]
    }
  }
}

Endpoints de API

El transporte HTTP+SSE expone dos endpoints:

  • GET /sse: Endpoint de conexión SSE (Protegido por guards si están configurados)
  • POST /messages: Endpoint de ejecución de herramientas (Protegido por guards si están configurados)

El transporte HTTP Streamable expone los siguientes endpoints:

  • POST /mcp: Endpoint principal para todas las operaciones MCP (ejecución de herramientas, acceso a recursos, etc.). En modo con estado, crea y mantiene sesiones.
  • GET /mcp: Establece flujos de Eventos Enviados por el Servidor (SSE) para actualizaciones en tiempo real y notificaciones de progreso. Solo disponible en modo con estado.
  • DELETE /mcp: Termina sesiones MCP. Solo disponible en modo con estado.

Consejos

Es posible usar el módulo con un prefijo global, pero la forma recomendada es excluir esos endpoints con:

app.setGlobalPrefix('/api', { exclude: ['sse', 'messages', 'mcp'] });

Autenticación

Puedes proteger tus endpoints MCP utilizando Guards estándar de NestJS.

1. Crear un Guard

Implementa la interfaz CanActivate. El guard debe manejar la validación de solicitudes (por ejemplo, verificar JWTs, claves API) y opcionalmente adjuntar información del usuario al objeto de solicitud.

Nada especial, consulta la documentación de NestJS para más detalles.

2. Aplicar el Guard

Pasa tu(s) guard(s) a la configuración McpModule.forRoot. Los guards se aplicarán tanto a los endpoints /sse como a los /messages.

// app.module.ts
import { Module } from '@nestjs/common';
import { McpModule } from '@rekog/mcp-nest';
import { GreetingTool } from './greeting.tool';
import { AuthGuard } from './auth.guard';

@Module({
  imports: [
    McpModule.forRoot({
      name: 'my-mcp-server',
      version: '1.0.0',
      guards: [AuthGuard], // Apply the guard here
    }),
  ],
  providers: [GreetingTool, AuthGuard], // Ensure the Guard is also provided
})
export class AppModule {}

¡Eso es todo! El resto es igual que los Guards de NestJS.

Playground

El directorio playground contiene ejemplos para probar rápidamente las características de MCP y @rekog/mcp-nest. Consulta el playground/README.md para más detalles.

Configuración

El método McpModule.forRoot() acepta un objeto McpOptions para configurar el servidor. Estas son las opciones disponibles:

OpciónDescripciónPredeterminado
nameRequerido. El nombre de tu servidor MCP.-
versionRequerido. La versión de tu servidor MCP.-
capabilitiesCapacidades opcionales del servidor MCP para anunciar. Consulta @modelcontextprotocol/sdk.undefined
instructionsInstrucciones opcionales para el cliente sobre cómo interactuar con el servidor.undefined
transportEspecifica el(los) tipo(s) de transporte a habilitar.[McpTransportType.SSE, McpTransportType.STREAMABLE_HTTP, McpTransportType.STDIO]
sseEndpointLa ruta del endpoint para la conexión SSE (usado con el transporte SSE).'sse'
messagesEndpointLa ruta del endpoint para enviar mensajes (usado con el transporte SSE).'messages'
mcpEndpointLa ruta base del endpoint para operaciones MCP (usado con el transporte STREAMABLE_HTTP).'mcp'
guardsUn arreglo de Guards de NestJS para aplicar a los endpoints MCP para autenticación/autorización.[]
decoratorsUn arreglo de Decoradores de Clase de NestJS para aplicar a los controladores MCP generados.[]
sseConfiguración específica para el transporte SSE.{ pingEnabled: true, pingIntervalMs: 30000 }
sse.pingEnabledSi se debe habilitar el envío periódico de mensajes ping SSE para mantener la conexión activa.true
sse.pingIntervalMsEl intervalo (en milisegundos) para enviar mensajes ping SSE.30000
streamableHttpConfiguración específica para el transporte STREAMABLE_HTTP.{ enableJsonResponse: true, sessionIdGenerator: undefined, statelessMode: true }
streamableHttp.enableJsonResponseSi es true, permite que el endpoint /mcp devuelva respuestas JSON para solicitudes no transmitidas (como listTools).true
streamableHttp.sessionIdGeneratorUna función para generar identificadores de sesión únicos cuando se ejecuta en modo con estado. Requerido si statelessMode es false.undefined
streamableHttp.statelessModeSi es true, el transporte STREAMABLE_HTTP opera sin estado (sin sesiones). Si es false, opera con estado, requiriendo un sessionIdGenerator.true