@nestjs-mcp/server 0.1.0-alpha.10
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/.copilotignore +38 -0
- package/.devcontainer/Dockerfile.dev +28 -0
- package/.devcontainer/devcontainer.json +56 -0
- package/.devcontainer/docker-compose.yml +15 -0
- package/.dockerignore +37 -0
- package/.prettierrc +4 -0
- package/LICENSE +21 -0
- package/README.md +540 -0
- package/dist/controllers/sse/index.d.ts +2 -0
- package/dist/controllers/sse/index.js +19 -0
- package/dist/controllers/sse/index.js.map +1 -0
- package/dist/controllers/sse/sse.controller.d.ts +10 -0
- package/dist/controllers/sse/sse.controller.js +57 -0
- package/dist/controllers/sse/sse.controller.js.map +1 -0
- package/dist/controllers/sse/sse.service.d.ts +16 -0
- package/dist/controllers/sse/sse.service.js +78 -0
- package/dist/controllers/sse/sse.service.js.map +1 -0
- package/dist/controllers/streamable/index.d.ts +2 -0
- package/dist/controllers/streamable/index.js +19 -0
- package/dist/controllers/streamable/index.js.map +1 -0
- package/dist/controllers/streamable/streamable.controller.d.ts +9 -0
- package/dist/controllers/streamable/streamable.controller.js +62 -0
- package/dist/controllers/streamable/streamable.controller.js.map +1 -0
- package/dist/controllers/streamable/streamable.service.d.ts +24 -0
- package/dist/controllers/streamable/streamable.service.js +118 -0
- package/dist/controllers/streamable/streamable.service.js.map +1 -0
- package/dist/decorators/capabilities.constants.d.ts +4 -0
- package/dist/decorators/capabilities.constants.js +8 -0
- package/dist/decorators/capabilities.constants.js.map +1 -0
- package/dist/decorators/capabilities.decorators.d.ts +8 -0
- package/dist/decorators/capabilities.decorators.js +49 -0
- package/dist/decorators/capabilities.decorators.js.map +1 -0
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.js +19 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors/message.interceptor.d.ts +10 -0
- package/dist/interceptors/message.interceptor.js +61 -0
- package/dist/interceptors/message.interceptor.js.map +1 -0
- package/dist/interfaces/capabilities.interface.d.ts +52 -0
- package/dist/interfaces/capabilities.interface.js +3 -0
- package/dist/interfaces/capabilities.interface.js.map +1 -0
- package/dist/interfaces/context.interface.d.ts +6 -0
- package/dist/interfaces/context.interface.js +3 -0
- package/dist/interfaces/context.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +2 -0
- package/dist/interfaces/index.js +19 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/mcp-server-options.interface.d.ts +42 -0
- package/dist/interfaces/mcp-server-options.interface.js +3 -0
- package/dist/interfaces/mcp-server-options.interface.js.map +1 -0
- package/dist/interfaces/message.types.d.ts +8 -0
- package/dist/interfaces/message.types.js +3 -0
- package/dist/interfaces/message.types.js.map +1 -0
- package/dist/mcp.module.d.ts +13 -0
- package/dist/mcp.module.js +193 -0
- package/dist/mcp.module.js.map +1 -0
- package/dist/registry/discovery.service.d.ts +16 -0
- package/dist/registry/discovery.service.js +85 -0
- package/dist/registry/discovery.service.js.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.js +19 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/logger.service.d.ts +16 -0
- package/dist/registry/logger.service.js +97 -0
- package/dist/registry/logger.service.js.map +1 -0
- package/dist/registry/registry.service.d.ts +16 -0
- package/dist/registry/registry.service.js +170 -0
- package/dist/registry/registry.service.js.map +1 -0
- package/dist/services/message.service.d.ts +7 -0
- package/dist/services/message.service.js +25 -0
- package/dist/services/message.service.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/eslint.config.mjs +40 -0
- package/package.json +109 -0
- package/src/controllers/sse/index.ts +2 -0
- package/src/controllers/sse/sse.controller.ts +25 -0
- package/src/controllers/sse/sse.service.ts +90 -0
- package/src/controllers/streamable/index.ts +2 -0
- package/src/controllers/streamable/streamable.controller.ts +24 -0
- package/src/controllers/streamable/streamable.service.ts +169 -0
- package/src/decorators/capabilities.constants.ts +7 -0
- package/src/decorators/capabilities.decorators.ts +150 -0
- package/src/decorators/index.ts +2 -0
- package/src/index.ts +11 -0
- package/src/interceptors/message.interceptor.ts +70 -0
- package/src/interfaces/capabilities.interface.ts +95 -0
- package/src/interfaces/context.interface.ts +18 -0
- package/src/interfaces/index.ts +2 -0
- package/src/interfaces/mcp-server-options.interface.ts +105 -0
- package/src/interfaces/message.types.ts +13 -0
- package/src/mcp.module.ts +250 -0
- package/src/mcp.service.spec.ts +28 -0
- package/src/registry/discovery.service.ts +116 -0
- package/src/registry/index.ts +2 -0
- package/src/registry/logger.service.ts +143 -0
- package/src/registry/registry.service.ts +282 -0
- package/src/services/message.service.ts +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
# MCP Server NestJS Module Library <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@nestjs-mcp/server)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview <!-- omit in toc -->
|
|
9
|
+
|
|
10
|
+
**NestJS MCP Server** is a modular library for building [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol/typescript-sdk/tree/server) servers using [NestJS](https://nestjs.com/). It provides decorators, modules, and integration patterns to expose MCP resources, tools, and prompts in a scalable, maintainable way. This project is a wrapper for the official [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk/tree/server) and is always kept compatible with its types and specification.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Table of Contents <!-- omit in toc -->
|
|
15
|
+
|
|
16
|
+
- [Overview](#overview)
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Quickstart](#quickstart)
|
|
19
|
+
- [What is MCP?](#what-is-mcp)
|
|
20
|
+
- [Core Concepts](#core-concepts)
|
|
21
|
+
- [Server](#server)
|
|
22
|
+
- [Resource](#resource)
|
|
23
|
+
- [Tool](#tool)
|
|
24
|
+
- [Prompt](#prompt)
|
|
25
|
+
- [Module API](#module-api)
|
|
26
|
+
- [forRoot](#mcpmoduleforroot)
|
|
27
|
+
- [forFeature](#mcpmoduleforfeature)
|
|
28
|
+
- [Resolver](#resolver)
|
|
29
|
+
- [Capabilities](#capabilities)
|
|
30
|
+
- [@Resolver](#resolver-decorator)
|
|
31
|
+
- [@Prompt](#prompt-decorator)
|
|
32
|
+
- [@Resource](#resource-decorator)
|
|
33
|
+
- [@Tool](#tool-decorator)
|
|
34
|
+
- [Guards](#guards)
|
|
35
|
+
- [Global-level guards:](#global-guard-guards)
|
|
36
|
+
- [Resolver-level guards:](#resolver-level-guards)
|
|
37
|
+
- [Method-level guards:](#method-level-guards)
|
|
38
|
+
- [Guard Example](#guard-example)
|
|
39
|
+
- [Inspector Playground](#inspector-playground)
|
|
40
|
+
- [Examples](#examples)
|
|
41
|
+
- [Changelog](#changelog)
|
|
42
|
+
- [License](#license)
|
|
43
|
+
- [Contributions](#contributions)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pnpm add @your-org/nestjs-mcp-server @modelcontextprotocol/sdk
|
|
51
|
+
# or
|
|
52
|
+
npm install @your-org/nestjs-mcp-server @modelcontextprotocol/sdk
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quickstart
|
|
58
|
+
|
|
59
|
+
Register the MCP module in your NestJS app and expose a simple tool:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { Module } from '@nestjs/common';
|
|
63
|
+
import { Injectable } from '@nestjs/common';
|
|
64
|
+
|
|
65
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types';
|
|
66
|
+
|
|
67
|
+
import { Tool } from '@nestjs-mcp/server';
|
|
68
|
+
|
|
69
|
+
@Injectable()
|
|
70
|
+
export class AppService {
|
|
71
|
+
/**
|
|
72
|
+
* Simple health check tool
|
|
73
|
+
*/
|
|
74
|
+
@Tool({ name: 'server_health_check' })
|
|
75
|
+
healthCheck(): CallToolResult {
|
|
76
|
+
return {
|
|
77
|
+
content: [
|
|
78
|
+
{
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: 'Server is operational. All systems running normally.',
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Module({
|
|
88
|
+
imports: [
|
|
89
|
+
McpModule.forRoot({
|
|
90
|
+
name: 'My MCP Server',
|
|
91
|
+
version: '1.0.0',
|
|
92
|
+
}),
|
|
93
|
+
],
|
|
94
|
+
providers: [AppService],
|
|
95
|
+
})
|
|
96
|
+
export class AppModule {}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## What is MCP?
|
|
102
|
+
|
|
103
|
+
The **Model Context Protocol (MCP)** is an open protocol for connecting LLMs to external data, tools, and prompts. MCP servers expose resources (data), tools (actions), and prompts (conversational flows) in a standardized way, enabling seamless integration with LLM-powered clients.
|
|
104
|
+
|
|
105
|
+
- See the [Anthropic announcement](https://www.anthropic.com/news/model-context-protocol) for more background.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Core Concepts
|
|
110
|
+
|
|
111
|
+
### Server
|
|
112
|
+
|
|
113
|
+
The MCP Server is the main entry point for exposing capabilities to LLMs. It manages the registration and discovery of resources, tools, and prompts.
|
|
114
|
+
|
|
115
|
+
### Resource
|
|
116
|
+
|
|
117
|
+
A Resource represents structured data or documents that can be queried or retrieved by LLMs. Resources are typically read-only and are identified by a unique URI.
|
|
118
|
+
|
|
119
|
+
- Learn more: [MCP Resources documentation](https://modelcontextprotocol.io/docs/concepts/resources)
|
|
120
|
+
|
|
121
|
+
### Tool
|
|
122
|
+
|
|
123
|
+
A Tool is an action or function that can be invoked by LLMs. Tools may have side effects and can accept parameters to perform computations or trigger operations.
|
|
124
|
+
|
|
125
|
+
- Learn more: [MCP Tools documentation](https://modelcontextprotocol.io/docs/concepts/tools)
|
|
126
|
+
|
|
127
|
+
### Prompt
|
|
128
|
+
|
|
129
|
+
A Prompt defines a conversational flow, template, or interaction pattern for LLMs. Prompts help guide the model's behavior in specific scenarios.
|
|
130
|
+
|
|
131
|
+
- Learn more: [MCP Prompts documentation](https://modelcontextprotocol.io/docs/concepts/prompts)
|
|
132
|
+
|
|
133
|
+
> **See the [Capabilities](#capabilities) section for implementation details and code examples.**
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Module API
|
|
138
|
+
|
|
139
|
+
### `McpModule.forRoot`
|
|
140
|
+
|
|
141
|
+
Registers the MCP Server globally in your NestJS application. Accepts an options object compatible with the MCP Server specification from `@modelcontextprotocol/sdk`.
|
|
142
|
+
|
|
143
|
+
**Parameters:**
|
|
144
|
+
|
|
145
|
+
- `options: McpServerOptions` — Main server configuration (name, version, description, etc.)
|
|
146
|
+
|
|
147
|
+
**Returns:**
|
|
148
|
+
|
|
149
|
+
- A dynamic NestJS module with all MCP providers registered
|
|
150
|
+
|
|
151
|
+
**Example:**
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
155
|
+
|
|
156
|
+
@Module({
|
|
157
|
+
imports: [
|
|
158
|
+
McpModule.forRoot({
|
|
159
|
+
name: 'My Server',
|
|
160
|
+
version: '1.0.0',
|
|
161
|
+
// ...other MCP options
|
|
162
|
+
}),
|
|
163
|
+
],
|
|
164
|
+
})
|
|
165
|
+
export class AppModule {}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `McpModule.forFeature`
|
|
169
|
+
|
|
170
|
+
Registers additional MCP resources, tools, or prompts in a feature module. Use this to organize large servers into multiple modules.
|
|
171
|
+
|
|
172
|
+
**Parameters:**
|
|
173
|
+
|
|
174
|
+
- `providers: Provider[]` — Array of NestJS providers (resources, tools, prompts)
|
|
175
|
+
|
|
176
|
+
**Returns:**
|
|
177
|
+
|
|
178
|
+
- A dynamic module with the specified providers
|
|
179
|
+
|
|
180
|
+
**Example:**
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
184
|
+
|
|
185
|
+
@Module({
|
|
186
|
+
imports: [McpModule.forFeature()],
|
|
187
|
+
providers: [
|
|
188
|
+
/*Your Providers with Mcp Capabilities*/
|
|
189
|
+
],
|
|
190
|
+
})
|
|
191
|
+
export class StatusModule {}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Module Usage
|
|
197
|
+
|
|
198
|
+
This library provides two main ways to register MCP capabilities in your NestJS application:
|
|
199
|
+
|
|
200
|
+
### 1. Global Registration with `McpModule.forRoot`
|
|
201
|
+
|
|
202
|
+
Use `McpModule.forRoot` in your root application module to configure and register the MCP server globally. This is required for every MCP server application.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { Module } from '@nestjs/common';
|
|
206
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
207
|
+
import { PromptsResolver } from './prompts.resolver';
|
|
208
|
+
|
|
209
|
+
@Module({
|
|
210
|
+
imports: [
|
|
211
|
+
McpModule.forRoot({
|
|
212
|
+
name: 'My MCP Server',
|
|
213
|
+
version: '1.0.0',
|
|
214
|
+
// ...other MCP options
|
|
215
|
+
}),
|
|
216
|
+
],
|
|
217
|
+
providers: [PromptsResolver],
|
|
218
|
+
})
|
|
219
|
+
export class AppModule {}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 2. Feature Module Registration with `McpModule.forFeature`
|
|
223
|
+
|
|
224
|
+
Use `McpModule.forFeature` in feature modules to register additional resolvers, tools, or resources. This is useful for organizing large servers into multiple modules.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { Module } from '@nestjs/common';
|
|
228
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
229
|
+
|
|
230
|
+
import { ToolsResolver } from './tools.resolver';
|
|
231
|
+
|
|
232
|
+
@Module({
|
|
233
|
+
imports: [McpModule.forFeature()],
|
|
234
|
+
providers: [ToolsResolver],
|
|
235
|
+
})
|
|
236
|
+
export class ToolsModule {}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
- Use `forRoot` only once in your root module.
|
|
240
|
+
- Use `forFeature` as many times as needed in feature modules.
|
|
241
|
+
- All resolvers, tools, and resources must be registered as providers.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Capabilities
|
|
246
|
+
|
|
247
|
+
This library provides a set of decorators to define MCP capabilities and apply cross-cutting concerns such as guards. Decorators can be used at both the Resolver (class) level and the method level.
|
|
248
|
+
|
|
249
|
+
### Resolver Decorator
|
|
250
|
+
|
|
251
|
+
A Resolver is a class that groups related MCP capabilities (such as prompts, resources, and tools) and provides a workspace context for them. Use the `@Resolver` decorator to mark a class as a resolver. Dependency injection is supported, and you can apply guards or other cross-cutting concerns at the class level.
|
|
252
|
+
|
|
253
|
+
**Example:**
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
import { Resolver, Prompt, Resource, Tool } from '@nestjs-mcp/server';
|
|
257
|
+
|
|
258
|
+
@Resolver('workspace')
|
|
259
|
+
export class MyResolver {
|
|
260
|
+
@Prompt({ name: 'greet' })
|
|
261
|
+
greetPrompt() {
|
|
262
|
+
/* ... */
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@Resource({ name: 'user', uri: 'user://{id}' })
|
|
266
|
+
getUserResource() {
|
|
267
|
+
/* ... */
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@Tool({ name: 'sum' })
|
|
271
|
+
sumTool() {
|
|
272
|
+
/* ... */
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
You can also apply guards at the resolver level:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { UseGuards, Resolver } from '@nestjs-mcp/server';
|
|
281
|
+
import { MyGuard } from './guards/my.guard';
|
|
282
|
+
|
|
283
|
+
@UseGuards(MyGuard)
|
|
284
|
+
@Resolver('secure')
|
|
285
|
+
export class SecureResolver {
|
|
286
|
+
// ...
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Prompt Decorator
|
|
291
|
+
|
|
292
|
+
Decorate methods within a Resolver to expose them as MCP Prompts.
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { Prompt } from '@nestjs-mcp/server';
|
|
296
|
+
|
|
297
|
+
@Resolver('workspace')
|
|
298
|
+
export class MyResolver {
|
|
299
|
+
@Prompt({ name: 'greet' })
|
|
300
|
+
greetPrompt() {
|
|
301
|
+
/* ... */
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Resource Decorator
|
|
307
|
+
|
|
308
|
+
Decorate methods within a Resolver to expose them as MCP Resources.
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
import { Resource } from '@nestjs-mcp/server';
|
|
312
|
+
|
|
313
|
+
@Resolver('workspace')
|
|
314
|
+
export class MyResolver {
|
|
315
|
+
@Resource({ name: 'user', uri: 'user://{id}' })
|
|
316
|
+
getUserResource() {
|
|
317
|
+
/* ... */
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Tool Decorator
|
|
323
|
+
|
|
324
|
+
Decorate methods within a Resolver to expose them as MCP Tools.
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
import { Tool } from '@nestjs-mcp/server';
|
|
328
|
+
|
|
329
|
+
@Resolver('workspace')
|
|
330
|
+
export class MyResolver {
|
|
331
|
+
@Tool({ name: 'sum' })
|
|
332
|
+
sumTool() {
|
|
333
|
+
/* ... */
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Guards
|
|
341
|
+
|
|
342
|
+
Apply one or more guards to a Resolver, to individual methods, or globally. Guards must implement the NestJS `CanActivate` interface.
|
|
343
|
+
|
|
344
|
+
### Global-level guards:
|
|
345
|
+
|
|
346
|
+
This approach uses the standard NestJS global guard system. A global guard will protect all entry points of your MCP server by running before any connection is handled. Use this for authentication, API key checks, or any logic that should apply to every connection.
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
// src/guards/global-auth.guard.ts
|
|
350
|
+
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
|
351
|
+
|
|
352
|
+
@Injectable()
|
|
353
|
+
export class GlobalAuthGuard implements CanActivate {
|
|
354
|
+
canActivate(context: ExecutionContext): boolean {
|
|
355
|
+
// Example: Allow all requests (replace with real logic)
|
|
356
|
+
// You can access request info via context.switchToHttp().getRequest() if needed
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Register the guard globally in your main module:
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import { Module } from '@nestjs/common';
|
|
366
|
+
import { APP_GUARD } from '@nestjs/core';
|
|
367
|
+
import { McpModule } from '@nestjs-mcp/server';
|
|
368
|
+
import { GlobalAuthGuard } from './guards/global-auth.guard';
|
|
369
|
+
import { PromptsResolver } from './prompts.resolver';
|
|
370
|
+
|
|
371
|
+
@Module({
|
|
372
|
+
imports: [
|
|
373
|
+
McpModule.forRoot({
|
|
374
|
+
name: 'My MCP Server',
|
|
375
|
+
version: '1.0.0',
|
|
376
|
+
}),
|
|
377
|
+
],
|
|
378
|
+
providers: [
|
|
379
|
+
PromptsResolver,
|
|
380
|
+
{
|
|
381
|
+
provide: APP_GUARD,
|
|
382
|
+
useClass: GlobalAuthGuard,
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
})
|
|
386
|
+
export class AppModule {}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Key points:**
|
|
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.
|
|
394
|
+
|
|
395
|
+
### Resolver-level guards:
|
|
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.
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { UseGuards, Resolver, Prompt } from '@nestjs-mcp/server';
|
|
401
|
+
import { MyGuard } from './guards/my.guard';
|
|
402
|
+
|
|
403
|
+
@UseGuards(MyGuard)
|
|
404
|
+
@Resolver('secure')
|
|
405
|
+
export class SecureResolver {
|
|
406
|
+
@Prompt({ name: 'securePrompt' })
|
|
407
|
+
securePrompt() {
|
|
408
|
+
/* ... */
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Method-level guards:
|
|
414
|
+
|
|
415
|
+
This is a custom feature of this library. Method-level guards are applied using the `@UseGuards` decorator directly on a method. Only the decorated MCP method will be protected by these guards. Use this for fine-grained access control on specific capabilities.
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
import { UseGuards, Resolver, Prompt } from '@nestjs-mcp/server';
|
|
419
|
+
import { MyGuard } from './guards/my.guard';
|
|
420
|
+
|
|
421
|
+
@Resolver('mixed')
|
|
422
|
+
export class MixedResolver {
|
|
423
|
+
@Prompt({ name: 'publicPrompt' })
|
|
424
|
+
publicPrompt() {
|
|
425
|
+
/* ... */
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@UseGuards(MyGuard)
|
|
429
|
+
@Prompt({ name: 'protectedPrompt' })
|
|
430
|
+
protectedPrompt() {
|
|
431
|
+
/* ... */
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Guard Example
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
import { CanActivate } from '@nestjs/common';
|
|
440
|
+
import { McpExecutionContext } from '@nestjs-mcp/server';
|
|
441
|
+
|
|
442
|
+
export class MyGuard implements CanActivate {
|
|
443
|
+
canActivate(context: McpExecutionContext): boolean {
|
|
444
|
+
// Custom logic: allow or deny
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Using McpContext in Guards
|
|
451
|
+
|
|
452
|
+
When implementing guards for MCP resolvers and methods, you can use the `McpExecutionContext` interface to access MCP-specific context information. This interface extends the standard NestJS `ExecutionContext` and provides additional properties specific to MCP operations.
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
import { CanActivate } from '@nestjs/common';
|
|
456
|
+
import { McpExecutionContext } from '@nestjs-mcp/server';
|
|
457
|
+
import { Request, Response } from 'express';
|
|
458
|
+
|
|
459
|
+
@Injectable()
|
|
460
|
+
export class McpAuthGuard implements CanActivate {
|
|
461
|
+
canActivate(context: McpExecutionContext): boolean {
|
|
462
|
+
// Access MCP-specific context
|
|
463
|
+
const { args, message } = context;
|
|
464
|
+
|
|
465
|
+
// Access the current message from the request
|
|
466
|
+
if (message) {
|
|
467
|
+
const { req, res } = message;
|
|
468
|
+
|
|
469
|
+
// Access Express request and response objects
|
|
470
|
+
const request = req as Request;
|
|
471
|
+
const response = res as Response;
|
|
472
|
+
|
|
473
|
+
// Example: Check authorization header
|
|
474
|
+
const authHeader = request.headers.authorization;
|
|
475
|
+
|
|
476
|
+
// Implement your authentication logic here
|
|
477
|
+
// For example, check if the authorization header is valid
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Access the arguments passed to the MCP method
|
|
481
|
+
const methodArgs = args;
|
|
482
|
+
|
|
483
|
+
return true; // or false to deny access
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Key properties of McpExecutionContext:**
|
|
489
|
+
|
|
490
|
+
- `args`: The arguments passed to the MCP method being guarded
|
|
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
|
|
497
|
+
|
|
498
|
+
This context allows you to implement guards that are aware of the MCP protocol and can make decisions based on MCP-specific information, such as checking request headers, query parameters, or other request data.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Inspector Playground
|
|
503
|
+
|
|
504
|
+
Use the Inspector Playground to interactively test and debug your MCP server endpoints in a browser UI. This tool, powered by [`@modelcontextprotocol/inspector`](https://www.npmjs.com/package/@modelcontextprotocol/inspector), allows you to:
|
|
505
|
+
|
|
506
|
+
- Explore available resources, tools, and prompts
|
|
507
|
+
- Invoke endpoints and view responses in real time
|
|
508
|
+
- Validate your server implementation against the MCP specification
|
|
509
|
+
|
|
510
|
+
To launch the Inspector Playground:
|
|
511
|
+
|
|
512
|
+
```sh
|
|
513
|
+
npx @modelcontextprotocol/inspector
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## Examples
|
|
519
|
+
|
|
520
|
+
The [`examples/`](./examples/) directory contains ready-to-use scenarios demonstrating how to register and expose MCP capabilities
|
|
521
|
+
|
|
522
|
+
Each example is self-contained and follows best practices. For advanced usage, see the code and documentation in each example.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## Changelog
|
|
527
|
+
|
|
528
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release notes.
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## License
|
|
533
|
+
|
|
534
|
+
MIT — see [LICENSE](./LICENSE) for details.
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## Contributions
|
|
539
|
+
|
|
540
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines, reporting issues, and pull request rules.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./sse.controller"), exports);
|
|
18
|
+
__exportStar(require("./sse.service"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/controllers/sse/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,gDAA8B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
import { McpLoggerService } from '../../registry/logger.service';
|
|
3
|
+
import { SseService } from './sse.service';
|
|
4
|
+
export declare class SseController {
|
|
5
|
+
private readonly logger;
|
|
6
|
+
private readonly service;
|
|
7
|
+
constructor(logger: McpLoggerService, service: SseService);
|
|
8
|
+
handleSse(req: Request, res: Response): Promise<void>;
|
|
9
|
+
handleMessages(req: Request, res: Response): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SseController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const logger_service_1 = require("../../registry/logger.service");
|
|
18
|
+
const sse_service_1 = require("./sse.service");
|
|
19
|
+
let SseController = class SseController {
|
|
20
|
+
logger;
|
|
21
|
+
service;
|
|
22
|
+
constructor(logger, service) {
|
|
23
|
+
this.logger = logger;
|
|
24
|
+
this.service = service;
|
|
25
|
+
}
|
|
26
|
+
async handleSse(req, res) {
|
|
27
|
+
this.logger.log('[SSE] Connection established');
|
|
28
|
+
await this.service.handleSse(req, res);
|
|
29
|
+
}
|
|
30
|
+
async handleMessages(req, res) {
|
|
31
|
+
this.logger.log('[SSE] Message received');
|
|
32
|
+
await this.service.handleMessage(req, res);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.SseController = SseController;
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, common_1.Get)('sse'),
|
|
38
|
+
__param(0, (0, common_1.Req)()),
|
|
39
|
+
__param(1, (0, common_1.Res)()),
|
|
40
|
+
__metadata("design:type", Function),
|
|
41
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
42
|
+
__metadata("design:returntype", Promise)
|
|
43
|
+
], SseController.prototype, "handleSse", null);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, common_1.Post)('messages'),
|
|
46
|
+
__param(0, (0, common_1.Req)()),
|
|
47
|
+
__param(1, (0, common_1.Res)()),
|
|
48
|
+
__metadata("design:type", Function),
|
|
49
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
50
|
+
__metadata("design:returntype", Promise)
|
|
51
|
+
], SseController.prototype, "handleMessages", null);
|
|
52
|
+
exports.SseController = SseController = __decorate([
|
|
53
|
+
(0, common_1.Controller)(),
|
|
54
|
+
__metadata("design:paramtypes", [logger_service_1.McpLoggerService,
|
|
55
|
+
sse_service_1.SseService])
|
|
56
|
+
], SseController);
|
|
57
|
+
//# sourceMappingURL=sse.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.controller.js","sourceRoot":"","sources":["../../../src/controllers/sse/sse.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAiE;AAGjE,kEAAiE;AACjE,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAEL;IACA;IAFnB,YACmB,MAAwB,EACxB,OAAmB;QADnB,WAAM,GAAN,MAAM,CAAkB;QACxB,YAAO,GAAP,OAAO,CAAY;IACnC,CAAC;IAGE,AAAN,KAAK,CAAC,SAAS,CAAQ,GAAY,EAAS,GAAa;QACvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAChD,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAGK,AAAN,KAAK,CAAC,cAAc,CAAQ,GAAY,EAAS,GAAa;QAC5D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7C,CAAC;CACF,CAAA;AAjBY,sCAAa;AAOlB;IADL,IAAA,YAAG,EAAC,KAAK,CAAC;IACM,WAAA,IAAA,YAAG,GAAE,CAAA;IAAgB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;8CAG1C;AAGK;IADL,IAAA,aAAI,EAAC,UAAU,CAAC;IACK,WAAA,IAAA,YAAG,GAAE,CAAA;IAAgB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;mDAG/C;wBAhBU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAGgB,iCAAgB;QACf,wBAAU;GAH3B,aAAa,CAiBzB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import { McpServerOptions } from '../../interfaces/mcp-server-options.interface';
|
|
4
|
+
import { McpLoggerService } from '../../registry/logger.service';
|
|
5
|
+
import { RegistryService } from '../../registry/registry.service';
|
|
6
|
+
export declare class SseService implements OnModuleInit {
|
|
7
|
+
private readonly options;
|
|
8
|
+
private readonly registry;
|
|
9
|
+
private readonly logger;
|
|
10
|
+
private server;
|
|
11
|
+
private transports;
|
|
12
|
+
constructor(options: McpServerOptions, registry: RegistryService, logger: McpLoggerService);
|
|
13
|
+
onModuleInit(): Promise<void>;
|
|
14
|
+
handleSse(req: Request, res: Response): Promise<void>;
|
|
15
|
+
handleMessage(req: Request, res: Response): Promise<void>;
|
|
16
|
+
}
|