内容
# @sowonai/nestjs-mcp-adapter
该项目是一个库,帮助您方便地开发 NestJS MCP(模型上下文协议)服务器。
它支持 STDIO 和 HTTP 协议,并允许您使用 NestJS 的所有功能,例如 AuthGuard 和 Interceptor,无论协议如何。
[](https://x.com/dohapark81)
[](https://www.threads.com/@sowonlabs)
## 特性
- **MCP 工具**:使用装饰器轻松创建 MCP 工具。
- **(TOBE)MCP 资源**:使用装饰器创建 MCP 资源。
- **(TOBE)MCP 提示**:使用装饰器创建 MCP 提示。
- 支持 STDIO 和 HTTP 协议。
- 支持多个 MCP 服务器。
## 安装
```bash
npm install @sowonai/nest-mcp-adapter @nestjs/platform-express @modelcontextprotocol/sdk zod
```
## 简单架构

## 使用示例(单服务器)
此示例演示如何设置单个 MCP 服务器。我们将使用一个简单的 "greet" 工具。
### 工具定义 (`greet.tool.ts`)
```typescript
import { Injectable } from '@nestjs/common';
import { McpTool } from '@sowonai/nest-mcp-adapter';
import { z } from 'zod';
@Injectable()
export class GreetToolService {
@McpTool({
server: 'mcp-greet',
name: 'helloMessage',
description: '用自定义消息向用户问好。',
input: {
message: z.string().describe('问候中包含的消息')
},
annotations: {
title: '问候消息',
readOnlyHint: true,
desctructiveHint: false,
}
})
async helloMessage({ message }: { message: string }) {
return {
content: [{ type: 'text', text: `你好, ${message || 'MCP'}!` }]
};
}
}
```
### 控制器 (`mcp.controller.ts`)
该控制器处理对 `mcp-greet` 服务器的请求。
```typescript
import { Controller, Post, Body, UseGuards, Req, Res, HttpCode, UseFilters } from '@nestjs/common';
import { McpHandler, JsonRpcRequest, JsonRpcExceptionFilter } from '@sowonai/nest-mcp-adapter';
import { AuthGuard } from './auth.guard';
import { Request, Response } from 'express';
@Controller('mcp') // MCP 请求的基础路径
@UseGuards(AuthGuard)
@UseFilters(JsonRpcExceptionFilter)
export class McpGreetController {
constructor(
private readonly mcpHandler: McpHandler
) {}
@Post()
@HttpCode(202)
async handlePost(
@Req() req: Request,
@Res() res: Response,
@Body() body: JsonRpcRequest,
) {
const serverName = 'mcp-greet';
const result = await this.mcpHandler.handleRequest(serverName, req, res, body);
if (result === null) {
if (!res.writableEnded) {
return res.end();
}
return;
}
return res.json(result);
}
}
```
### 模块 (`app.module.ts`)
```typescript
import { Module } from '@nestjs/common';
import { McpAdapterModule, McpModuleOptions } from '@sowonai/nest-mcp-adapter';
import { GreetToolService } from './greet.tool';
import { McpGreetController } from './mcp.controller';
import { AuthGuard } from './auth.guard';
@Module({
imports: [
McpAdapterModule.forRoot({
servers: {
'mcp-greet': {
version: '1.0.0',
instructions: '欢迎来到问候服务器!使用 helloMessage 工具获取问候。',
}
}
}),
],
controllers: [
McpGreetController,
],
providers: [
GreetToolService,
AuthGuard
],
})
export class AppModule {}
```
## 高级:多个服务器
对于需要多个 MCP 服务器的应用程序,您可以定义在特定服务器或多个服务器上可用的工具和资源。
### 多个服务器的工具定义 (`calculator.tool.ts`)
```typescript
import { Injectable } from '@nestjs/common';
import { McpTool } from '@sowonai/nest-mcp-adapter';
import { z } from 'zod';
@Injectable()
export class CalculatorToolService {
@McpTool({
server: ['mcp-calculator', 'mcp-other'], // 在多个服务器上可用
name: 'calculate',
description: '执行数学运算。',
input: {
a: z.number().describe('第一个数字'),
b: z.number().describe('第二个数字'),
operation: z.string().describe('运算类型(加、减、乘、除)')
},
annotations: {
title: '计算',
readOnlyHint: true,
desctructiveHint: false,
}
})
async calculate(params: { a: number, b: number, operation: string }) {
const { a, b, operation } = params;
let result: number;
switch (operation) {
case 'add':
result = a + b;
break;
// ... 其他情况 ...
case 'divide':
if (b === 0) {
throw new Error('不能除以零。');
}
result = a / b;
break;
default:
throw new Error('不支持的操作。');
}
return {
content: [{ type: 'text', text: String(result) }]
};
}
}
```
### 多个服务器的资源定义 (`users.resource.ts`)
```typescript
import { Injectable } from '@nestjs/common';
import { McpResource } from '@sowonai/nest-mcp-adapter';
@Injectable()
export class UsersResourceService {
@McpResource({
server: ['mcp-userinfo', 'mcp-other'], // 在多个服务器上可用
uri: 'users://{userId}/profile',
description: '用户个人信息',
mimeType: 'text/plain',
})
async getUserProfile({ uri, userId }: { uri: string, userId: string }) {
return {
contents: [{
uri,
text: `用户 ID: ${userId}\n姓名: Jane Doe\n职位: 工程师`
}]
};
}
}
```
### 多个服务器的控制器 (`mcp.controller.ts`)
该控制器可以通过使用 URL 参数处理不同 MCP 服务器的请求。
```typescript
import { Controller, Post, Param, Body, UseGuards, Req, Res, HttpCode, UseFilters } from '@nestjs/common';
import { McpHandler } from '@sowonai/nest-mcp-adapter';
import { JsonRpcRequest } from '@sowonai/nest-mcp-adapter';
import { AuthGuard } from './auth.guard';
import { JsonRpcExceptionFilter } from '@sowonai/nest-mcp-adapter';
import { Request, Response } from 'express';
@Controller('mcp')
@UseGuards(AuthGuard)
@UseFilters(JsonRpcExceptionFilter)
export class McpMultiServerController {
constructor(
private readonly mcpHandler: McpHandler
) {}
@Post(':serverName') // serverName 参数用于路由到不同的 MCP 服务器
@HttpCode(202)
async handlePost(
@Param('serverName') serverName: string,
@Req() req: Request,
@Res() res: Response,
@Body() body: JsonRpcRequest,
) {
const result = await this.mcpHandler.handleRequest(serverName, req, res, body);
if (result === null) {
if (!res.writableEnded) {
return res.end();
}
return;
}
return res.json(result);
}
}
```
### 多个服务器的模块 (`app.module.ts`)
```typescript
import { Module } from '@nestjs/common';
import { McpAdapterModule, McpModuleOptions } from '@sowonai/nest-mcp-adapter';
import { AuthGuard } from './auth.guard';
import { CalculatorToolService } from './calculator.tool';
import { UsersResourceService } from './users.resource';
import { McpMultiServerController } from './mcp.controller';
@Module({
imports: [
McpAdapterModule.forRoot({
servers: {
'mcp-calculator': {
version: '1.2.0-calc',
instructions: '计算器服务器:支持加、减、乘、除。',
},
'mcp-userinfo': {
version: '0.8.0-user',
instructions: '用户信息服务器:提供用户个人资料。',
},
'mcp-other': {
version: '0.5.0-other',
instructions: '一个用于杂项工具和资源的共享服务器。',
},
},
}),
],
controllers: [
McpMultiServerController,
],
providers: [
AuthGuard,
CalculatorToolService,
UsersResourceService,
],
})
export class AppModuleMultiServer {}
```
## 示例:使用 HTTP 协议
```typescript
import { NestFactory } from '@nestjs/core';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: false
});
await app.init();
await app.listen(3000);
}
```
## 示例:使用 STDIO 协议
```typescript
import { NestFactory } from '@nestjs/core';
import { StdioExpressAdapter } from '@sowonai/nest-mcp-adapter';
async function bootstrap() {
const adapter = new StdioExpressAdapter('/mcp/mcp-calculator');
const app = await NestFactory.create(AppModule, adapter, {
logger: false
});
await app.init();
await app.listen(0); // 实际上并未绑定
}
```
## 贡献
欢迎贡献!如果您想为此项目做出贡献,请提交拉取请求。所有贡献都受到赞赏。
## 许可证
MIT
连接信息
猜你喜欢
暂无推荐服务器