NestJS MCP Server Module
by rekog-labs
# NestJS MCP Server Module
A NestJS module for exposing your services as an MCP (Model Context Protocol) server with Server-Sent Events (SSE) transport. This package simplifies exposing tools that clients can discover and execute via SSE.
## Features
- **SSE Transport**: Built-in `/sse` endpoint for streaming and `/messages` for handling tool execution
- **Tool Discovery**: Automatically discover and register tools using decorators
- **Tool Request Validation**: Define Zod schemas to validate tool requests.
- **Progress Notifications**: Send continuous progress updates from tools to clients.
## Installation
```bash
npm install @rekog/mcp-nest reflect-metadata @modelcontextprotocol/sdk zod
```
## Quick Start
### 1. Import Module
```typescript
// 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. Define Tools
```typescript
// greeting.tool.ts
import { Injectable } from '@nestjs/common';
import { Tool } from '@rekog/mcp-nest';
import { z } from 'zod';
import { Context } from '@rekog/mcp-nest/dist/services/mcp-tools.discovery';
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) {
const greeting = `Hello, ${name}!`;
const totalSteps = 5;
for (let i = 0; i < totalSteps; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
// Send a progress update.
await context.reportProgress({
progress: (i + 1) * 20,
total: 100,
} as Progress);
}
return {
content: [{ type: 'text', text: greeting }],
};
}
}
```
You are done!
## Client Connection
Clients can connect using the MCP SDK:
```typescript
// client.ts
import { Client } from '@modelcontextprotocol/sdk/client';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse';
const client = new Client(
{ name: 'client-name', version: '1.0.0' },
{ capabilities: {} }
);
await client.connect(
new SSEClientTransport(new URL('http://localhost:3000/sse'))
);
// Execute the 'hello-world' tool with progress tracking
const greetResult = await client.callTool(
{
name: 'hello-world',
arguments: {
name: 'MCP User',
},
},
undefined, // responseSchema is optional, or you can define a Zod schema here
{
onprogress: (progress) => {
console.log(
`Progress: ${progress.progress}/${progress.total}`
);
},
},
);
console.log(greetResult.content[0].text); // Output: Hello MCP User! I'm Test User from Test Org.
```
## API Endpoints
- `GET /sse`: SSE connection endpoint
- `POST /messages`: Tool execution endpoint
## Configuration Reference
### `McpOptions`
| Property | Type | Description | Default Value |
|----------------------|---------------------------|-----------------------------------------------------------------------------|---------------|
| `name` | string | Server name | - |
| `version` | string | Server version | - |
| `capabilities` | Record<string, any> | Server capabilities, defines what the server can do. | `{}` |
| `sseEndpoint` | string (optional) | Endpoint for SSE connections. | `'sse'` |
| `messagesEndpoint` | string (optional) | Endpoint for handling tool execution. | `'messages'` |
| `globalApiPrefix` | string (optional) | Global API prefix for all endpoints. | `''` |
### Tool Decorator
The `@Tool` decorator is used to define a method as an MCP tool.
```typescript
@Tool({ name: string, description: string, parameters?: z.ZodObject<any> })
```
- `name`: The name of the tool. This will be used to list it in the `listTools` request.
- `description`: A description of the tool.
- `parameters`: (Optional) A Zod schema defining the expected structure of the tool's input arguments.