返回市场
nestjs-mcp服务器

nestjs-mcp服务器

作者:adrian-d-hidalgo13 星标更新:2025-05-19

项目介绍

技术文档摘要

MCP Server NestJS 模块库 <!-- 省略在目录中 -->

NPM 版本 语义化发布 下载量 CI 流水线 Codecov 已知漏洞 MIT 许可证 欢迎 PR 贡献者公约


概述 <!-- 省略在目录中 -->

NestJS MCP Server 是一个用于使用 NestJS 构建 Model Context Protocol (MCP) 服务器的模块化库。它提供了装饰器、模块和集成模式,以可扩展且易于维护的方式暴露 MCP 资源、工具和提示。此项目是官方 @modelcontextprotocol/sdk 的封装,并始终与它的类型和规范保持兼容。


目录 <!-- 省略在目录中 -->


安装

npm install @nestjs-mcp/server @modelcontextprotocol/sdk zod
# 或
yarn add @nestjs-mcp/server @modelcontextprotocol/sdk zod
# 或
pnpm add @nestjs-mcp/server @modelcontextprotocol/sdk zod

快速开始

在您的 NestJS 应用程序中注册 MCP 模块并暴露一个简单的工具:

import { Module } from '@nestjs/common';

import { CallToolResult } from '@modelcontextprotocol/sdk/types';

import { Resolver, Tool, McpModule } from '@nestjs-mcp/server';

@Resolver()
export class HealthResolver {
  /**
   * 简单的健康检查工具
   */
  @Tool({ name: 'server_health_check' })
  healthCheck(): CallToolResult {
    return {
      content: [
        {
          type: 'text',
          text: '服务器运行正常。所有系统运行正常。',
        },
      ],
    };
  }
}

@Module({
  imports: [
    McpModule.forRoot({
      name: '我的 MCP 服务器',
      version: '1.0.0',
    }),
  ],
  providers: [HealthResolver],
})
export class AppModule {}

什么是 MCP?

Model Context Protocol (MCP) 是一种开放协议,用于连接 LLM 到外部数据、工具和提示。MCP 服务器以标准化方式暴露资源(数据)、工具(操作)和提示(对话流程),使与 LLM 驱动客户端的无缝集成成为可能。


核心概念

服务器

MCP 服务器是向 LLM 暴露功能的主要入口点。它管理资源、工具和提示的注册和发现。

资源

资源表示可以被 LLM 查询或检索的结构化数据或文档。资源通常是只读的,并通过唯一的 URI 来标识。

工具

工具是一个可以由 LLM 调用的操作或函数。工具可能会有副作用,并可以接受参数来执行计算或触发操作。

提示

提示定义了 LLM 的对话流程、模板或交互模式。提示有助于指导模型在特定场景中的行为。

参见 能力 部分了解实现细节和代码示例。


模块 API

McpModule.forRoot

在您的 NestJS 应用程序中全局注册 MCP 服务器。

参数:

  • options: McpModuleOptions — 主服务器配置对象:
    • name: string: 您的 MCP 服务器名称。
    • version: string: 您的 MCP 服务器版本。
    • instructions?: string: 可选的客户端 MCP 服务器描述。
    • capabilities?: Record<string, unknown>: 可选的附加功能元数据。
    • providers?: Provider[]: 可选的要包含在模块中的 NestJS 提供者数组。
    • imports?: any[]: 可选的要导入的 NestJS 模块数组。
    • logging?: McpLoggingOptions: 可选的日志配置:
      • enabled?: boolean(默认值:true):启用/禁用日志记录。
      • level?: 'error' | 'warn' | 'log' | 'debug' | 'verbose'(默认值:'verbose'):设置日志级别。
    • transports?: McpModuleTransportOptions: 可选的传输配置(参见 传输选项)。
    • protocolOptions?: Record<string, unknown>: 直接传递给底层 @modelcontextprotocol/sdk 服务器实例的其他参数。

返回:

  • 包含所有 MCP 提供者的动态 NestJS 模块。

示例:

import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';

@Module({
  imports: [
    McpModule.forRoot({
      name: '我的服务器',
      version: '1.0.0',
      instructions: '提供实用工具和数据的服务器。',
      logging: { level: 'log' },
      transports: { sse: { enabled: false } }, // 禁用 SSE 传输
      // ...其他 MCP 选项
    }),
  ],
})
export class AppModule {}

McpModule.forRootAsync

使用异步选项全局注册 MCP 服务器,适用于与配置模块(如 @nestjs/config)集成。

注意:

  • imports 数组应包括提供 useFactory 所需依赖项的任何模块(例如,如果您注入 ConfigService,则为 ConfigModule)。
  • 只在根模块(AppModule)中使用一次 forRootAsync
  • 查看 McpModuleAsyncOptions 以获取所有可用选项。

参数:

  • options: McpModuleAsyncOptions — 异步配置对象:
    • imports?: any[]: 在工厂运行之前导入的可选模块。
    • useFactory: (...args: any[]) => Promise<McpModuleOptions> | McpModuleOptions: 返回 McpModuleOptions 的工厂函数。
    • inject?: any[]: 注入到 useFactory 的可选提供者。

返回:

  • 动态 NestJS 模块。

示例(与 ConfigModule 结合使用):

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { McpModule } from '@nestjs-mcp/server';

@Module({
  imports: [
    ConfigModule.forRoot(), // 确保导入 ConfigModule
    McpModule.forRootAsync({
      imports: [ConfigModule], // 在这里也导入 ConfigModule
      useFactory: (configService: ConfigService) => ({
        name: configService.get<string>('MCP_SERVER_NAME', '默认服务器'),
        version: configService.get<string>('MCP_SERVER_VERSION', '1.0.0'),
        instructions: configService.get<string>('MCP_SERVER_DESC'),
        logging: {
          level: configService.get('MCP_LOG_LEVEL', 'verbose'),
        },
        // ...来自 configService 的其他选项
      }),
      inject: [ConfigService], // 将 ConfigService 注入到工厂
    }),
  ],
})
export class AppModule {}

McpModule.forFeature

在特性模块中注册额外的 MCP 资源、工具或提示。使用此功能将大型服务器组织成多个模块。包含 MCP 功能的解析器必须包含在特性模块的 providers 数组中。

参数:

  • options?: McpFeatureOptions(目前未使用,保留用于未来增强)。

返回:

  • 动态模块。

示例:

// src/status/status.resolver.ts
import { Resolver, Tool } from '@nestjs-mcp/server';
import { CallToolResult } from '@modelcontextprotocol/sdk/types';

@Resolver('status')
export class StatusResolver {
  @Tool({ name: 'health_check' })
  healthCheck(): CallToolResult {
    return { content: [{ type: 'text', text: 'OK' }] };
  }
}

// src/status/status.module.ts
import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
import { StatusResolver } from './status.resolver';

@Module({
  imports: [McpModule.forFeature()], // 在这里导入 forFeature
  providers: [StatusResolver], // 注册您的解析器
})
export class StatusModule {}

模块用法

此库提供了两种主要方式在您的 NestJS 应用程序中注册 MCP 功能:

1. 使用 McpModule.forRoot 进行全局注册

在您的根应用程序模块中使用 McpModule.forRoot 来配置和注册 MCP 服务器。这是每个 MCP 服务器应用程序所必需的。

import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
import { PromptsResolver } from './prompts.resolver';

@Module({
  imports: [
    McpModule.forRoot({
      name: '我的 MCP 服务器',
      version: '1.0.0',
      // ...其他 MCP 选项
    }),
  ],
  providers: [PromptsResolver],
})
export class AppModule {}

2. 使用 McpModule.forFeature 注册特性模块

在特性模块中使用 McpModule.forFeature 注册额外的解析器、工具或资源。这对于将大型服务器组织成多个模块非常有用。

import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';

import { ToolsResolver } from './tools.resolver';

@Module({
  imports: [McpModule.forFeature()],
  providers: [ToolsResolver],
})
export class ToolsModule {}
  • 只在根模块(AppModule)中使用一次 forRootforRootAsync
  • 在定义 MCP 功能(@Resolver 类)的任何特性模块中使用 forFeature
  • 确保所有解析器都列在其相应模块的 providers 数组中。

能力

此库提供了一组装饰器来定义 MCP 功能并应用横切关注点,如守卫。装饰器可以在解析器(类)级别和方法级别使用。

解析器装饰器

解析器是一个将相关 MCP 功能分组的类。所有 MCP 功能方法(@Prompt@Resource@Tool必须属于一个用 @Resolver 装饰的类。

  • 不需要 @Injectable(): 解析器类由 MCP 模块自动视为提供者,并且不需要 @Injectable() 装饰器。
  • 依赖注入: 标准的 NestJS 依赖注入在解析器构造函数中有效。
  • 命名空间: 您可以选择性地提供字符串参数给 @Resolver('my_namespace') 以在该解析器内命名空间这些功能。
  • 守卫: 可以使用 @UseGuards() 在类级别应用守卫。

示例:

import { Resolver, Prompt, Resource, Tool } from '@nestjs-mcp/server';
// 导入您需要注入的服务
import { SomeService } from '../some.service';

@Resolver('workspace') // 不需要 @Injectable()
export class MyResolver {
  // 如常注入依赖
  constructor(private readonly someService: SomeService) {}

  @Prompt({ name: 'greet_user' }) // 功能必须在解析器内
  greetPrompt(/*...args...*/) {
    const greeting = this.someService.getGreeting();
    /* ... */
  }

  @Resource({ name: 'user_profile', uri: 'user://{id}' })
  getUserResource(/*...args...*/) {
    /* ... */
  }

  @Tool({ name: 'calculate_sum' })
  sumTool(/*...args...*/) {
    /* ... */
  }
}

您还可以在解析器级别应用守卫:

import { UseGuards, Resolver } from '@nestjs-mcp/server';
import { MyGuard } from './guards/my.guard';

@UseGuards(MyGuard) // 应用于此解析器内的所有功能
@Resolver('secure') // 不需要 @Injectable()
export class SecureResolver {
  // 此解析器内的所有功能都将使用 MyGuard
}

提示装饰器

在解析器类的方法上使用装饰器以将其暴露为 MCP 提示。接受与 @modelcontextprotocol/sdk 中的 server.prompt() 兼容的选项。name 应使用 snake_case

import { Prompt, Resolver } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // 导入额外信息类型
import { z } from 'zod'; // 示例如果使用 Zod 模式

// 可选:如果需要定义模式
// const SummaryArgs = z.object({ topic: z.string() });

@Resolver('prompts') // 必须在解析器类内
export class MyPrompts {
  @Prompt({
    name: 'generate_summary',
    description: '为给定的文本生成摘要。',
    // argsSchema: SummaryArgs
  })
  generateSummaryPrompt(
    // params: z.infer<typeof SummaryArgs>, // 基于 argsSchema(如果有定义)的参数
    extra: RequestHandlerExtra, // 包含 sessionId 和其他元数据
  ) {
    console.log(`为会话生成摘要:${extra.sessionId}`);
    /* ... 返回 CallPromptResult ... */
    return { content: [{ type: 'text', text: '摘要已生成。' }] };
  }
}

资源装饰器

在解析器类的方法上使用装饰器以将其暴露为 MCP 资源。接受与 @modelcontextprotocol/sdk 中的 server.resource() 兼容的选项。name 应使用 snake_case

import { Resource, Resolver } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // 导入额外信息类型
import { URL } from 'url'; // 资源 URI 类型
import { z } from 'zod'; // 示例如果使用 Zod 模板

// 可选:如果需要定义模板模式
// const DocQueryTemplate = z.object({ query: z.string() });

@Resolver('data') // 必须在解析器类内
export class MyResources {
  @Resource({
    name: 'user_profile',
    uri: 'user://profiles/{userId}',
    // metadata: