@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.
Files changed (36) hide show
  1. package/.rinorism/index.d.ts +1 -0
  2. package/.vscode/settings.json +1 -0
  3. package/README.md +157 -15
  4. package/coverage/clover.xml +135 -121
  5. package/coverage/coverage-final.json +8 -8
  6. package/coverage/lcov-report/index.html +39 -39
  7. package/coverage/lcov.info +208 -207
  8. package/dist/controllers/sse.controller.factory.d.ts +13 -5
  9. package/dist/controllers/sse.controller.factory.d.ts.map +1 -1
  10. package/dist/controllers/sse.controller.factory.js +19 -6
  11. package/dist/controllers/sse.controller.factory.js.map +1 -1
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/interfaces/mcp-options.interface.d.ts +2 -0
  17. package/dist/interfaces/mcp-options.interface.d.ts.map +1 -1
  18. package/dist/mcp.module.d.ts.map +1 -1
  19. package/dist/mcp.module.js +10 -6
  20. package/dist/mcp.module.js.map +1 -1
  21. package/dist/services/mcp-tool-registry.service.d.ts +19 -0
  22. package/dist/services/mcp-tool-registry.service.d.ts.map +1 -0
  23. package/dist/services/mcp-tool-registry.service.js +66 -0
  24. package/dist/services/mcp-tool-registry.service.js.map +1 -0
  25. package/dist/services/mcp-tools-executor.service.d.ts +84 -0
  26. package/dist/services/mcp-tools-executor.service.d.ts.map +1 -0
  27. package/dist/services/mcp-tools-executor.service.js +154 -0
  28. package/dist/services/mcp-tools-executor.service.js.map +1 -0
  29. package/dist/services/mcp-tools.discovery.d.ts +19 -15
  30. package/dist/services/mcp-tools.discovery.d.ts.map +1 -1
  31. package/dist/services/mcp-tools.discovery.js +66 -127
  32. package/dist/services/mcp-tools.discovery.js.map +1 -1
  33. package/package.json +1 -1
  34. package/tests/mcp-auth.e2e.spec.ts +231 -0
  35. package/tests/mcp.e2e.spec.ts +30 -73
  36. package/tsconfig.tsbuildinfo +1 -1
@@ -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 UserRepository for testing
10
+ // Mock user repository
12
11
  @Injectable()
13
12
  class MockUserRepository {
14
13
  async findOne() {
15
14
  return {
16
- id: "user123",
17
- name: "Test User",
15
+ id: "userRepo123",
16
+ name: "Repository User",
18
17
  orgMemberships: [
19
18
  {
20
19
  orgId: "org123",
21
20
  organization: {
22
- name: "Test Org",
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 GreetingTool {
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 returns a greeting",
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
- const user = await this.userRepository.findOne();
43
- const greeting = `Hello, ${name}! I'm ${user.name} from ${
44
- user.orgMemberships[0].organization.name
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, 500));
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 via SSE", () => {
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
- capabilities: {
77
- tools: {
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: [GreetingTool, MockUserRepository],
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
- let countProgress=1;
133
- const result = await client.callTool(
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
+ });