@millionfor/nestjs-mcp-server v1.0.0-alpha.3
nestjs-mcp-server
A mcp service encapsulation based on nestjs framework
Install
# npm
npm install @millionfor/nestjs-mcp-server @modelcontextprotocol/sdk zod
# yarn
yarn add @millionfor/nestjs-mcp-server @modelcontextprotocol/sdk zod
# pnpm
pnpm add @millionfor/nestjs-mcp-server @modelcontextprotocol/sdk zod
Usage
1. Import module
Import McpModule
in your module
import { Module } from "@nestjs/common";
import { McpModule } from "@millionfor/nestjs-mcp-server";
@Module({
imports: [
McpModule.register({
controllerBaseUrl: "api/mcp",
mcpServerConfigs: [
{
serverId: "my-mcp-server",
serverInfo: {
name: "my-mcp-server",
version: "1.0.0",
},
},
],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
In addition, you can also import modules through forRoot
and forFeature
, the differences are as follows:
- forRoot: Usually registered in the root module
- forFeature: Share Service instance with forRoot registered module
- register: Register once and do not share with any module
2. Operation McpServer
After creating MCP Server, you can obtain the official sdk's native MCP Server instance through the getServer
method. This instance has no encapsulation and is completely native.
For example, you can register a tool
import { Controller } from "@nestjs/common";
import { McpServerService } from "@millionfor/nestjs-mcp-server";
import { z } from "zod";
@Controller()
export class AppController {
constructor(private readonly mcpServerService: McpServerService) {
this.mcpServerService.getServer("server-id")?.tool(
"get-current-time",
{
format: z
.enum(["iso", "locale", "unix"])
.optional()
.default("iso")
.describe("时间格式: iso, locale, 或 unix"),
},
async ({ format }: { format: "iso" | "locale" | "unix" }) => {
const now = new Date();
let timeValue: string | number;
switch (format) {
case "iso":
timeValue = now.toISOString();
break;
case "locale":
timeValue = now.toLocaleString();
break;
case "unix":
timeValue = now.getTime();
break;
default:
timeValue = now.toISOString();
}
return {
content: [{ type: "text", text: String(timeValue) }],
};
}
);
}
}
3. Manually register the server instance
The above example directly passes in mcpServerConfigs
in McpModule.register
, which creates an MCP Server when the module is initialized.
Of course this is not necessary. You can manually register the MCP Server in the Controller or Service without passing in mcpServerConfigs
:
import { Controller } from "@nestjs/common";
import { McpServerService } from "@millionfor/nestjs-mcp-server";
import { z } from "zod";
@Controller()
export class AppController {
constructor(private readonly mcpServerService: McpServerService) {
// 手动注册一个MCP Server实例
this.mcpServerService.registerServer({
serverId: "another-server",
serverInfo: {
name: "another-mcp-server",
version: "1.0.0",
},
});
}
}
Server access endpoint
After registering the module, the following endpoints are automatically created:
- SSE connection endpoint:
/{controllerBaseUrl}/{serverId}/sse
- Message processing endpoint:
/{controllerBaseUrl}/{serverId}/messages
For example, if you use controllerBaseUrl: 'api/mcp'
and serverId: 'my-mcp-server'
, the access URL is:
http://localhost:3000/api/mcp/my-mcp-server/sse
- for SSE connectionshttp://localhost:3000/api/mcp/my-mcp-server/messages
- for message processing
API
McpModule.register
- controllerBaseUrl: Basic URL path for MCP Controller
- sseEndpoint: SSE connection endpoint name, default is
sse
- messagesEndpoint: Message processing endpoint name, default is
messages
- mcpServerConfigs:
- serverId: McpServer id, use id to manage multiple instances
- serverInfo: As the first parameter, pass it directly into the native MCP TS-SDK McpServer class
- serverOptions: As the second parameter, pass it directly into the native MCP TS-SDK McpServer class
forRoot same as register, forFeature only receives mcpServerConfigs
McpServerService
McpModule export service to manage multiple McpServer instances.
You can inject it into your Controller or Service using the following methods:
registerServer
- Function: Register a McpServer instance
- Parameters:
mcpServerConfigs
same asMcpModule.forRoot
- Return value: Registered McpServer instance
getServer
- Function: Get the specified McpServer instance
- Parameters: serverId
- Return value: McpServer instance
getServerIds
- Function: Get all registered McpServer instance ids
- Return value:
string[]
All registered McpServer instance id arrays
hasServer
- Function: determine whether the specified McpServer instance has been registered
- Parameters: serverId
- Return value: boolean
connect
- Function: Connecting McpServer to the transport layer generally does not need to be used unless you want to manually manage the connection.
- Parameters:
- serverId
- transport, Transport instance
- Return value: void
McpTransportService
McpModule export service to manage multiple SSEServerTransport instances.
It is usually not necessary to use unless you want to manually manage the connection.
The following only lists the possible methods. For more methods, please refer to the source code.
getTransport
- Function: Get a specific transmission connection
- Parameters: serverId, sessionId
- Return value: SSEServerTransport instance
getActiveSessionIds
- Function: Get all active session IDs of McpServer
- Parameters: serverId
- Return value:
string[]
All active session ID array
Advanced Configuration
Custom endpoint name
You can customize the SSE and message endpoint names when module registration:
McpModule.register({
controllerBaseUrl: "api/mcp",
sseEndpoint: "connect", // Default is 'sse'
messagesEndpoint: "rpc", // Default is 'messages'
mcpServerConfigs: [
/* ... */
],
});