@rekog/mcp-nest 1.1.4 → 1.2.0
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/.rinorism/index.d.ts +1 -0
- package/.vscode/settings.json +1 -0
- package/README.md +157 -15
- package/coverage/clover.xml +135 -121
- package/coverage/coverage-final.json +8 -8
- package/coverage/lcov-report/index.html +39 -39
- package/coverage/lcov.info +208 -207
- package/dist/controllers/sse.controller.factory.d.ts +13 -5
- package/dist/controllers/sse.controller.factory.d.ts.map +1 -1
- package/dist/controllers/sse.controller.factory.js +19 -6
- package/dist/controllers/sse.controller.factory.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/mcp-options.interface.d.ts +2 -0
- package/dist/interfaces/mcp-options.interface.d.ts.map +1 -1
- package/dist/mcp.module.d.ts.map +1 -1
- package/dist/mcp.module.js +10 -6
- package/dist/mcp.module.js.map +1 -1
- package/dist/services/mcp-tool-registry.service.d.ts +19 -0
- package/dist/services/mcp-tool-registry.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-registry.service.js +66 -0
- package/dist/services/mcp-tool-registry.service.js.map +1 -0
- package/dist/services/mcp-tools-executor.service.d.ts +84 -0
- package/dist/services/mcp-tools-executor.service.d.ts.map +1 -0
- package/dist/services/mcp-tools-executor.service.js +154 -0
- package/dist/services/mcp-tools-executor.service.js.map +1 -0
- package/dist/services/mcp-tools.discovery.d.ts +19 -15
- package/dist/services/mcp-tools.discovery.d.ts.map +1 -1
- package/dist/services/mcp-tools.discovery.js +66 -127
- package/dist/services/mcp-tools.discovery.js.map +1 -1
- package/package.json +1 -1
- package/tests/mcp-auth.e2e.spec.ts +231 -0
- package/tests/mcp.e2e.spec.ts +30 -73
- package/tsconfig.tsbuildinfo +1 -1
package/tests/mcp.e2e.spec.ts
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
3
|
+
import { Progress } from "@modelcontextprotocol/sdk/types.js";
|
|
1
4
|
import { INestApplication, Injectable } from "@nestjs/common";
|
|
2
5
|
import { Test, TestingModule } from "@nestjs/testing";
|
|
3
6
|
import { z } from "zod";
|
|
4
|
-
import { Tool } from "../src";
|
|
7
|
+
import { Context, Tool } from "../src";
|
|
5
8
|
import { McpModule } from "../src/mcp.module";
|
|
6
|
-
import { Context } from "../src/services/mcp-tools.discovery";
|
|
7
|
-
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
8
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
-
import { Progress } from "@modelcontextprotocol/sdk/types.js";
|
|
10
9
|
|
|
11
|
-
// Mock
|
|
10
|
+
// Mock user repository
|
|
12
11
|
@Injectable()
|
|
13
12
|
class MockUserRepository {
|
|
14
13
|
async findOne() {
|
|
15
14
|
return {
|
|
16
|
-
id: "
|
|
17
|
-
name: "
|
|
15
|
+
id: "userRepo123",
|
|
16
|
+
name: "Repository User",
|
|
18
17
|
orgMemberships: [
|
|
19
18
|
{
|
|
20
19
|
orgId: "org123",
|
|
21
20
|
organization: {
|
|
22
|
-
name: "
|
|
21
|
+
name: "Repository Org",
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
24
|
],
|
|
@@ -27,25 +26,31 @@ class MockUserRepository {
|
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
// Greeting tool that uses the authentication context
|
|
30
30
|
@Injectable()
|
|
31
|
-
export class
|
|
31
|
+
export class AuthGreetingTool {
|
|
32
32
|
constructor(private readonly userRepository: MockUserRepository) {}
|
|
33
33
|
|
|
34
34
|
@Tool({
|
|
35
35
|
name: "hello-world",
|
|
36
|
-
description: "A sample tool that
|
|
36
|
+
description: "A sample tool that accesses the authenticated user",
|
|
37
37
|
parameters: z.object({
|
|
38
38
|
name: z.string().default("World"),
|
|
39
39
|
}),
|
|
40
40
|
})
|
|
41
|
-
async sayHello({ name }, context: Context) {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
async sayHello({ name }, context: Context, request: Request & { user: any }) {
|
|
42
|
+
// Access both repository data and the authenticated user context
|
|
43
|
+
const repoUser = await this.userRepository.findOne();
|
|
44
|
+
const authUser = request.user; // Authenticated user from the request
|
|
45
|
+
|
|
46
|
+
// Construct greeting using both data sources
|
|
47
|
+
const greeting = `Hello, ${name}! I'm ${authUser.name} from ${
|
|
48
|
+
authUser.orgMemberships[0].organization.name
|
|
49
|
+
}. Repository user is ${repoUser.name}.`;
|
|
46
50
|
|
|
51
|
+
// Report progress for demonstration
|
|
47
52
|
for (let i = 0; i < 5; i++) {
|
|
48
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
49
54
|
await context.reportProgress({
|
|
50
55
|
progress: (i+1) * 20,
|
|
51
56
|
total: 100,
|
|
@@ -63,7 +68,7 @@ export class GreetingTool {
|
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
describe("E2E: MCP Server
|
|
71
|
+
describe("E2E: MCP Server with Authentication", () => {
|
|
67
72
|
let app: INestApplication;
|
|
68
73
|
let testPort: number;
|
|
69
74
|
|
|
@@ -73,25 +78,11 @@ describe("E2E: MCP Server via SSE", () => {
|
|
|
73
78
|
McpModule.forRoot({
|
|
74
79
|
name: "test-mcp-server",
|
|
75
80
|
version: "0.0.1",
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"hello-world": {
|
|
79
|
-
description: "A sample tool that returns a greeting",
|
|
80
|
-
input: {
|
|
81
|
-
name: {
|
|
82
|
-
type: "string",
|
|
83
|
-
default: "World",
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
"progress-test": {
|
|
88
|
-
description: "A tool that simulates progress",
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
},
|
|
81
|
+
// Specify the MockAuthGuard to protect the messages endpoint
|
|
82
|
+
guards: [],
|
|
92
83
|
}),
|
|
93
84
|
],
|
|
94
|
-
providers: [
|
|
85
|
+
providers: [AuthGreetingTool, MockUserRepository],
|
|
95
86
|
}).compile();
|
|
96
87
|
|
|
97
88
|
app = moduleFixture.createNestApplication();
|
|
@@ -114,45 +105,11 @@ describe("E2E: MCP Server via SSE", () => {
|
|
|
114
105
|
const transport = new SSEClientTransport(sseUrl);
|
|
115
106
|
await client.connect(transport);
|
|
116
107
|
const tools = await client.listTools();
|
|
117
|
-
expect(tools.tools.length).toBeGreaterThan(0);
|
|
118
|
-
await client.close();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should inject dependencies into the tool and call the "hello-world" tool via SSE', async () => {
|
|
122
|
-
const client = new Client(
|
|
123
|
-
{ name: "example-client", version: "1.0.0" },
|
|
124
|
-
{ capabilities: {} },
|
|
125
|
-
);
|
|
126
|
-
const sseUrl = new URL(`http://localhost:${testPort}/sse`);
|
|
127
|
-
const transport = new SSEClientTransport(sseUrl);
|
|
128
|
-
await client.connect(transport);
|
|
129
|
-
const tools = await client.listTools();
|
|
130
|
-
expect(tools.tools.find((t) => t.name == "hello-world")).toBeDefined();
|
|
131
108
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
name: "hello-world",
|
|
136
|
-
arguments: { name: "World" },
|
|
137
|
-
},
|
|
138
|
-
undefined,
|
|
139
|
-
{
|
|
140
|
-
onprogress: (progress) => {
|
|
141
|
-
console.log(progress);
|
|
142
|
-
countProgress++;
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
);
|
|
109
|
+
// Verify that the authenticated tool is available
|
|
110
|
+
expect(tools.tools.length).toBeGreaterThan(0);
|
|
111
|
+
expect(tools.tools.find((t) => t.name === "hello-world")).toBeDefined();
|
|
146
112
|
|
|
147
|
-
expect(countProgress).toBe(5)
|
|
148
|
-
expect(result).toEqual({
|
|
149
|
-
content: [
|
|
150
|
-
{
|
|
151
|
-
type: "text",
|
|
152
|
-
text: "Hello, World! I'm Test User from Test Org.",
|
|
153
|
-
},
|
|
154
|
-
],
|
|
155
|
-
});
|
|
156
113
|
await client.close();
|
|
157
114
|
});
|
|
158
|
-
});
|
|
115
|
+
});
|