@muzikanto/nestjs-mcp 1.7.1 → 1.7.3
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/CHANGELOG.md +12 -0
- package/README.md +11 -0
- package/dist/mcp-server/config.d.ts +5 -0
- package/dist/mcp-server/dto/McpToolResultMessage.dto.d.ts +1 -1
- package/dist/mcp-server/mcp.module.d.ts +13 -1
- package/dist/mcp-server/mcp.module.js +10 -2
- package/dist/mcp-server/services/mcp-dynamic.service.d.ts +5 -1
- package/dist/mcp-server/services/mcp-dynamic.service.js +12 -0
- package/dist/mcp-server/services/mcp.sse.service.js +16 -1
- package/dist/mcp-server/utils/run-fillters.js +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -50,6 +50,13 @@ NestJS MCP (Model Context Protocol) module — allows you to create “tools”,
|
|
|
50
50
|
- Full TypeScript typing
|
|
51
51
|
- Support `@UseGuards`, `@UseInterceptors`, `@UseFilters`
|
|
52
52
|
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
- [Example server](https://github.com/Muzikanto/nestjs-mcp/tree/main/example)
|
|
56
|
+
- [Example librechat](https://github.com/Muzikanto/nestjs-mcp/tree/main/example/librechat)
|
|
57
|
+
- [Example openai request](https://github.com/Muzikanto/nestjs-mcp/blob/main/example/src/openai/openai.service.ts)
|
|
58
|
+
- [Example mcp handlers](https://github.com/Muzikanto/nestjs-mcp/tree/main/example/src/mcp-server/handlers)
|
|
59
|
+
|
|
53
60
|
---
|
|
54
61
|
|
|
55
62
|
## Installation
|
|
@@ -74,6 +81,10 @@ import { TelegramAutoReplyPrompt } from "./prompts/telegram-auto-reply.prompt";
|
|
|
74
81
|
imports: [
|
|
75
82
|
McpModule.forRoot({
|
|
76
83
|
providers: [TelegramSendMessageTool, TelegramAutoReplyPrompt],
|
|
84
|
+
transports: {
|
|
85
|
+
sse: true, // SSE endpoints for mcp
|
|
86
|
+
http: true, // HTTP endpoints for custom server
|
|
87
|
+
},
|
|
77
88
|
}),
|
|
78
89
|
],
|
|
79
90
|
})
|
|
@@ -3,6 +3,11 @@ export declare const MCP_CONFIG_TOKEN = "mcl:config-token";
|
|
|
3
3
|
export type IMcpConfig = {
|
|
4
4
|
name?: string;
|
|
5
5
|
version?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
icons?: {
|
|
9
|
+
src: string;
|
|
10
|
+
}[];
|
|
6
11
|
httpAdapter: IHttpAdapter;
|
|
7
12
|
};
|
|
8
13
|
export declare const InjectMcpConfig: () => PropertyDecorator & ParameterDecorator;
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { CanActivate, DynamicModule, ModuleMetadata, Provider } from "@nestjs/common";
|
|
2
2
|
import { IHttpAdapter } from "./utils/http-adapter";
|
|
3
3
|
type Metadata = Pick<ModuleMetadata, "providers" | "imports" | "exports"> & {
|
|
4
|
-
guard?: Provider<CanActivate>;
|
|
5
4
|
name?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
icons?: {
|
|
8
|
+
src: string;
|
|
9
|
+
}[];
|
|
6
10
|
version?: string;
|
|
11
|
+
/**
|
|
12
|
+
* @default { sse: true, http: true }
|
|
13
|
+
*/
|
|
14
|
+
transports?: {
|
|
15
|
+
sse?: boolean;
|
|
16
|
+
http?: boolean;
|
|
17
|
+
};
|
|
7
18
|
httpAdapter?: IHttpAdapter;
|
|
19
|
+
guard?: Provider<CanActivate>;
|
|
8
20
|
};
|
|
9
21
|
export declare class McpModule {
|
|
10
22
|
static forRoot(metadata?: Metadata): DynamicModule;
|
|
@@ -22,11 +22,16 @@ const mcp_sse_service_1 = require("./services/mcp.sse.service");
|
|
|
22
22
|
const publicGuard = { canActivate: () => Promise.resolve(true) };
|
|
23
23
|
let McpModule = McpModule_1 = class McpModule {
|
|
24
24
|
static forRoot(metadata = {}) {
|
|
25
|
+
// TODO remove defaut in next major version
|
|
26
|
+
const transports = metadata.transports || { sse: true, http: true };
|
|
25
27
|
const configProviver = {
|
|
26
28
|
provide: config_1.MCP_CONFIG_TOKEN,
|
|
27
29
|
useValue: {
|
|
28
30
|
name: metadata.name,
|
|
29
31
|
version: metadata.version,
|
|
32
|
+
description: metadata.description,
|
|
33
|
+
title: metadata.title,
|
|
34
|
+
icons: metadata.icons,
|
|
30
35
|
httpAdapter: metadata.httpAdapter || http_adapter_1.DEFAULT_FASTIFY_ADAPTER,
|
|
31
36
|
},
|
|
32
37
|
};
|
|
@@ -41,7 +46,7 @@ let McpModule = McpModule_1 = class McpModule {
|
|
|
41
46
|
imports: [core_1.DiscoveryModule, ...(metadata.imports || [])],
|
|
42
47
|
providers: [
|
|
43
48
|
mcp_service_1.McpService,
|
|
44
|
-
mcp_sse_service_1.McpSseService,
|
|
49
|
+
...(transports.sse ? [mcp_sse_service_1.McpSseService] : []),
|
|
45
50
|
mcp_explorer_1.McpExplorer,
|
|
46
51
|
mcp_dynamic_service_1.McpDynamicService,
|
|
47
52
|
configProviver,
|
|
@@ -50,7 +55,10 @@ let McpModule = McpModule_1 = class McpModule {
|
|
|
50
55
|
...(metadata.providers || []),
|
|
51
56
|
],
|
|
52
57
|
exports: [mcp_dynamic_service_1.McpDynamicService, ...(metadata.exports || [])],
|
|
53
|
-
controllers: [
|
|
58
|
+
controllers: [
|
|
59
|
+
...(transports.http ? [mcp_controller_1.McpController] : []),
|
|
60
|
+
...(transports.sse ? [mcp_sse_controller_1.McpSseController] : []),
|
|
61
|
+
],
|
|
54
62
|
};
|
|
55
63
|
}
|
|
56
64
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CanActivate, NestInterceptor, Type } from "@nestjs/common";
|
|
1
|
+
import { CanActivate, ExceptionFilter, NestInterceptor, Type } from "@nestjs/common";
|
|
2
2
|
import { ModuleRef } from "@nestjs/core";
|
|
3
3
|
import { McpService } from "../services/mcp.service";
|
|
4
4
|
import { IMcpTool } from "../decorators/mcp-tool.decorator";
|
|
@@ -7,14 +7,17 @@ import { IMcpPrompt } from "../decorators/mcp-prompt.decorator";
|
|
|
7
7
|
export type IMcpDynamicTool<Input, Result extends Record<string, unknown>> = IMcpTool<Input, Result> & {
|
|
8
8
|
guards?: Type<CanActivate>[];
|
|
9
9
|
interceptors?: Type<NestInterceptor>[];
|
|
10
|
+
filters?: Type<ExceptionFilter>[];
|
|
10
11
|
};
|
|
11
12
|
export type IMcpDynamicPrompt<Input> = IMcpPrompt<Input> & {
|
|
12
13
|
guards?: Type<CanActivate>[];
|
|
13
14
|
interceptors?: Type<NestInterceptor>[];
|
|
15
|
+
filters?: Type<ExceptionFilter>[];
|
|
14
16
|
};
|
|
15
17
|
export type IMcpDynamicResource<Input> = IMcpResource<Input> & {
|
|
16
18
|
guards?: Type<CanActivate>[];
|
|
17
19
|
interceptors?: Type<NestInterceptor>[];
|
|
20
|
+
filters?: Type<ExceptionFilter>[];
|
|
18
21
|
};
|
|
19
22
|
export declare class McpDynamicService {
|
|
20
23
|
private readonly moduleRef;
|
|
@@ -28,4 +31,5 @@ export declare class McpDynamicService {
|
|
|
28
31
|
registerResource<Input>(resource: IMcpDynamicResource<Input>): Promise<void>;
|
|
29
32
|
protected applyGuards(item: Function, guards: Type<CanActivate>[]): void;
|
|
30
33
|
protected applyInterceptors(item: Function, interceptors: Type<NestInterceptor>[]): void;
|
|
34
|
+
protected applyFilters(item: Function, filters: Type<ExceptionFilter>[]): void;
|
|
31
35
|
}
|
|
@@ -39,6 +39,9 @@ let McpDynamicService = class McpDynamicService {
|
|
|
39
39
|
if (tool.interceptors) {
|
|
40
40
|
this.applyInterceptors(DynamicToolClass, tool.interceptors);
|
|
41
41
|
}
|
|
42
|
+
if (tool.filters) {
|
|
43
|
+
this.applyFilters(DynamicToolClass, tool.filters);
|
|
44
|
+
}
|
|
42
45
|
const instance = await this.moduleRef.create(DynamicToolClass);
|
|
43
46
|
this.mcpService.registerTool(instance.name, {
|
|
44
47
|
instance,
|
|
@@ -60,6 +63,9 @@ let McpDynamicService = class McpDynamicService {
|
|
|
60
63
|
if (prompt.interceptors) {
|
|
61
64
|
this.applyInterceptors(DynamicPromptClass, prompt.interceptors);
|
|
62
65
|
}
|
|
66
|
+
if (prompt.filters) {
|
|
67
|
+
this.applyFilters(DynamicPromptClass, prompt.filters);
|
|
68
|
+
}
|
|
63
69
|
const instance = await this.moduleRef.create(DynamicPromptClass);
|
|
64
70
|
this.mcpService.registerPrompt(instance.name, {
|
|
65
71
|
instance,
|
|
@@ -84,6 +90,9 @@ let McpDynamicService = class McpDynamicService {
|
|
|
84
90
|
if (resource.interceptors) {
|
|
85
91
|
this.applyInterceptors(DynamicResourceClass, resource.interceptors);
|
|
86
92
|
}
|
|
93
|
+
if (resource.filters) {
|
|
94
|
+
this.applyFilters(DynamicResourceClass, resource.filters);
|
|
95
|
+
}
|
|
87
96
|
const instance = await this.moduleRef.create(DynamicResourceClass);
|
|
88
97
|
this.mcpService.registerResource(instance.name, {
|
|
89
98
|
instance,
|
|
@@ -96,6 +105,9 @@ let McpDynamicService = class McpDynamicService {
|
|
|
96
105
|
applyInterceptors(item, interceptors) {
|
|
97
106
|
Reflect.defineMetadata(constants_1.INTERCEPTORS_METADATA, interceptors, item);
|
|
98
107
|
}
|
|
108
|
+
applyFilters(item, filters) {
|
|
109
|
+
Reflect.defineMetadata(constants_1.EXCEPTION_FILTERS_METADATA, filters, item);
|
|
110
|
+
}
|
|
99
111
|
};
|
|
100
112
|
exports.McpDynamicService = McpDynamicService;
|
|
101
113
|
exports.McpDynamicService = McpDynamicService = __decorate([
|
|
@@ -63,7 +63,22 @@ let McpSseService = class McpSseService {
|
|
|
63
63
|
const server = new mcp_js_1.McpServer({
|
|
64
64
|
version: this.config.version || "1",
|
|
65
65
|
name: this.config.name || "MCP server",
|
|
66
|
-
|
|
66
|
+
description: this.config.description,
|
|
67
|
+
title: this.config.title,
|
|
68
|
+
icons: this.config.icons,
|
|
69
|
+
}, {
|
|
70
|
+
capabilities: {
|
|
71
|
+
prompts: {
|
|
72
|
+
listChanged: true,
|
|
73
|
+
},
|
|
74
|
+
tools: {
|
|
75
|
+
listChanged: true,
|
|
76
|
+
},
|
|
77
|
+
resources: {
|
|
78
|
+
listChanged: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
});
|
|
67
82
|
this.registerTools(server, context);
|
|
68
83
|
this.registerPrompts(server, context);
|
|
69
84
|
this.registerResources(server, context);
|
|
@@ -22,8 +22,11 @@ async function runFilters(moduleRef, metatype, exception, host) {
|
|
|
22
22
|
const filters = Reflect.getMetadata(constants_1.EXCEPTION_FILTERS_METADATA, metatype) || [];
|
|
23
23
|
for (const Filter of filters) {
|
|
24
24
|
const filterInstance = await resolveFilter(Filter);
|
|
25
|
-
const filterExceptions = (Reflect.getMetadata(constants_1.FILTER_CATCH_EXCEPTIONS, Filter)
|
|
26
|
-
if (!filterExceptions
|
|
25
|
+
const filterExceptions = (Reflect.getMetadata(constants_1.FILTER_CATCH_EXCEPTIONS, Filter));
|
|
26
|
+
if (!filterExceptions) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (filterExceptions.length > 0 &&
|
|
27
30
|
!filterExceptions.some((ex) => exception instanceof ex)) {
|
|
28
31
|
continue;
|
|
29
32
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muzikanto/nestjs-mcp",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.3",
|
|
4
4
|
"description": "NestJS MCP (Model Context Protocol) module for creating tools for LLM or HTTP with validation, decorators, and OpenAI Function Calls integration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nestjs",
|