MCP服务器NestJS模块库
](https://www.npmjs.com/package/@nestjs-mcp/server)  ](https://www.npmjs.com/package/@nestjs-mcp/server)      
______________________________________________________________________
概述
______________________________________________________________________
目录
- McpModule.forRoot - McpModule.forRootAsync - McpModule.forFeature
- 1.全球注册 McpModule.forRoot - 2.功能模块注册 McpModule.forFeature
- 解析器装饰器 - 快速装饰师 - 资源装饰师 - 工具装饰器 - 工具注释 - 工具选项变体 - RequestHandler额外参数
- 全球级警卫 - 分解器液位保护装置 - 方法级别防护 - 警卫示例 - MCP执行上下文 - 依赖注入防护
- 会话管理选项
______________________________________________________________________
安装
npm install @nestjs-mcp/server @modelcontextprotocol/sdk zod
# or
yarn add @nestjs-mcp/server @modelcontextprotocol/sdk zod
# or
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 {
/**
* Simple health check tool
*/
@Tool({ name: 'server_health_check' })
healthCheck(): CallToolResult {
return {
content: [
{
type: 'text',
text: 'Server is operational. All systems running normally.',
},
],
};
}
}
@Module({
imports: [
McpModule.forRoot({
name: 'My MCP Server',
version: '1.0.0',
}),
],
providers: [HealthResolver],
})
export class AppModule {}______________________________________________________________________
什么是MCP?
这 模型上下文协议(MCP) 是一种用于将LLM连接到外部数据、工具和提示的开放协议。MCP服务器以标准化的方式公开资源(数据)、工具(操作)和提示(会话流),实现与LLM驱动的客户端的无缝集成。
- 看 人类公告 了解更多背景信息。
______________________________________________________________________
核心概念
服务器
MCP服务器是向LLM公开功能的主要入口点。它管理资源、工具和提示的注册和发现。
资源
资源表示LLM可以查询或检索的结构化数据或文档。资源通常是只读的,由唯一的URI标识。
- 了解更多: MCP资源文档
工具
工具是LLM可以调用的动作或函数。工具可能有副作用,可以接受参数来执行计算或触发操作。
- 了解更多: MCP工具文档
提示
Prompt为LLM定义会话流、模板或交互模式。提示有助于指导模型在特定场景中的行为。
- 了解更多: MCP提示文件
看 能力 实现细节和代码示例部分。
______________________________________________________________________
模块API
McpModule.forRoot
在NestJS应用程序中全局注册MCP服务器。
参数:
options: McpModuleOptions--主服务器配置对象:
- name: string:您的MCP服务器的名称。 - version: string:MCP服务器的版本。 - instructions?: string:客户端MCP服务器的可选描述。 - capabilities?: Record:可选的附加功能元数据。 - providers?: Provider[]:要包含在模块中的NestJS提供程序的可选数组。 - imports?: any[]:要导入的NestJS模块的可选数组。 - logging?: McpLoggingOptions:可选日志记录配置: - enabled?: boolean (默认值: true):启用/禁用日志记录。 - level?: 'error' | 'warn' | 'log' | 'debug' | 'verbose' (默认值: 'verbose'):设置日志记录级别。 - transports?: McpModuleTransportOptions:可选传输配置(请参见 运输选项). - protocolOptions?: Record:直接传递给底层的可选参数 @modelcontextprotocol/sdk 服务器实例。
退货:
- 一个动态NestJS模块,已注册所有MCP提供商。
例子:
import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
McpModule.forRoot({
name: 'My Server',
version: '1.0.0',
instructions: 'A server providing utility tools and data.',
logging: { level: 'log' },
transports: { sse: { enabled: false } }, // Disable SSE transport
// ...other MCP options
}),
],
})
export class AppModule {}McpModule.forRootAsync
使用异步选项全局注册MCP服务器,这对于与配置模块集成非常有用,例如 @nestjs/config.
注: - 这imports数组应包括提供所需依赖项的任何模块useFactory(例如。,ConfigModule如果你注射ConfigService). - 使用forRootAsync在根模块中只有一次(AppModule). - 看McpModuleAsyncOptions所有可用选项。
参数:
options: McpModuleAsyncOptions--异步配置对象:
- imports?: any[]:在工厂运行之前导入的可选模块。 - useFactory: (...args: any[]) => Promise | McpModuleOptions:一个返回 McpModuleOptions. - inject?: any[]:可供选择的注射提供者 useFactory.
退货:
- 一个动态的NestJS模块。
示例(使用ConfigMgr):
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
ConfigModule.forRoot(), // Make sure ConfigModule is imported
McpModule.forRootAsync({
imports: [ConfigModule], // Import ConfigModule here too
useFactory: (configService: ConfigService) => ({
name: configService.get('MCP_SERVER_NAME', 'Default Server'),
version: configService.get('MCP_SERVER_VERSION', '1.0.0'),
instructions: configService.get('MCP_SERVER_DESC'),
logging: {
level: configService.get('MCP_LOG_LEVEL', 'verbose'),
},
// ... other options from configService
}),
inject: [ConfigService], // Inject ConfigService into the factory
}),
],
})
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()], // Import forFeature here
providers: [StatusResolver], // Register your resolver
})
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: 'My MCP Server',
version: '1.0.0',
// ...other MCP options
}),
],
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 {}- 使用
forRoot或forRootAsync仅一次 在根模块中(AppModule). - 使用
forFeature在定义MCP功能的任何功能模块中(@Resolver班级)。 - 确保所有解析程序都列在
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 any services you need to inject
import { SomeService } from '../some.service';
@Resolver('workspace') // No @Injectable()
export class MyResolver {
// Inject dependencies as usual
constructor(private readonly someService: SomeService) {}
@Prompt({ name: 'greet_user' }) // Capabilities must be inside a Resolver
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) // Applied to all capabilities in this Resolver
@Resolver('secure') // No @Injectable()
export class SecureResolver {
// All capabilities in this resolver will use MyGuard
}快速装饰师
装饰Resolver类中的方法,将其作为MCP Prompts公开。接受与兼容的选项 server.prompt() 从 @modelcontextprotocol/sdk. 这 name 应该使用 snake_case.
import { Prompt, Resolver } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Import type for extra info
import { z } from 'zod'; // Example if using Zod schema
// Optional: Define schema if needed
// const SummaryArgs = z.object({ topic: z.string() });
@Resolver('prompts') // Must be in a Resolver class
export class MyPrompts {
@Prompt({
name: 'generate_summary',
description: 'Generates a summary for the given text.',
// argsSchema: SummaryArgs
})
generateSummaryPrompt(
// params: z.infer, // Arguments based on argsSchema (if defined)
extra: RequestHandlerExtra, // Contains sessionId and other metadata
) {
console.log(`Generating summary for session: ${extra.sessionId}`);
/* ... return CallPromptResult ... */
return { content: [{ type: 'text', text: 'Summary generated.' }] };
}
}资源装饰师
装饰Resolver类中的方法,将其作为MCP资源公开。接受与兼容的选项 server.resource() 从 @modelcontextprotocol/sdk. 这 name 应该使用 snake_case.
import { Resource, Resolver } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Import type for extra info
import { URL } from 'url'; // Type for URI resource
import { z } from 'zod'; // Example if using Zod template
// Optional: Define template schema if needed
// const DocQueryTemplate = z.object({ query: z.string() });
@Resolver('data') // Must be in a Resolver class
export class MyResources {
@Resource({
name: 'user_profile',
uri: 'user://profiles/{userId}',
// metadata: { description: '...' } // Optional
})
getUserProfile(
uri: URL, // First argument is the parsed URI
// metadata: Record // Second argument if is defined
extra: RequestHandlerExtra, // Contains sessionId and other metadata
) {
const userId = uri.pathname.split('/').pop(); // Example: Extract ID from URI
console.log(`Fetching profile for ${userId}, session: ${extra.sessionId}`);
/* ... return CallResourceResult ... */
return { content: [{ type: 'text', text: `Profile data for ${userId}` }] };
}
@Resource({
name: 'document_list',
template: { type: 'string', description: 'Document content query' }, // Simple template example
// metadata: { list: true } // Optional
})
findDocuments(
uri: URL, // First arg based on simple template type
variables: Record, // Second arg is path params (if any)
extra: RequestHandlerExtra, // Contains sessionId and other metadata
) {
console.log(
`Finding documents matching '${query}', session: ${extra.sessionId}`,
);
/* ... return CallResourceResult ... */
return { content: [{ type: 'text', text: 'List of documents.' }] };
}
}工具装饰器
装饰Resolver类中的方法,将其作为MCP工具公开。接受与兼容的选项 server.tool() 从 @modelcontextprotocol/sdk. 这 name 应该使用 snake_case.
import { Tool, Resolver } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server';
import { z } from 'zod';
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
@Resolver('user_tools')
export class UserToolsResolver {
@Tool({
name: 'delete_user',
description: 'Deletes a user by ID',
paramsSchema: { userId: z.string() },
annotations: { destructiveHint: true, readOnlyHint: false },
})
deleteUser(
{ userId }: { userId: string },
extra: RequestHandlerExtra,
): CallToolResult {
// ...logic...
return { content: [{ type: 'text', text: `User ${userId} deleted.` }] };
}
}工具注释
这 annotations 字段允许您提供有关工具行为的协议级提示,例如它是破坏性的、只读的、幂等的,还是具有其他特殊属性。客户端、UI或协议本身可以使用这些提示来显示警告、优化调用或执行策略。
常用注释键:
destructiveHint(boolean):表示工具执行破坏性操作(例如,删除数据)。readOnlyHint(boolean):表示该工具不修改任何数据。idempotentHint(boolean):表示该工具可以安全地多次调用,效果相同。openWorldHint(boolean):表示该工具可能在当前系统之外产生副作用。
例子:
@Tool({
name: 'reset_password',
paramsSchema: { userId: z.string() },
annotations: { destructiveHint: true, idempotentHint: false }
})
resetPassword({ userId }: { userId: string }): CallToolResult {
// ...
}工具选项变体
| 变量 | 必填字段 |
|---|---|
| ToolBaseOptions | 名称 |
| ToolWithDescriptionOptions | 名称、描述 |
| 工具带参数或注释选项 | 名称、参数模式或注释 |
| 工具带参数或注释和描述选项 | 名称、参数模式或注释、描述 |
| 工具带参数和注释选项 | 名称、参数模式、注释 |
| 工具带参数和注释和描述选项 | 名称、参数模式、注释、描述 |
paramsSchema和paramsSchemaOrAnnotations可以是用于输入验证的Zod模式。annotations是具有如上所述的协议级提示的对象。
RequestHandler额外参数
所有MCP能力方法(@Prompt, @Resource, @Tool)总是收到a RequestHandlerExtra object作为最后一个参数。此对象从以下对象扩展了原始类型 @modelcontextprotocol/sdk 并提供关于当前MCP请求的基本上下文。
SDK中的属性:
signal一AbortSignal用于在请求被取消时进行通信authInfo:有关已验证访问令牌的可选信息sessionId:传输中的会话ID(如果可用)sendNotification:发送与当前请求相关的通知的函数sendRequest:发送与当前请求相关的请求的函数
扩展属性:
headers:来自原始请求的HTTP标头(由@nestjs-mcp/server添加)
使用示例:
import { Tool, Resolver, SessionManager } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server';
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
@Resolver('auth')
export class AuthResolver {
@Tool({
name: 'authenticate_user',
description: 'Authenticates a user with credentials',
// ...other options
})
authenticateUser(
params: { username: string; password: string },
extra: RequestHandlerExtra, // Always the last parameter
): CallToolResult {
// Access the session ID
console.log(`Request received in session: ${extra.sessionId}`);
// Access request headers (extended property)
const authHeader = extra.headers.authorization;
const userAgent = extra.headers['user-agent'];
console.log(`Request from: ${userAgent}`);
// Check if request was cancelled
if (extra.signal.aborted) {
return {
content: [{ type: 'text', text: 'Request was cancelled' }],
};
}
// Implement authentication logic
return {
content: [{ type: 'text', text: 'Authentication successful' }],
};
}
}重要提示:
extra始终是任何方法中的最后一个参数@Resource,@Prompt,或@Tool- 这
headers属性是@nestjs-mcp/server添加的一个扩展,用于直接访问HTTP标头
______________________________________________________________________
守卫
对解析器、单个方法或全局应用一个或多个保护。警卫必须执行NestJS CanActivate 界面。
全球级警卫
这种方法使用标准的NestJS全局防护系统(APP_GUARD).全球警卫将保护 全部 NestJS路由,包括MCP传输端点(如 /mcp 或 /sse).在任何MCP特定逻辑运行之前,将此用于广泛的身份验证或检查。
// src/guards/global-auth.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Request } from 'express';
@Injectable()
export class GlobalAuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const apiKey = request.headers['x-api-key'];
// Example: Check for a valid API key
return !!apiKey && apiKey === 'EXPECTED_KEY';
}
}在主模块中全局注册警卫:
// src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { McpModule } from '@nestjs-mcp/server';
import { GlobalAuthGuard } from './guards/global-auth.guard';
@Module({
imports: [McpModule.forRoot(/*...*/)],
providers: [
{
provide: APP_GUARD,
useClass: GlobalAuthGuard,
},
],
})
export class AppModule {}分解器液位保护装置
这是此库的自定义功能。使用 @UseGuards() 装饰师(出口自 @nestjs-mcp/server)在Resolver类上。所有MCP方法(@Prompt, @Resource, @Tool) 在该特定解析器内 将受到这些警卫的保护。使用此功能为一组相关功能强制执行逻辑(例如角色检查)。
import { UseGuards, Resolver, Prompt } from '@nestjs-mcp/server';
import { RoleGuard } from './guards/role.guard';
@UseGuards(RoleGuard)
@Resolver('admin')
export class AdminResolver {
@Prompt({ name: 'admin_action' })
adminAction(/*...*/) {
/* ... */
}
// ... other admin capabilities
}方法级别防护
这是此库的自定义功能。方法级别防护使用 @UseGuards() 直接在MCP能力方法上进行装饰(@Prompt, @Resource, @Tool).只有装饰的方法会受到这些警卫的保护。使用此功能对特定功能进行细粒度访问控制。
import { UseGuards, Resolver, Prompt, Tool } from '@nestjs-mcp/server';
import { SpecificCheckGuard } from './guards/specific-check.guard';
@Resolver('mixed')
export class MixedResolver {
@Prompt({ name: 'public_prompt' })
publicPrompt() {
/* Publicly accessible */
}
@UseGuards(SpecificCheckGuard)
@Tool({ name: 'protected_tool' })
protectedTool(/*...*/) {
/* Requires SpecificCheckGuard to pass */
}
}重要提示: 解析器和方法级别保护 仅对MCP功能调用运行,不适用于由全局警卫处理的初始连接建立。他们使用习俗 McpExecutionContext.
警卫示例
解析器或方法级别保护的防护:
// src/guards/my-mcp.guard.ts
import { CanActivate, Injectable } from '@nestjs/common';
import { McpExecutionContext, SessionManager } from '@nestjs-mcp/server';
@Injectable()
export class MyMcpGuard implements CanActivate {
constructor(private readonly sessionManager: SessionManager) {}
canActivate(context: McpExecutionContext): boolean {
const sessionId = context.getSessionId();
if (!sessionId) return false;
const handlerArgs = context.getArgs();
const session = this.sessionManager.getSession(sessionId);
const request = session?.request;
const userAgent = request?.headers['user-agent'];
console.log(`Guard activated for session ${sessionId} from ${userAgent}`);
console.log('Handler args:', handlerArgs);
return true;
}
}MCP执行上下文
实施时 解析器级别 或 方法级别 警卫使用 @UseGuards() 从这个图书馆,你的 canActivate 方法接收 McpExecutionContext 例子此上下文提供了对MCP特定信息的访问:
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { McpExecutionContext, SessionManager } from '@nestjs-mcp/server';
import { Request } from 'express';
@Injectable()
export class McpAuthGuard implements CanActivate {
constructor(private readonly sessionManager: SessionManager) {}
canActivate(context: McpExecutionContext): boolean {
const sessionId = context.getSessionId();
if (!sessionId) {
console.error('Guard Error: MCP Session ID not found in context.');
return false;
}
const handlerArgs = context.getArgs();
console.log('MCP Handler Arguments:', handlerArgs);
const session = this.sessionManager.getSession(sessionId);
if (!session) {
console.error(`Guard Error: Session not found for ID: ${sessionId}`);
return false;
}
const request = session.request as Request;
const authHeader = request.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
console.log('Guard Denied: Missing or invalid Bearer token.');
return false;
}
const token = authHeader.split(' ')[1];
const isValidToken = token === 'VALID_TOKEN';
if (isValidToken) {
console.log(`Guard Passed for session ${sessionId} with token.`);
return true;
} else {
console.log(`Guard Denied: Invalid token for session ${sessionId}.`);
return false;
}
}
}关键点 McpExecutionContext:
getSessionId():检索当前MCP会话的唯一ID。 关键 用于将保护检查与存储的会话状态相关联SessionManager.- 论点(
handlerArgs):提供专门传递给MCP处理程序方法的参数(@Tool,@Prompt,@Resource)被调用。这些参数的结构取决于能力类型及其定义(例如。,params对于工具,query/params资源)。您可以通过以下方式访问这些context.getArgs(),但要注意基于能力的实际结构。 - 请求数据:使用
SessionManager注入到你的警卫中以获取会话详细信息(包括原始信息)Request)基于sessionId从上下文中获得。 switchToHttp().getResponse()/switchToHttp().getNext():这些将抛出错误,因为Response对象在此上下文中不直接可用或不相关。
使用 SessionManager 注入到你的警卫中以获取会话详细信息(包括原始信息) Request)基于 sessionId 从上下文中获得。
依赖注入防护
守卫可以注入NestJS提供程序,如 SessionManager.使用 @Injectable() 并将该警卫注册为提供者:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly sessionManager: SessionManager) {}
canActivate(context: McpExecutionContext): boolean {
const session = this.sessionManager.getSession(context.getSessionId());
return !!session?.request.headers.authorization;
}
}
@Module({
imports: [McpModule.forRoot({ name: 'my-server', version: '1.0.0' })],
providers: [AuthGuard, MyResolver],
})
export class AppModule {}警卫没有 @Injectable() 仍然有效,但不会收到注入的依赖项。______________________________________________________________________
会话管理
这个图书馆包括 SessionManager 负责跟踪活动MCP会话的服务。每个传入的MCP连接都会建立一个会话,由一个唯一的 sessionIdThe SessionManager 通常存储相关的初始值 Request 每个会话的对象。
为什么它很重要?
- 访问请求数据: 由于MCP操作(工具调用、提示执行)可能独立于初始HTTP连接(特别是使用SSE等流式传输)发生
SessionManager提供了一种检索原始文件的方法Request与特定内容相关的上下文sessionId。这对于需要访问原始请求中的请求标头、参数或其他特定于连接的详细信息的防护或功能方法(在解析器中)至关重要。 - 状态管理: 虽然目前专注于存储请求
SessionManager如果您的应用程序需要,可以扩展以存储额外的会话特定状态。
用法示例(在解析器中):
解析程序可能需要访问原始请求,例如,获取用户信息或在初始连接期间在头中传递的API密钥。
import { Tool, Resolver, SessionManager } from '@nestjs-mcp/server';
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Provides sessionId
import { Request } from 'express';
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
import { z } from 'zod';
const UserToolParams = z.object({
user_id: z.string().optional(),
});
@Resolver('user_tools') // No @Injectable() needed
export class UserToolsResolver {
// Inject SessionManager
constructor(private readonly sessionManager: SessionManager) {}
@Tool({
name: 'get_user_agent',
description:
'Gets the user agent from the original request for the session.',
paramSchema: UserToolParams,
})
getUserAgent(
params: z.infer,
extra: RequestHandlerExtra, // Get extra info, including sessionId
): CallToolResult {
const sessionId = extra.sessionId;
if (!sessionId) {
return {
content: [{ type: 'text', text: 'Error: Session ID missing.' }],
};
}
// Use sessionId to get the session from the manager
const session = this.sessionManager.getSession(sessionId);
if (!session) {
return {
content: [
{
type: 'text',
text: `Error: Session not found for ID: ${sessionId}`,
},
],
};
}
// Access the original request stored in the session
const request = session.request as Request;
const userAgent = request.headers['user-agent'] || 'Unknown';
return {
content: [
{ type: 'text', text: `Session ${sessionId} User Agent: ${userAgent}` },
],
};
}
}在这个例子中:
- 这
@Tool方法接收extra: RequestHandlerExtra,其中包含sessionId. - 这
SessionManager被注入UserToolsResolver. - 这
sessionId与一起使用sessionManager.getSession()以检索会话数据。 - 原版
request从检索到的会话数据中访问对象。
这 SessionManager 当您使用时,会自动注册为提供商 McpModule.forRoot 或 McpModule.forRootAsync 并且可以像任何其他NestJS提供者一样注入。
______________________________________________________________________
运输选项
MCP服务器可以通过不同的传输机制进行通信。此库包括对以下内容的内置支持:
- 可流式传输(
/mcp端点): 使用标准HTTP POST请求和响应的通用传输。适用于大多数请求/响应交互。默认情况下启用。 - SSE(服务器发送事件)(
/sse端点): 一种传输机制,允许服务器通过单个HTTP连接向客户端推送更新。适用于流式响应或长时间运行的操作。 注: 这被认为是一种传统的传输方式,但仍然支持兼容性。默认情况下启用。
您可以使用配置全局启用哪些传输 transports 选项在 McpModule.forRoot 或 McpModule.forRootAsync.
配置:
import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
McpModule.forRoot({
name: 'My Server',
version: '1.0.0',
transports: {
streamable: { enabled: true }, // Keep streamable enabled (default)
sse: { enabled: false }, // Disable legacy SSE transport
},
}),
],
})
export class AppModule {}默认配置:
如果 transports 选项被省略,两者 streamable (/mcp)以及 sse (/sse)默认情况下启用。
import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
McpModule.forRoot({
name: 'My Server',
version: '1.0.0',
// Both streamable and sse will be enabled
}),
],
})
export class AppModule {}禁用未使用的传输可以略微减少应用程序的表面积和资源使用。
______________________________________________________________________
会话管理选项
配置会话超时、清理间隔和资源限制,以针对生产工作负载优化服务器。
配置:
import { Module } from '@nestjs/common';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
McpModule.forRoot({
name: 'My Server',
version: '1.0.0',
session: {
sessionTimeoutMs: 1800000, // 30 minutes (default)
cleanupIntervalMs: 300000, // 5 minutes (default)
maxConcurrentSessions: 1000, // Max sessions (default)
},
}),
],
})
export class AppModule {}配置选项:
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
sessionTimeoutMs | number | 1800000 (30分钟) | 会话清理前的最长不活动时间 |
cleanupIntervalMs | number | 300000 (5分钟) | 清理作业执行频率 |
maxConcurrentSessions | number | 1000 | 允许的最大并发会话数 |
工作原理:
- 活动跟踪:每届会议
lastActivity每次请求时都会更新时间戳 - 清理工作:运行每
cleanupIntervalMs关闭并删除非活动会话 - 会话限制:当出现以下情况时,新连接被拒绝(503)
maxConcurrentSessions已达到
生产建议:
- 高流量服务器:增加
maxConcurrentSessions(2000-5000)和减少cleanupIntervalMs(2-3分钟) - 低内存环境:减少
maxConcurrentSessions(100-500)和sessionTimeoutMs(10-15分钟) - 长时间运行的工作流程:增加
sessionTimeoutMs(60-90分钟)
环境变量示例:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { McpModule } from '@nestjs-mcp/server';
@Module({
imports: [
ConfigModule.forRoot(),
McpModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
name: 'My Server',
version: '1.0.0',
session: {
sessionTimeoutMs: config.get('MCP_SESSION_TIMEOUT', 1800000),
cleanupIntervalMs: config.get('MCP_CLEANUP_INTERVAL', 300000),
maxConcurrentSessions: config.get('MCP_MAX_SESSIONS', 1000),
},
}),
}),
],
})
export class AppModule {}______________________________________________________________________
检查员游乐场
使用Inspector Playground在浏览器UI中交互式测试和调试MCP服务器端点。该工具由 @modelcontextprotocol/inspector,允许您:
- 探索可用的资源、工具和提示
- 实时调用端点并查看响应
- 根据MCP规范验证服务器实现
要启动Inspector Playground(确保您的NestJS MCP服务器正在运行):
npx @modelcontextprotocol/inspector它通常会连接到 http://localhost:3000 默认情况下,您也可以指定其他目标URL。
______________________________________________________________________
例子
这 examples/ 目录包含演示如何注册和公开MCP功能的现成场景。
每个示例都是自包含的,并遵循最佳实践。有关高级用法,请参阅每个示例中的代码和文档。
______________________________________________________________________
更新日志
看 更改日志.md 发布说明。
______________________________________________________________________
许可证
麻省理工学院——见 许可证 了解详情。
______________________________________________________________________
贡献
欢迎投稿!请参阅 贡献.md 用于指导方针、报告问题和拉取请求规则。
在投稿之前,请阅读我们的 行为准则 了解我们社区对行为的期望。
