Move 6 recently generated inquiry and MCP exploration documents to the centralized audit directory. Co-Authored-By: Paperclip <noreply@paperclip.ing>
397 lines
14 KiB
Plaintext
397 lines
14 KiB
Plaintext
================================================================================
|
||
MCP MODULE - COMPLETE FILES LISTING
|
||
================================================================================
|
||
|
||
PROJECT: GoodGo Platform
|
||
MODULE: Model Context Protocol (MCP) Integration
|
||
LOCATION: apps/api/src/modules/mcp/
|
||
DATE: April 11, 2026
|
||
|
||
================================================================================
|
||
1. SOURCE FILES
|
||
================================================================================
|
||
|
||
📄 File 1: apps/api/src/modules/mcp/index.ts
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
Type: Module Export/Index
|
||
Lines: 1
|
||
Purpose: Main module entry point
|
||
Exports: { McpIntegrationModule }
|
||
|
||
Content:
|
||
────────
|
||
export { McpIntegrationModule } from './mcp.module';
|
||
|
||
Status: ✅ Simple re-export, well-formed
|
||
|
||
|
||
📄 File 2: apps/api/src/modules/mcp/mcp.module.ts
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
Type: NestJS Module Configuration
|
||
Lines: 22
|
||
Purpose: Bootstrap MCP integration module with dependencies
|
||
|
||
Key Features:
|
||
• @Module decorator with imports, controllers
|
||
• Implements OnModuleInit lifecycle hook
|
||
• Configures McpCoreModule.forRoot() with settings
|
||
• Sets up service integration (Typesense, Auth, MCP Registry)
|
||
• Logs initialized servers on startup
|
||
|
||
Decorator: @Module({
|
||
imports: [SearchModule, AuthModule, McpCoreModule.forRoot({...})],
|
||
controllers: [McpTransportController],
|
||
})
|
||
|
||
Class: McpIntegrationModule implements OnModuleInit
|
||
|
||
Injected Dependencies:
|
||
1. typesenseClient: TypesenseClientService (from SearchModule)
|
||
2. mcpRegistry: McpRegistryService (from @goodgo/mcp-servers)
|
||
3. logger: LoggerService (from SharedModule)
|
||
|
||
Lifecycle Hook:
|
||
async onModuleInit(): Promise<void>
|
||
- Sets Typesense client on registry
|
||
- Re-initializes MCP servers
|
||
- Logs server names on startup
|
||
|
||
Status: ⚠️ Partially tested (initialization logic not covered)
|
||
|
||
|
||
📄 File 3: apps/api/src/modules/mcp/presentation/mcp-transport.controller.ts
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
Type: NestJS HTTP Controller
|
||
Lines: 102
|
||
Purpose: HTTP transport layer for MCP Server-Sent Events (SSE) connections
|
||
|
||
Decorators Applied:
|
||
@ApiTags('mcp') - Swagger grouping
|
||
@ApiBearerAuth('JWT') - API doc
|
||
@Controller('mcp') - Route prefix
|
||
@UseGuards(JwtAuthGuard) - Auth guard (all endpoints)
|
||
|
||
Private Properties:
|
||
transports: Map<string, SSEServerTransport>
|
||
→ Active session tracking by sessionId
|
||
|
||
Constructor:
|
||
McpTransportController(registry: McpRegistryService)
|
||
|
||
Endpoints (3):
|
||
|
||
1️⃣ GET /mcp/servers
|
||
├── Decorator: @Get('servers')
|
||
├── Throttle: 30 requests per 60,000ms
|
||
├── Auth: JwtAuthGuard ✅
|
||
├── Returns: { servers: string[] }
|
||
├── HTTP Status: 200 OK, 401 Unauthorized
|
||
└── Logic: Returns server.names from registry
|
||
|
||
2️⃣ GET /mcp/:serverName/sse
|
||
├── Decorator: @Get(':serverName/sse')
|
||
├── Throttle: 5 requests per 60,000ms ⚡ (STRICTER)
|
||
├── Params: serverName (string)
|
||
├── Auth: JwtAuthGuard ✅, CurrentUser decorator
|
||
├── Returns: SSE stream (response.write)
|
||
├── HTTP Status: 200 (stream), 404 (not found), 401 (unauthorized)
|
||
└── Logic:
|
||
1. Verify server exists (throw NOT_FOUND if not)
|
||
2. Create SSEServerTransport instance
|
||
3. Store in Map[sessionId]
|
||
4. Attach close listener for cleanup
|
||
5. Connect transport to server
|
||
|
||
3️⃣ POST /mcp/:serverName/messages
|
||
├── Decorator: @Post(':serverName/messages')
|
||
├── Throttle: 30 requests per 60,000ms
|
||
├── Params: serverName (string)
|
||
├── Query: sessionId (required)
|
||
├── Auth: JwtAuthGuard ✅, CurrentUser decorator
|
||
├── Returns: Delegate response to transport
|
||
├── HTTP Status: 200 OK, 400 (missing sessionId), 404 (not found), 401 (unauthorized)
|
||
└── Logic:
|
||
1. Extract sessionId from query
|
||
2. Validate sessionId present (throw BAD_REQUEST if not)
|
||
3. Look up transport (throw NOT_FOUND if expired)
|
||
4. Delegate to transport.handlePostMessage()
|
||
|
||
Status: ✅ Well tested (see spec file)
|
||
|
||
|
||
================================================================================
|
||
2. TEST FILES
|
||
================================================================================
|
||
|
||
🧪 File 4: apps/api/src/modules/mcp/presentation/__tests__/mcp-transport.controller.spec.ts
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
Type: Unit Test Suite
|
||
Lines: 174
|
||
Testing Framework: Vitest
|
||
Subject: McpTransportController
|
||
|
||
Test Coverage: 11 tests in 4 describe blocks
|
||
|
||
DESCRIBE BLOCK 1: security decorators (4 tests)
|
||
────────────────────────────────────────────────
|
||
✅ Test 1: has JwtAuthGuard applied at controller level
|
||
Method: Reflect.getMetadata('__guards__', McpTransportController)
|
||
Checks: guards exist and contain JwtAuthGuard
|
||
|
||
✅ Test 2: has Throttle metadata on listServers endpoint
|
||
Metadata: THROTTLER:LIMITdefault
|
||
Expected: 30
|
||
|
||
✅ Test 3: has Throttle metadata on handleSse endpoint with low limit
|
||
Metadata: THROTTLER:LIMITdefault on handleSse
|
||
Expected: 5 (stricter limit)
|
||
|
||
✅ Test 4: has Throttle metadata on handleMessage endpoint
|
||
Metadata: THROTTLER:LIMITdefault
|
||
Expected: 30
|
||
|
||
DESCRIBE BLOCK 2: listServers (2 tests)
|
||
────────────────────────────────────────
|
||
✅ Test 1: returns list of server names from registry
|
||
Setup: mockRegistry.getServerNames.mockReturnValue(['search', 'listings'])
|
||
Action: controller.listServers()
|
||
Assert: result.servers equals ['search', 'listings']
|
||
Verify: getServerNames called once
|
||
|
||
✅ Test 2: returns empty array when no servers registered
|
||
Setup: mockRegistry.getServerNames.mockReturnValue([])
|
||
Action: controller.listServers()
|
||
Assert: result.servers equals []
|
||
|
||
DESCRIBE BLOCK 3: handleSse (3 tests)
|
||
──────────────────────────────────────
|
||
✅ Test 1: throws NOT_FOUND when server does not exist
|
||
Setup: mockRegistry.getServer.mockReturnValue(null)
|
||
Action: controller.handleSse('nonexistent', mockUser, req, res)
|
||
Assert: Throws HttpException
|
||
Status: HttpStatus.NOT_FOUND
|
||
Message: Contains 'nonexistent'
|
||
|
||
✅ Test 2: creates transport and connects to server
|
||
Setup: mockServer.connect mock resolved
|
||
Action: controller.handleSse('search', mockUser, req, res)
|
||
Verify:
|
||
- getServer called with 'search'
|
||
- connect called once
|
||
- req.on called with 'close' event
|
||
|
||
✅ Test 3: cleans up transport on connection close
|
||
Setup: handleSse called successfully
|
||
Action: Simulate connection close by calling closeHandler
|
||
Assert: Subsequent handleMessage fails with NOT_FOUND
|
||
(proves transport was deleted from Map)
|
||
|
||
DESCRIBE BLOCK 4: handleMessage (2 tests)
|
||
──────────────────────────────────────────
|
||
✅ Test 1: throws BAD_REQUEST when sessionId query parameter is missing
|
||
Setup: mockReq.query = {}
|
||
Action: controller.handleMessage('search', mockUser, req, res)
|
||
Assert: Throws HttpException
|
||
Status: HttpStatus.BAD_REQUEST
|
||
|
||
✅ Test 2: throws NOT_FOUND when session does not exist
|
||
Setup: mockReq.query = { sessionId: 'nonexistent-session' }
|
||
Action: controller.handleMessage('search', mockUser, req, res)
|
||
Assert: Throws HttpException
|
||
Status: HttpStatus.NOT_FOUND
|
||
|
||
Mocking Strategies Used:
|
||
1. vi.mock() - Module mocking (SSEServerTransport)
|
||
2. vi.fn() - Function mocks (service methods)
|
||
3. mockReturnValue() - Sync returns
|
||
4. mockResolvedValue() - Async returns
|
||
5. Manual mock objects - req/res simulation
|
||
6. Reflect.getMetadata() - Decorator inspection
|
||
|
||
Status: ✅ Comprehensive test coverage
|
||
|
||
|
||
================================================================================
|
||
3. ARCHITECTURE & DDD LAYERS
|
||
================================================================================
|
||
|
||
Current Status: SIMPLIFIED ARCHITECTURE (Presentation-only)
|
||
|
||
✅ IMPLEMENTED LAYERS:
|
||
|
||
Presentation Layer
|
||
├── Controllers
|
||
│ └── mcp-transport.controller.ts (102 lines)
|
||
│ ├── 3 HTTP endpoints
|
||
│ ├── JWT auth protection
|
||
│ ├── Rate limiting (throttle)
|
||
│ └── SSE session management
|
||
│
|
||
└── Tests
|
||
└── __tests__/mcp-transport.controller.spec.ts (174 lines)
|
||
├── 11 tests
|
||
├── 4 describe blocks
|
||
└── Comprehensive coverage
|
||
|
||
❌ MISSING LAYERS:
|
||
|
||
Domain Layer (NO FILES)
|
||
├── No entities/
|
||
├── No value-objects/
|
||
├── No domain-events/
|
||
└── No repositories/ interfaces
|
||
|
||
Application Layer (NO FILES)
|
||
├── No handlers/ (CQRS)
|
||
├── No commands/
|
||
├── No queries/
|
||
└── No DTOs/
|
||
|
||
Infrastructure Layer (NO FILES)
|
||
├── No repositories/ (implementations)
|
||
├── No services/
|
||
└── No external-adapters/
|
||
|
||
Architecture Notes:
|
||
• Acts as integration wrapper
|
||
• Delegates to @goodgo/mcp-servers library
|
||
• Simple HTTP-to-SSE bridge
|
||
• In-memory session tracking (Map)
|
||
• No persistence or business logic
|
||
|
||
|
||
================================================================================
|
||
4. DEPENDENCIES & IMPORTS
|
||
================================================================================
|
||
|
||
External Dependencies:
|
||
• @goodgo/mcp-servers (SSEServerTransport, McpRegistryService)
|
||
• @nestjs/common (Controller, decorators, etc.)
|
||
• @nestjs/swagger (API documentation)
|
||
• @nestjs/throttler (Rate limiting)
|
||
|
||
Internal Dependencies:
|
||
• @modules/auth (JwtAuthGuard, CurrentUser)
|
||
• @modules/search (TypesenseClientService)
|
||
• @modules/shared (LoggerService)
|
||
|
||
Direct Imports in Module:
|
||
import { McpTransportController } from './presentation/mcp-transport.controller';
|
||
import { SearchModule, AuthModule } from other modules;
|
||
|
||
|
||
================================================================================
|
||
5. KEY STATISTICS
|
||
================================================================================
|
||
|
||
File Count:
|
||
• Total Source Files: 4
|
||
• Test Files: 1
|
||
• Lines of Code: 125 (implementation only)
|
||
• Lines of Tests: 174
|
||
• Test/Code Ratio: 1.39:1
|
||
|
||
Test Coverage:
|
||
• Controller Methods Tested: 3/3 (100%)
|
||
• Endpoints Tested: 3/3 (100%)
|
||
• Security Decorators Tested: ✅
|
||
• Error Cases Tested: ✅
|
||
• Happy Path Cases: ✅
|
||
• Module Initialization: ⚠️ (Partial)
|
||
|
||
Classes & Handlers:
|
||
• Controllers: 1 (McpTransportController)
|
||
• Modules: 1 (McpIntegrationModule)
|
||
• Handlers: 0 (Not using CQRS)
|
||
• Entities: 0 (Not implemented)
|
||
• Services: 0 (Delegated to library)
|
||
|
||
|
||
================================================================================
|
||
6. TESTING PATTERNS & CONVENTIONS
|
||
================================================================================
|
||
|
||
Framework: Vitest
|
||
Config: apps/api/vitest.config.ts
|
||
• globals: true (vi, describe, it, expect available globally)
|
||
• environment: 'node'
|
||
• pattern: src/**/*.spec.ts
|
||
|
||
Common Patterns in Codebase:
|
||
|
||
Pattern A: Simple Handler Testing (Auth module)
|
||
├── Minimal mocking
|
||
├── Command objects for input
|
||
└── Focused assertions
|
||
|
||
Pattern B: Complex Handler Testing (Payments module)
|
||
├── Multiple dependency mocks
|
||
├── Business rule testing
|
||
├── Event bus verification
|
||
└── Error scenario coverage
|
||
|
||
Pattern C: Domain Entity Testing (Payments module)
|
||
├── Explicit vitest imports
|
||
├── Entity state transitions
|
||
├── Domain event verification
|
||
├── Value object testing
|
||
└── Helper factory functions
|
||
|
||
Pattern D: Infrastructure Service Testing (Zalopay service)
|
||
├── External service simulation
|
||
├── Crypto/security testing
|
||
├── Complex test data builders
|
||
└── Edge case coverage
|
||
|
||
|
||
================================================================================
|
||
7. RECOMMENDED TEST COMMANDS
|
||
================================================================================
|
||
|
||
Run all MCP tests:
|
||
$ pnpm test -- src/modules/mcp
|
||
|
||
Run specific test file:
|
||
$ pnpm test -- src/modules/mcp/presentation/__tests__/mcp-transport.controller.spec.ts
|
||
|
||
Run with watch mode:
|
||
$ pnpm test -- --watch src/modules/mcp
|
||
|
||
Run with coverage:
|
||
$ pnpm test -- --coverage src/modules/mcp
|
||
|
||
Run all tests (project-wide):
|
||
$ pnpm test
|
||
|
||
|
||
================================================================================
|
||
SUMMARY
|
||
================================================================================
|
||
|
||
The MCP module is a SIMPLIFIED integration layer that:
|
||
✅ Exposes 3 HTTP endpoints for MCP server access
|
||
✅ Handles SSE connection lifecycle
|
||
✅ Provides rate limiting and JWT authentication
|
||
✅ Well-tested at controller level (174 lines of tests)
|
||
|
||
Areas for Improvement:
|
||
⚠️ Module initialization not tested
|
||
⚠️ No domain layer implementation
|
||
⚠️ No application handlers (CQRS)
|
||
⚠️ No infrastructure adapters
|
||
|
||
The module follows project conventions:
|
||
✅ Vitest for testing
|
||
✅ vi.fn() for mocking
|
||
✅ Decorator verification with Reflect API
|
||
✅ Organized __tests__/ subdirectory
|
||
|
||
For additional test examples:
|
||
• Auth module: apps/api/src/modules/auth/application/__tests__/
|
||
• Payments module: apps/api/src/modules/payments/
|
||
• Search module: apps/api/src/modules/search/
|
||
|
||
================================================================================
|
||
Generated: April 11, 2026
|
||
================================================================================
|