@nestjs-mcp/server 0.1.0-alpha.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +454 -136
- package/coverage/clover.xml +507 -0
- package/coverage/coverage-final.json +19 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +206 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/controllers/sse/index.html +146 -0
- package/coverage/lcov-report/src/controllers/sse/index.ts.html +91 -0
- package/coverage/lcov-report/src/controllers/sse/sse.controller.ts.html +160 -0
- package/coverage/lcov-report/src/controllers/sse/sse.service.ts.html +403 -0
- package/coverage/lcov-report/src/controllers/streamable/index.html +146 -0
- package/coverage/lcov-report/src/controllers/streamable/index.ts.html +91 -0
- package/coverage/lcov-report/src/controllers/streamable/streamable.controller.ts.html +157 -0
- package/coverage/lcov-report/src/controllers/streamable/streamable.service.ts.html +655 -0
- package/coverage/lcov-report/src/decorators/capabilities.constants.ts.html +106 -0
- package/coverage/lcov-report/src/decorators/capabilities.decorators.ts.html +535 -0
- package/coverage/lcov-report/src/decorators/index.html +146 -0
- package/coverage/lcov-report/src/decorators/index.ts.html +91 -0
- package/coverage/lcov-report/src/index.html +131 -0
- package/coverage/lcov-report/src/index.ts.html +118 -0
- package/coverage/lcov-report/src/interfaces/capabilities.interface.ts.html +703 -0
- package/coverage/lcov-report/src/interfaces/index.html +131 -0
- package/coverage/lcov-report/src/interfaces/index.ts.html +91 -0
- package/coverage/lcov-report/src/mcp.module.ts.html +817 -0
- package/coverage/lcov-report/src/registry/discovery.service.ts.html +433 -0
- package/coverage/lcov-report/src/registry/index.html +161 -0
- package/coverage/lcov-report/src/registry/index.ts.html +91 -0
- package/coverage/lcov-report/src/registry/logger.service.ts.html +514 -0
- package/coverage/lcov-report/src/registry/registry.service.ts.html +1183 -0
- package/coverage/lcov-report/src/services/index.html +116 -0
- package/coverage/lcov-report/src/services/session.manager.ts.html +163 -0
- package/coverage/lcov.info +912 -0
- package/dist/controllers/sse/sse.controller.d.ts +1 -3
- package/dist/controllers/sse/sse.controller.js +2 -8
- package/dist/controllers/sse/sse.controller.js.map +1 -1
- package/dist/interfaces/capabilities.interface.d.ts +1 -1
- package/dist/interfaces/{context.interface.d.ts → guards.interface.d.ts} +0 -2
- package/dist/interfaces/{message.types.js → guards.interface.js} +1 -1
- package/dist/interfaces/guards.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +1 -1
- package/dist/interfaces/index.js +1 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/interfaces/mcp-server-options.interface.d.ts +2 -2
- package/dist/mcp.module.js +1 -18
- package/dist/mcp.module.js.map +1 -1
- package/dist/registry/registry.service.d.ts +1 -3
- package/dist/registry/registry.service.js +3 -8
- package/dist/registry/registry.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +20 -18
- package/src/controllers/sse/sse.service.ts +21 -5
- package/src/controllers/streamable/streamable.service.ts +45 -23
- package/src/interfaces/capabilities.interface.ts +112 -1
- package/src/interfaces/context.interface.ts +21 -6
- package/src/mcp.module.ts +4 -10
- package/src/registry/registry.service.ts +94 -10
- package/src/services/session.manager.ts +26 -0
- package/dist/interceptors/message.interceptor.d.ts +0 -10
- package/dist/interceptors/message.interceptor.js +0 -61
- package/dist/interceptors/message.interceptor.js.map +0 -1
- package/dist/interfaces/context.interface.js +0 -3
- package/dist/interfaces/context.interface.js.map +0 -1
- package/dist/interfaces/message.types.d.ts +0 -8
- package/dist/interfaces/message.types.js.map +0 -1
- package/dist/services/message.service.d.ts +0 -7
- package/dist/services/message.service.js +0 -25
- package/dist/services/message.service.js.map +0 -1
- package/src/interceptors/message.interceptor.ts +0 -70
- package/src/services/message.service.ts +0 -18
package/README.md
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
# MCP Server NestJS Module Library <!-- omit in toc -->
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@nestjs-mcp/server)
|
|
4
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
5
|
+
[](https://www.npmjs.com/package/@nestjs-mcp/server)
|
|
6
|
+
[](https://github.com/adrian-d-hidalgo/nestjs-mcp-server/actions/workflows/run-tests.yml)
|
|
7
|
+
[](https://codecov.io/gh/adrian-d-hidalgo/nestjs-mcp-server)
|
|
8
|
+
[](https://snyk.io/test/github/adrian-d-hidalgo/nestjs-mcp-server)
|
|
4
9
|
[](./LICENSE)
|
|
10
|
+
[](./CONTRIBUTING.md)
|
|
5
11
|
|
|
6
12
|
---
|
|
7
13
|
|
|
@@ -24,18 +30,24 @@
|
|
|
24
30
|
- [Prompt](#prompt)
|
|
25
31
|
- [Module API](#module-api)
|
|
26
32
|
- [forRoot](#mcpmoduleforroot)
|
|
33
|
+
- [forRootAsync](#mcpmoduleforrootasync)
|
|
27
34
|
- [forFeature](#mcpmoduleforfeature)
|
|
28
|
-
|
|
35
|
+
- [Module Usage](#module-usage)
|
|
36
|
+
- [1. Global Registration with `McpModule.forRoot`](#1-global-registration-with-mcpmoduleforroot)
|
|
37
|
+
- [2. Feature Module Registration with `McpModule.forFeature`](#2-feature-module-registration-with-mcpmoduleforfeature)
|
|
29
38
|
- [Capabilities](#capabilities)
|
|
30
|
-
- [
|
|
31
|
-
- [
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
39
|
+
- [Resolver Decorator](#resolver-decorator)
|
|
40
|
+
- [Prompt Decorator](#prompt-decorator)
|
|
41
|
+
- [Resource Decorator](#resource-decorator)
|
|
42
|
+
- [Tool Decorator](#tool-decorator)
|
|
34
43
|
- [Guards](#guards)
|
|
35
|
-
- [Global-level guards
|
|
36
|
-
- [Resolver-level guards
|
|
37
|
-
- [Method-level guards
|
|
44
|
+
- [Global-level guards](#global-level-guards)
|
|
45
|
+
- [Resolver-level guards](#resolver-level-guards)
|
|
46
|
+
- [Method-level guards](#method-level-guards)
|
|
38
47
|
- [Guard Example](#guard-example)
|
|
48
|
+
- [MCP Execution Context](#mcp-execution-context)
|
|
49
|
+
- [Session Management](#session-management)
|
|
50
|
+
- [Transport Options](#transport-options)
|
|
39
51
|
- [Inspector Playground](#inspector-playground)
|
|
40
52
|
- [Examples](#examples)
|
|
41
53
|
- [Changelog](#changelog)
|
|
@@ -47,9 +59,11 @@
|
|
|
47
59
|
## Installation
|
|
48
60
|
|
|
49
61
|
```sh
|
|
50
|
-
|
|
62
|
+
npm install @nestjs-mcp/server @modelcontextprotocol/sdk zod
|
|
51
63
|
# or
|
|
52
|
-
|
|
64
|
+
yarn add @nestjs-mcp/server @modelcontextprotocol/sdk zod
|
|
65
|
+
# or
|
|
66
|
+
pnpm add @nestjs-mcp/server @modelcontextprotocol/sdk zod
|
|
53
67
|
```
|
|
54
68
|
|
|
55
69
|
---
|
|
@@ -60,14 +74,13 @@ Register the MCP module in your NestJS app and expose a simple tool:
|
|
|
60
74
|
|
|
61
75
|
```ts
|
|
62
76
|
import { Module } from '@nestjs/common';
|
|
63
|
-
import { Injectable } from '@nestjs/common';
|
|
64
77
|
|
|
65
78
|
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
|
|
66
79
|
|
|
67
|
-
import { Tool } from '@nestjs-mcp/server';
|
|
80
|
+
import { Resolver, Tool, McpModule } from '@nestjs-mcp/server';
|
|
68
81
|
|
|
69
|
-
@
|
|
70
|
-
export class
|
|
82
|
+
@Resolver()
|
|
83
|
+
export class HealthResolver {
|
|
71
84
|
/**
|
|
72
85
|
* Simple health check tool
|
|
73
86
|
*/
|
|
@@ -91,7 +104,7 @@ export class AppService {
|
|
|
91
104
|
version: '1.0.0',
|
|
92
105
|
}),
|
|
93
106
|
],
|
|
94
|
-
providers: [
|
|
107
|
+
providers: [HealthResolver],
|
|
95
108
|
})
|
|
96
109
|
export class AppModule {}
|
|
97
110
|
```
|
|
@@ -138,19 +151,31 @@ A Prompt defines a conversational flow, template, or interaction pattern for LLM
|
|
|
138
151
|
|
|
139
152
|
### `McpModule.forRoot`
|
|
140
153
|
|
|
141
|
-
Registers the MCP Server globally in your NestJS application.
|
|
154
|
+
Registers the MCP Server globally in your NestJS application.
|
|
142
155
|
|
|
143
156
|
**Parameters:**
|
|
144
157
|
|
|
145
|
-
- `options:
|
|
158
|
+
- `options: McpModuleOptions` — Main server configuration object:
|
|
159
|
+
- `name: string`: The name of your MCP server.
|
|
160
|
+
- `version: string`: The version of your MCP server.
|
|
161
|
+
- `instructions?: string`: Optional description of the MCP server for the client.
|
|
162
|
+
- `capabilities?: Record<string, unknown>`: Optional additional capabilities metadata.
|
|
163
|
+
- `providers?: Provider[]`: Optional array of NestJS providers to include in the module.
|
|
164
|
+
- `imports?: any[]`: Optional array of NestJS modules to import.
|
|
165
|
+
- `logging?: McpLoggingOptions`: Optional logging configuration:
|
|
166
|
+
- `enabled?: boolean` (default: `true`): Enable/disable logging.
|
|
167
|
+
- `level?: 'error' | 'warn' | 'log' | 'debug' | 'verbose'` (default: `'verbose'`): Set the logging level.
|
|
168
|
+
- `transports?: McpModuleTransportOptions`: Optional transport configuration (see [Transport Options](#transport-options)).
|
|
169
|
+
- `protocolOptions?: Record<string, unknown>`: Optional parameters passed directly to the underlying `@modelcontextprotocol/sdk` server instance.
|
|
146
170
|
|
|
147
171
|
**Returns:**
|
|
148
172
|
|
|
149
|
-
- A dynamic NestJS module with all MCP providers registered
|
|
173
|
+
- A dynamic NestJS module with all MCP providers registered.
|
|
150
174
|
|
|
151
175
|
**Example:**
|
|
152
176
|
|
|
153
177
|
```ts
|
|
178
|
+
import { Module } from '@nestjs/common';
|
|
154
179
|
import { McpModule } from '@nestjs-mcp/server';
|
|
155
180
|
|
|
156
181
|
@Module({
|
|
@@ -158,6 +183,9 @@ import { McpModule } from '@nestjs-mcp/server';
|
|
|
158
183
|
McpModule.forRoot({
|
|
159
184
|
name: 'My Server',
|
|
160
185
|
version: '1.0.0',
|
|
186
|
+
instructions: 'A server providing utility tools and data.',
|
|
187
|
+
logging: { level: 'log' },
|
|
188
|
+
transports: { sse: { enabled: false } }, // Disable SSE transport
|
|
161
189
|
// ...other MCP options
|
|
162
190
|
}),
|
|
163
191
|
],
|
|
@@ -165,28 +193,84 @@ import { McpModule } from '@nestjs-mcp/server';
|
|
|
165
193
|
export class AppModule {}
|
|
166
194
|
```
|
|
167
195
|
|
|
196
|
+
### `McpModule.forRootAsync`
|
|
197
|
+
|
|
198
|
+
Registers the MCP Server globally using asynchronous options, useful for integrating with configuration modules like `@nestjs/config`.
|
|
199
|
+
|
|
200
|
+
**Parameters:**
|
|
201
|
+
|
|
202
|
+
- `options: McpModuleAsyncOptions` — Asynchronous configuration object:
|
|
203
|
+
- `imports?: any[]`: Optional modules to import before the factory runs.
|
|
204
|
+
- `useFactory: (...args: any[]) => Promise<McpModuleOptions> | McpModuleOptions`: A factory function that returns the `McpModuleOptions`.
|
|
205
|
+
- `inject?: any[]`: Optional providers to inject into the `useFactory`.
|
|
206
|
+
|
|
207
|
+
**Returns:**
|
|
208
|
+
|
|
209
|
+
- A dynamic NestJS module.
|
|
210
|
+
|
|
211
|
+
**Example (with ConfigModule):**
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { Module } from '@nestjs/common';
|
|
215
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
216
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
217
|
+
|
|
218
|
+
@Module({
|
|
219
|
+
imports: [
|
|
220
|
+
ConfigModule.forRoot(), // Make sure ConfigModule is imported
|
|
221
|
+
McpModule.forRootAsync({
|
|
222
|
+
imports: [ConfigModule], // Import ConfigModule here too
|
|
223
|
+
useFactory: (configService: ConfigService) => ({
|
|
224
|
+
name: configService.get<string>('MCP_SERVER_NAME', 'Default Server'),
|
|
225
|
+
version: configService.get<string>('MCP_SERVER_VERSION', '1.0.0'),
|
|
226
|
+
instructions: configService.get<string>('MCP_SERVER_DESC'),
|
|
227
|
+
logging: {
|
|
228
|
+
level: configService.get('MCP_LOG_LEVEL', 'verbose'),
|
|
229
|
+
},
|
|
230
|
+
// ... other options from configService
|
|
231
|
+
}),
|
|
232
|
+
inject: [ConfigService], // Inject ConfigService into the factory
|
|
233
|
+
}),
|
|
234
|
+
],
|
|
235
|
+
})
|
|
236
|
+
export class AppModule {}
|
|
237
|
+
```
|
|
238
|
+
|
|
168
239
|
### `McpModule.forFeature`
|
|
169
240
|
|
|
170
|
-
Registers additional MCP resources, tools, or prompts
|
|
241
|
+
Registers additional MCP resources, tools, or prompts within a feature module. Use this to organize large servers into multiple modules. Resolvers containing MCP capabilities must be included in the `providers` array of the feature module.
|
|
171
242
|
|
|
172
243
|
**Parameters:**
|
|
173
244
|
|
|
174
|
-
- `
|
|
245
|
+
- `options?: McpFeatureOptions` (Currently unused, reserved for future enhancements).
|
|
175
246
|
|
|
176
247
|
**Returns:**
|
|
177
248
|
|
|
178
|
-
- A dynamic module
|
|
249
|
+
- A dynamic module.
|
|
179
250
|
|
|
180
251
|
**Example:**
|
|
181
252
|
|
|
182
253
|
```ts
|
|
254
|
+
// src/status/status.resolver.ts
|
|
255
|
+
import { Resolver, Tool } from '@nestjs-mcp/server';
|
|
256
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
|
|
257
|
+
|
|
258
|
+
@Resolver('status')
|
|
259
|
+
export class StatusResolver {
|
|
260
|
+
@Tool({ name: 'health_check' })
|
|
261
|
+
healthCheck(): CallToolResult {
|
|
262
|
+
return { content: [{ type: 'text', text: 'OK' }] };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/status/status.module.ts
|
|
267
|
+
import { Module } from '@nestjs/common';
|
|
183
268
|
import { McpModule } from '@nestjs-mcp/server';
|
|
269
|
+
import { StatusResolver } from './status.resolver';
|
|
184
270
|
|
|
185
271
|
@Module({
|
|
186
|
-
imports: [McpModule.forFeature()],
|
|
187
|
-
providers: [
|
|
188
|
-
/*Your Providers with Mcp Capabilities*/
|
|
189
|
-
],
|
|
272
|
+
imports: [McpModule.forFeature()], // Import forFeature here
|
|
273
|
+
providers: [StatusResolver], // Register your resolver
|
|
190
274
|
})
|
|
191
275
|
export class StatusModule {}
|
|
192
276
|
```
|
|
@@ -236,9 +320,9 @@ import { ToolsResolver } from './tools.resolver';
|
|
|
236
320
|
export class ToolsModule {}
|
|
237
321
|
```
|
|
238
322
|
|
|
239
|
-
- Use `forRoot` only once in your root module.
|
|
240
|
-
- Use `forFeature`
|
|
241
|
-
-
|
|
323
|
+
- Use `forRoot` or `forRootAsync` **only once** in your root module (`AppModule`).
|
|
324
|
+
- Use `forFeature` in any feature module where you define MCP capabilities (`@Resolver` classes).
|
|
325
|
+
- Ensure all Resolvers are listed in the `providers` array of their respective modules.
|
|
242
326
|
|
|
243
327
|
---
|
|
244
328
|
|
|
@@ -248,27 +332,38 @@ This library provides a set of decorators to define MCP capabilities and apply c
|
|
|
248
332
|
|
|
249
333
|
### Resolver Decorator
|
|
250
334
|
|
|
251
|
-
A Resolver is a class that groups related MCP capabilities
|
|
335
|
+
A Resolver is a class that groups related MCP capabilities. **All** MCP capability methods (`@Prompt`, `@Resource`, `@Tool`) **must** belong to a class decorated with `@Resolver`.
|
|
336
|
+
|
|
337
|
+
- **No `@Injectable()` Needed:** Resolver classes are automatically treated as providers by the MCP module and **do not** require the `@Injectable()` decorator.
|
|
338
|
+
- **Dependency Injection:** Standard NestJS dependency injection works within Resolver constructors.
|
|
339
|
+
- **Namespacing:** You can optionally provide a string argument to `@Resolver('my_namespace')` to namespace the capabilities within that resolver.
|
|
340
|
+
- **Guards:** Guards can be applied at the class level using `@UseGuards()`.
|
|
252
341
|
|
|
253
342
|
**Example:**
|
|
254
343
|
|
|
255
344
|
```ts
|
|
256
345
|
import { Resolver, Prompt, Resource, Tool } from '@nestjs-mcp/server';
|
|
346
|
+
// Import any services you need to inject
|
|
347
|
+
import { SomeService } from '../some.service';
|
|
257
348
|
|
|
258
|
-
@Resolver('workspace')
|
|
349
|
+
@Resolver('workspace') // No @Injectable()
|
|
259
350
|
export class MyResolver {
|
|
260
|
-
|
|
261
|
-
|
|
351
|
+
// Inject dependencies as usual
|
|
352
|
+
constructor(private readonly someService: SomeService) {}
|
|
353
|
+
|
|
354
|
+
@Prompt({ name: 'greet_user' }) // Capabilities must be inside a Resolver
|
|
355
|
+
greetPrompt(/*...args...*/) {
|
|
356
|
+
const greeting = this.someService.getGreeting();
|
|
262
357
|
/* ... */
|
|
263
358
|
}
|
|
264
359
|
|
|
265
|
-
@Resource({ name: '
|
|
266
|
-
getUserResource() {
|
|
360
|
+
@Resource({ name: 'user_profile', uri: 'user://{id}' })
|
|
361
|
+
getUserResource(/*...args...*/) {
|
|
267
362
|
/* ... */
|
|
268
363
|
}
|
|
269
364
|
|
|
270
|
-
@Tool({ name: '
|
|
271
|
-
sumTool() {
|
|
365
|
+
@Tool({ name: 'calculate_sum' })
|
|
366
|
+
sumTool(/*...args...*/) {
|
|
272
367
|
/* ... */
|
|
273
368
|
}
|
|
274
369
|
}
|
|
@@ -280,57 +375,123 @@ You can also apply guards at the resolver level:
|
|
|
280
375
|
import { UseGuards, Resolver } from '@nestjs-mcp/server';
|
|
281
376
|
import { MyGuard } from './guards/my.guard';
|
|
282
377
|
|
|
283
|
-
@UseGuards(MyGuard)
|
|
284
|
-
@Resolver('secure')
|
|
378
|
+
@UseGuards(MyGuard) // Applied to all capabilities in this Resolver
|
|
379
|
+
@Resolver('secure') // No @Injectable()
|
|
285
380
|
export class SecureResolver {
|
|
286
|
-
//
|
|
381
|
+
// All capabilities in this resolver will use MyGuard
|
|
287
382
|
}
|
|
288
383
|
```
|
|
289
384
|
|
|
290
385
|
### Prompt Decorator
|
|
291
386
|
|
|
292
|
-
Decorate methods within a Resolver to expose them as MCP Prompts.
|
|
387
|
+
Decorate methods within a Resolver class to expose them as MCP Prompts. Accepts options compatible with `server.prompt()` from `@modelcontextprotocol/sdk`. **The `name` should use `snake_case`.**
|
|
293
388
|
|
|
294
389
|
```ts
|
|
295
|
-
import { Prompt } from '@nestjs-mcp/server';
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
390
|
+
import { Prompt, Resolver } from '@nestjs-mcp/server';
|
|
391
|
+
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Import type for extra info
|
|
392
|
+
import { z } from 'zod'; // Example if using Zod schema
|
|
393
|
+
|
|
394
|
+
// Optional: Define schema if needed
|
|
395
|
+
// const SummaryArgs = z.object({ topic: z.string() });
|
|
396
|
+
|
|
397
|
+
@Resolver('prompts') // Must be in a Resolver class
|
|
398
|
+
export class MyPrompts {
|
|
399
|
+
@Prompt({
|
|
400
|
+
name: 'generate_summary',
|
|
401
|
+
description: 'Generates a summary for the given text.',
|
|
402
|
+
// argsSchema: SummaryArgs
|
|
403
|
+
})
|
|
404
|
+
generateSummaryPrompt(
|
|
405
|
+
// params: z.infer<typeof SummaryArgs>, // Arguments based on argsSchema (if defined)
|
|
406
|
+
extra: RequestHandlerExtra, // Contains sessionId and other metadata
|
|
407
|
+
) {
|
|
408
|
+
console.log(`Generating summary for session: ${extra.sessionId}`);
|
|
409
|
+
/* ... return CallPromptResult ... */
|
|
410
|
+
return { content: [{ type: 'text', text: 'Summary generated.' }] };
|
|
302
411
|
}
|
|
303
412
|
}
|
|
304
413
|
```
|
|
305
414
|
|
|
306
415
|
### Resource Decorator
|
|
307
416
|
|
|
308
|
-
Decorate methods within a Resolver to expose them as MCP Resources.
|
|
417
|
+
Decorate methods within a Resolver class to expose them as MCP Resources. Accepts options compatible with `server.resource()` from `@modelcontextprotocol/sdk`. **The `name` should use `snake_case`.**
|
|
309
418
|
|
|
310
419
|
```ts
|
|
311
|
-
import { Resource } from '@nestjs-mcp/server';
|
|
420
|
+
import { Resource, Resolver } from '@nestjs-mcp/server';
|
|
421
|
+
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Import type for extra info
|
|
422
|
+
import { URL } from 'url'; // Type for URI resource
|
|
423
|
+
import { z } from 'zod'; // Example if using Zod template
|
|
424
|
+
|
|
425
|
+
// Optional: Define template schema if needed
|
|
426
|
+
// const DocQueryTemplate = z.object({ query: z.string() });
|
|
427
|
+
|
|
428
|
+
@Resolver('data') // Must be in a Resolver class
|
|
429
|
+
export class MyResources {
|
|
430
|
+
@Resource({
|
|
431
|
+
name: 'user_profile',
|
|
432
|
+
uri: 'user://profiles/{userId}',
|
|
433
|
+
// metadata: { description: '...' } // Optional
|
|
434
|
+
})
|
|
435
|
+
getUserProfile(
|
|
436
|
+
uri: URL, // First argument is the parsed URI
|
|
437
|
+
// metadata: Record<string, any> // Second argument if is defined
|
|
438
|
+
extra: RequestHandlerExtra, // Contains sessionId and other metadata
|
|
439
|
+
) {
|
|
440
|
+
const userId = uri.pathname.split('/').pop(); // Example: Extract ID from URI
|
|
441
|
+
console.log(`Fetching profile for ${userId}, session: ${extra.sessionId}`);
|
|
442
|
+
/* ... return CallResourceResult ... */
|
|
443
|
+
return { content: [{ type: 'text', text: `Profile data for ${userId}` }] };
|
|
444
|
+
}
|
|
312
445
|
|
|
313
|
-
@
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
446
|
+
@Resource({
|
|
447
|
+
name: 'document_list',
|
|
448
|
+
template: { type: 'string', description: 'Document content query' }, // Simple template example
|
|
449
|
+
// metadata: { list: true } // Optional
|
|
450
|
+
})
|
|
451
|
+
findDocuments(
|
|
452
|
+
uri: URL, // First arg based on simple template type
|
|
453
|
+
variables: Record<string, string>, // Second arg is path params (if any)
|
|
454
|
+
extra: RequestHandlerExtra, // Contains sessionId and other metadata
|
|
455
|
+
) {
|
|
456
|
+
console.log(
|
|
457
|
+
`Finding documents matching '${query}', session: ${extra.sessionId}`,
|
|
458
|
+
);
|
|
459
|
+
/* ... return CallResourceResult ... */
|
|
460
|
+
return { content: [{ type: 'text', text: 'List of documents.' }] };
|
|
318
461
|
}
|
|
319
462
|
}
|
|
320
463
|
```
|
|
321
464
|
|
|
322
465
|
### Tool Decorator
|
|
323
466
|
|
|
324
|
-
Decorate methods within a Resolver to expose them as MCP Tools.
|
|
467
|
+
Decorate methods within a Resolver class to expose them as MCP Tools. Accepts options compatible with `server.tool()` from `@modelcontextprotocol/sdk`. **The `name` should use `snake_case`.**
|
|
325
468
|
|
|
326
469
|
```ts
|
|
327
|
-
import { Tool } from '@nestjs-mcp/server';
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
470
|
+
import { Tool, Resolver } from '@nestjs-mcp/server';
|
|
471
|
+
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Import type for extra info
|
|
472
|
+
import { z } from 'zod'; // Example using Zod for schema
|
|
473
|
+
|
|
474
|
+
// Example Zod schema for parameters
|
|
475
|
+
const SumParams = z.object({
|
|
476
|
+
num1: z.number(),
|
|
477
|
+
num2: z.number(),
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
@Resolver('utils') // Must be in a Resolver class
|
|
481
|
+
export class MyTools {
|
|
482
|
+
@Tool({
|
|
483
|
+
name: 'calculate_sum',
|
|
484
|
+
description: 'Calculates the sum of two numbers.',
|
|
485
|
+
paramSchema: SumParams, // Use the Zod schema
|
|
486
|
+
})
|
|
487
|
+
sumTool(
|
|
488
|
+
params: z.infer<typeof SumParams>, // First arg is typed parameters from schema
|
|
489
|
+
extra: RequestHandlerExtra, // Contains sessionId and other metadata
|
|
490
|
+
) {
|
|
491
|
+
console.log(`Calculating sum for session: ${extra.sessionId}`);
|
|
492
|
+
const result = params.num1 + params.num2;
|
|
493
|
+
/* ... return CallToolResult ... */
|
|
494
|
+
return { content: [{ type: 'text', text: `Result: ${result}` }] };
|
|
334
495
|
}
|
|
335
496
|
}
|
|
336
497
|
```
|
|
@@ -341,20 +502,22 @@ export class MyResolver {
|
|
|
341
502
|
|
|
342
503
|
Apply one or more guards to a Resolver, to individual methods, or globally. Guards must implement the NestJS `CanActivate` interface.
|
|
343
504
|
|
|
344
|
-
### Global-level guards
|
|
505
|
+
### Global-level guards
|
|
345
506
|
|
|
346
|
-
This approach uses the standard NestJS global guard system. A global guard will protect all
|
|
507
|
+
This approach uses the standard NestJS global guard system (`APP_GUARD`). A global guard will protect **all** NestJS routes, including the MCP transport endpoints (like `/mcp` or `/sse`). Use this for broad authentication or checks that apply before any MCP-specific logic runs.
|
|
347
508
|
|
|
348
509
|
```ts
|
|
349
510
|
// src/guards/global-auth.guard.ts
|
|
350
511
|
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
|
512
|
+
import { Request } from 'express';
|
|
351
513
|
|
|
352
514
|
@Injectable()
|
|
353
515
|
export class GlobalAuthGuard implements CanActivate {
|
|
354
516
|
canActivate(context: ExecutionContext): boolean {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
517
|
+
const request = context.switchToHttp().getRequest<Request>();
|
|
518
|
+
const apiKey = request.headers['x-api-key'];
|
|
519
|
+
// Example: Check for a valid API key
|
|
520
|
+
return !!apiKey && apiKey === 'EXPECTED_KEY';
|
|
358
521
|
}
|
|
359
522
|
}
|
|
360
523
|
```
|
|
@@ -362,21 +525,15 @@ export class GlobalAuthGuard implements CanActivate {
|
|
|
362
525
|
Register the guard globally in your main module:
|
|
363
526
|
|
|
364
527
|
```ts
|
|
528
|
+
// src/app.module.ts
|
|
365
529
|
import { Module } from '@nestjs/common';
|
|
366
530
|
import { APP_GUARD } from '@nestjs/core';
|
|
367
531
|
import { McpModule } from '@nestjs-mcp/server';
|
|
368
532
|
import { GlobalAuthGuard } from './guards/global-auth.guard';
|
|
369
|
-
import { PromptsResolver } from './prompts.resolver';
|
|
370
533
|
|
|
371
534
|
@Module({
|
|
372
|
-
imports: [
|
|
373
|
-
McpModule.forRoot({
|
|
374
|
-
name: 'My MCP Server',
|
|
375
|
-
version: '1.0.0',
|
|
376
|
-
}),
|
|
377
|
-
],
|
|
535
|
+
imports: [McpModule.forRoot(/*...*/)],
|
|
378
536
|
providers: [
|
|
379
|
-
PromptsResolver,
|
|
380
537
|
{
|
|
381
538
|
provide: APP_GUARD,
|
|
382
539
|
useClass: GlobalAuthGuard,
|
|
@@ -386,116 +543,275 @@ import { PromptsResolver } from './prompts.resolver';
|
|
|
386
543
|
export class AppModule {}
|
|
387
544
|
```
|
|
388
545
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
- The guard will run for every request handled by your NestJS application, including all MCP endpoints.
|
|
392
|
-
- You can implement any logic in canActivate, such as checking headers, tokens, or user roles.
|
|
393
|
-
- This approach is fully compatible with NestJS and your MCP Server module.
|
|
546
|
+
### Resolver-level guards
|
|
394
547
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
This is a custom feature of this library. Resolver-level guards are applied using the `@UseGuards` decorator on a Resolver class. All MCP methods (`@Prompt`, `@Resource`, `@Tool`) in the resolver will be protected by these guards. Use this to enforce logic (e.g., role checks) for a specific group of capabilities.
|
|
548
|
+
This is a custom feature of this library. Resolver-level guards are applied using the `@UseGuards()` decorator (exported from `@nestjs-mcp/server`) on a Resolver class. All MCP methods (`@Prompt`, `@Resource`, `@Tool`) **within that specific resolver** will be protected by these guards. Use this to enforce logic (e.g., role checks) for a group of related capabilities.
|
|
398
549
|
|
|
399
550
|
```ts
|
|
400
551
|
import { UseGuards, Resolver, Prompt } from '@nestjs-mcp/server';
|
|
401
|
-
import {
|
|
552
|
+
import { RoleGuard } from './guards/role.guard';
|
|
402
553
|
|
|
403
|
-
@UseGuards(
|
|
404
|
-
@Resolver('
|
|
405
|
-
export class
|
|
406
|
-
@Prompt({ name: '
|
|
407
|
-
|
|
554
|
+
@UseGuards(RoleGuard)
|
|
555
|
+
@Resolver('admin')
|
|
556
|
+
export class AdminResolver {
|
|
557
|
+
@Prompt({ name: 'admin_action' })
|
|
558
|
+
adminAction(/*...*/) {
|
|
408
559
|
/* ... */
|
|
409
560
|
}
|
|
561
|
+
// ... other admin capabilities
|
|
410
562
|
}
|
|
411
563
|
```
|
|
412
564
|
|
|
413
|
-
### Method-level guards
|
|
565
|
+
### Method-level guards
|
|
414
566
|
|
|
415
|
-
This is a custom feature of this library. Method-level guards are applied using the `@UseGuards` decorator directly on
|
|
567
|
+
This is a custom feature of this library. Method-level guards are applied using the `@UseGuards()` decorator directly on an MCP capability method (`@Prompt`, `@Resource`, `@Tool`). Only the decorated method will be protected by these guards. Use this for fine-grained access control on specific capabilities.
|
|
416
568
|
|
|
417
569
|
```ts
|
|
418
|
-
import { UseGuards, Resolver, Prompt } from '@nestjs-mcp/server';
|
|
419
|
-
import {
|
|
570
|
+
import { UseGuards, Resolver, Prompt, Tool } from '@nestjs-mcp/server';
|
|
571
|
+
import { SpecificCheckGuard } from './guards/specific-check.guard';
|
|
420
572
|
|
|
421
573
|
@Resolver('mixed')
|
|
422
574
|
export class MixedResolver {
|
|
423
|
-
@Prompt({ name: '
|
|
575
|
+
@Prompt({ name: 'public_prompt' })
|
|
424
576
|
publicPrompt() {
|
|
425
|
-
/*
|
|
577
|
+
/* Publicly accessible */
|
|
426
578
|
}
|
|
427
579
|
|
|
428
|
-
@UseGuards(
|
|
429
|
-
@
|
|
430
|
-
|
|
431
|
-
/*
|
|
580
|
+
@UseGuards(SpecificCheckGuard)
|
|
581
|
+
@Tool({ name: 'protected_tool' })
|
|
582
|
+
protectedTool(/*...*/) {
|
|
583
|
+
/* Requires SpecificCheckGuard to pass */
|
|
432
584
|
}
|
|
433
585
|
}
|
|
434
586
|
```
|
|
435
587
|
|
|
588
|
+
**Important:** Resolver and Method-level guards **only run for MCP capability invocations**, not for the initial connection establishment handled by global guards. They use the custom `McpExecutionContext`.
|
|
589
|
+
|
|
436
590
|
### Guard Example
|
|
437
591
|
|
|
592
|
+
A guard for Resolver or Method-level protection:
|
|
593
|
+
|
|
438
594
|
```ts
|
|
439
|
-
|
|
440
|
-
import {
|
|
595
|
+
// src/guards/my-mcp.guard.ts
|
|
596
|
+
import { CanActivate, Injectable } from '@nestjs/common';
|
|
597
|
+
import { McpExecutionContext, SessionManager } from '@nestjs-mcp/server';
|
|
598
|
+
|
|
599
|
+
@Injectable()
|
|
600
|
+
export class MyMcpGuard implements CanActivate {
|
|
601
|
+
constructor(private readonly sessionManager: SessionManager) {}
|
|
441
602
|
|
|
442
|
-
export class MyGuard implements CanActivate {
|
|
443
603
|
canActivate(context: McpExecutionContext): boolean {
|
|
444
|
-
|
|
604
|
+
const sessionId = context.getSessionId();
|
|
605
|
+
if (!sessionId) return false;
|
|
606
|
+
|
|
607
|
+
const handlerArgs = context.getArgs();
|
|
608
|
+
|
|
609
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
610
|
+
const request = session?.request;
|
|
611
|
+
const userAgent = request?.headers['user-agent'];
|
|
612
|
+
|
|
613
|
+
console.log(`Guard activated for session ${sessionId} from ${userAgent}`);
|
|
614
|
+
console.log('Handler args:', handlerArgs);
|
|
615
|
+
|
|
445
616
|
return true;
|
|
446
617
|
}
|
|
447
618
|
}
|
|
448
619
|
```
|
|
449
620
|
|
|
450
|
-
###
|
|
621
|
+
### MCP Execution Context
|
|
451
622
|
|
|
452
|
-
When implementing
|
|
623
|
+
When implementing **Resolver-level** or **Method-level** guards using `@UseGuards()` from this library, your `canActivate` method receives an `McpExecutionContext` instance. This context provides access to MCP-specific information:
|
|
453
624
|
|
|
454
|
-
```
|
|
455
|
-
import { CanActivate } from '@nestjs/common';
|
|
456
|
-
import { McpExecutionContext } from '@nestjs-mcp/server';
|
|
457
|
-
import { Request
|
|
625
|
+
```typescript
|
|
626
|
+
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
|
627
|
+
import { McpExecutionContext, SessionManager } from '@nestjs-mcp/server';
|
|
628
|
+
import { Request } from 'express';
|
|
458
629
|
|
|
459
630
|
@Injectable()
|
|
460
631
|
export class McpAuthGuard implements CanActivate {
|
|
632
|
+
constructor(private readonly sessionManager: SessionManager) {}
|
|
633
|
+
|
|
461
634
|
canActivate(context: McpExecutionContext): boolean {
|
|
462
|
-
|
|
463
|
-
|
|
635
|
+
const sessionId = context.getSessionId();
|
|
636
|
+
if (!sessionId) {
|
|
637
|
+
console.error('Guard Error: MCP Session ID not found in context.');
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const handlerArgs = context.getArgs<any>();
|
|
642
|
+
console.log('MCP Handler Arguments:', handlerArgs);
|
|
643
|
+
|
|
644
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
645
|
+
if (!session) {
|
|
646
|
+
console.error(`Guard Error: Session not found for ID: ${sessionId}`);
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
const request = session.request as Request;
|
|
650
|
+
|
|
651
|
+
const authHeader = request.headers.authorization;
|
|
652
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
653
|
+
console.log('Guard Denied: Missing or invalid Bearer token.');
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
const token = authHeader.split(' ')[1];
|
|
657
|
+
const isValidToken = token === 'VALID_TOKEN';
|
|
658
|
+
|
|
659
|
+
if (isValidToken) {
|
|
660
|
+
console.log(`Guard Passed for session ${sessionId} with token.`);
|
|
661
|
+
return true;
|
|
662
|
+
} else {
|
|
663
|
+
console.log(`Guard Denied: Invalid token for session ${sessionId}.`);
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
**Key points for `McpExecutionContext`:**
|
|
671
|
+
|
|
672
|
+
- `getSessionId()`: Retrieves the unique ID for the current MCP session. **Crucial** for relating the guard check to the session state stored by `SessionManager`.
|
|
673
|
+
- Arguments (`handlerArgs`): Provides the arguments passed specifically to the MCP handler method (`@Tool`, `@Prompt`, `@Resource`) being invoked. The structure of these arguments depends on the capability type and its definition (e.g., `params` for tools, `query`/`params` for resources). You access these via `context.getArgs()`, but be mindful of the actual structure based on the capability.
|
|
674
|
+
- Request Data: Use the `SessionManager` injected into your guard to fetch the session details (including the original `Request`) based on the `sessionId` obtained from the context.
|
|
675
|
+
- `switchToHttp().getResponse()` / `switchToHttp().getNext()`: These will throw errors as the Response object is not directly available or relevant in this context.
|
|
676
|
+
|
|
677
|
+
Use `SessionManager` injected into your guard to fetch the session details (including the original `Request`) based on the `sessionId` obtained from the context.
|
|
464
678
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
## Session Management
|
|
682
|
+
|
|
683
|
+
This library includes a `SessionManager` service responsible for tracking active MCP sessions. Each incoming MCP connection establishes a session, identified by a unique `sessionId`. The `SessionManager` typically stores the associated initial `Request` object for each session.
|
|
684
|
+
|
|
685
|
+
**Why is it important?**
|
|
686
|
+
|
|
687
|
+
- **Accessing Request Data:** Since MCP operations (tool calls, prompt executions) might happen independently of the initial HTTP connection (especially with streaming transports like SSE), the `SessionManager` provides a way to retrieve the original `Request` context associated with a specific `sessionId`. This is essential for guards or capability methods (within Resolvers) that need access to request headers, parameters, or other connection-specific details from the original request.
|
|
688
|
+
- **State Management:** While currently focused on storing the request, the `SessionManager` could be extended to store additional session-specific state if needed by your application.
|
|
468
689
|
|
|
469
|
-
|
|
470
|
-
const request = req as Request;
|
|
471
|
-
const response = res as Response;
|
|
690
|
+
**Usage Example (in a Resolver):**
|
|
472
691
|
|
|
473
|
-
|
|
474
|
-
const authHeader = request.headers.authorization;
|
|
692
|
+
Resolvers might need access to the original request, for example, to get user information or API keys passed in headers during the initial connection.
|
|
475
693
|
|
|
476
|
-
|
|
477
|
-
|
|
694
|
+
```typescript
|
|
695
|
+
import { Tool, Resolver, SessionManager } from '@nestjs-mcp/server';
|
|
696
|
+
import { RequestHandlerExtra } from '@nestjs-mcp/server'; // Provides sessionId
|
|
697
|
+
import { Request } from 'express';
|
|
698
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
|
|
699
|
+
import { z } from 'zod';
|
|
700
|
+
|
|
701
|
+
const UserToolParams = z.object({
|
|
702
|
+
user_id: z.string().optional(),
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
@Resolver('user_tools') // No @Injectable() needed
|
|
706
|
+
export class UserToolsResolver {
|
|
707
|
+
// Inject SessionManager
|
|
708
|
+
constructor(private readonly sessionManager: SessionManager) {}
|
|
709
|
+
|
|
710
|
+
@Tool({
|
|
711
|
+
name: 'get_user_agent',
|
|
712
|
+
description:
|
|
713
|
+
'Gets the user agent from the original request for the session.',
|
|
714
|
+
paramSchema: UserToolParams,
|
|
715
|
+
})
|
|
716
|
+
getUserAgent(
|
|
717
|
+
params: z.infer<typeof UserToolParams>,
|
|
718
|
+
extra: RequestHandlerExtra, // Get extra info, including sessionId
|
|
719
|
+
): CallToolResult {
|
|
720
|
+
const sessionId = extra.sessionId;
|
|
721
|
+
if (!sessionId) {
|
|
722
|
+
return {
|
|
723
|
+
content: [{ type: 'text', text: 'Error: Session ID missing.' }],
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Use sessionId to get the session from the manager
|
|
728
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
729
|
+
if (!session) {
|
|
730
|
+
return {
|
|
731
|
+
content: [
|
|
732
|
+
{
|
|
733
|
+
type: 'text',
|
|
734
|
+
text: `Error: Session not found for ID: ${sessionId}`,
|
|
735
|
+
},
|
|
736
|
+
],
|
|
737
|
+
};
|
|
478
738
|
}
|
|
479
739
|
|
|
480
|
-
// Access the
|
|
481
|
-
const
|
|
740
|
+
// Access the original request stored in the session
|
|
741
|
+
const request = session.request as Request;
|
|
742
|
+
const userAgent = request.headers['user-agent'] || 'Unknown';
|
|
482
743
|
|
|
483
|
-
return
|
|
744
|
+
return {
|
|
745
|
+
content: [
|
|
746
|
+
{ type: 'text', text: `Session ${sessionId} User Agent: ${userAgent}` },
|
|
747
|
+
],
|
|
748
|
+
};
|
|
484
749
|
}
|
|
485
750
|
}
|
|
486
751
|
```
|
|
487
752
|
|
|
488
|
-
|
|
753
|
+
In this example:
|
|
754
|
+
|
|
755
|
+
1. The `@Tool` method receives `extra: RequestHandlerExtra`, which contains the `sessionId`.
|
|
756
|
+
2. The `SessionManager` is injected into the `UserToolsResolver`.
|
|
757
|
+
3. The `sessionId` is used with `sessionManager.getSession()` to retrieve the session data.
|
|
758
|
+
4. The original `request` object is accessed from the retrieved session data.
|
|
759
|
+
|
|
760
|
+
The `SessionManager` is automatically registered as a provider when you use `McpModule.forRoot` or `McpModule.forRootAsync` and can be injected like any other NestJS provider.
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## Transport Options
|
|
765
|
+
|
|
766
|
+
The MCP server can communicate over different transport mechanisms. This library includes built-in support for:
|
|
767
|
+
|
|
768
|
+
1. **Streamable (`/mcp` endpoint):** A common transport using standard HTTP POST requests and responses. Suitable for most request/response interactions. Enabled by default.
|
|
769
|
+
2. **SSE (Server-Sent Events) (`/sse` endpoint):** A transport mechanism allowing the server to push updates to the client over a single HTTP connection. Useful for streaming responses or long-running operations. **Note:** This is considered a legacy transport but remains supported for compatibility. Enabled by default.
|
|
770
|
+
|
|
771
|
+
You can configure which transports are enabled globally using the `transports` option in `McpModule.forRoot` or `McpModule.forRootAsync`.
|
|
772
|
+
|
|
773
|
+
**Configuration:**
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
import { Module } from '@nestjs/common';
|
|
777
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
778
|
+
|
|
779
|
+
@Module({
|
|
780
|
+
imports: [
|
|
781
|
+
McpModule.forRoot({
|
|
782
|
+
name: 'My Server',
|
|
783
|
+
version: '1.0.0',
|
|
784
|
+
transports: {
|
|
785
|
+
streamable: { enabled: true }, // Keep streamable enabled (default)
|
|
786
|
+
sse: { enabled: false }, // Disable legacy SSE transport
|
|
787
|
+
},
|
|
788
|
+
}),
|
|
789
|
+
],
|
|
790
|
+
})
|
|
791
|
+
export class AppModule {}
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
**Default Configuration:**
|
|
489
795
|
|
|
490
|
-
|
|
491
|
-
- `message`: The current message from the request, containing:
|
|
492
|
-
- `req`: The Express Request object
|
|
493
|
-
- `res`: The Express Response object
|
|
494
|
-
- `getType()`: Returns the type of execution context (always 'mcp' for MCP operations)
|
|
495
|
-
- `getClass()`: Returns the class of the resolver
|
|
496
|
-
- `getArgs()`: Returns the arguments passed to the method
|
|
796
|
+
If the `transports` option is omitted, both `streamable` (`/mcp`) and `sse` (`/sse`) are enabled by default.
|
|
497
797
|
|
|
498
|
-
|
|
798
|
+
```typescript
|
|
799
|
+
import { Module } from '@nestjs/common';
|
|
800
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
801
|
+
|
|
802
|
+
@Module({
|
|
803
|
+
imports: [
|
|
804
|
+
McpModule.forRoot({
|
|
805
|
+
name: 'My Server',
|
|
806
|
+
version: '1.0.0',
|
|
807
|
+
// Both streamable and sse will be enabled
|
|
808
|
+
}),
|
|
809
|
+
],
|
|
810
|
+
})
|
|
811
|
+
export class AppModule {}
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
Disabling unused transports can slightly reduce the application's surface area and resource usage.
|
|
499
815
|
|
|
500
816
|
---
|
|
501
817
|
|
|
@@ -507,17 +823,19 @@ Use the Inspector Playground to interactively test and debug your MCP server end
|
|
|
507
823
|
- Invoke endpoints and view responses in real time
|
|
508
824
|
- Validate your server implementation against the MCP specification
|
|
509
825
|
|
|
510
|
-
To launch the Inspector Playground:
|
|
826
|
+
To launch the Inspector Playground (make sure your NestJS MCP server is running):
|
|
511
827
|
|
|
512
828
|
```sh
|
|
513
829
|
npx @modelcontextprotocol/inspector
|
|
514
830
|
```
|
|
515
831
|
|
|
832
|
+
It will typically connect to `http://localhost:3000` by default, or you can specify a different target URL.
|
|
833
|
+
|
|
516
834
|
---
|
|
517
835
|
|
|
518
836
|
## Examples
|
|
519
837
|
|
|
520
|
-
The [`examples/`](./examples/) directory contains ready-to-use scenarios demonstrating how to register and expose MCP capabilities
|
|
838
|
+
The [`examples/`](./examples/) directory contains ready-to-use scenarios demonstrating how to register and expose MCP capabilities.
|
|
521
839
|
|
|
522
840
|
Each example is self-contained and follows best practices. For advanced usage, see the code and documentation in each example.
|
|
523
841
|
|