150 lines
6.2 KiB
Markdown
150 lines
6.2 KiB
Markdown
|
|
# Task ID: 28
|
||
|
|
|
||
|
|
**Title:** Add MCP proxy endpoint to mcpd
|
||
|
|
|
||
|
|
**Status:** done
|
||
|
|
|
||
|
|
**Dependencies:** None
|
||
|
|
|
||
|
|
**Priority:** high
|
||
|
|
|
||
|
|
**Description:** Create a new endpoint in mcpd at /api/v1/mcp/proxy that accepts MCP tool call requests and executes them on managed MCP server instances. Also add authentication endpoints (login/logout) that mcpctl will use to authenticate users.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
## MCP Proxy Endpoint
|
||
|
|
|
||
|
|
1. Create new route file: `src/mcpd/src/routes/mcp-proxy.ts`
|
||
|
|
2. Define request schema:
|
||
|
|
```typescript
|
||
|
|
interface McpProxyRequest {
|
||
|
|
serverId: string; // or instanceId
|
||
|
|
method: string; // e.g., 'tools/call', 'resources/read'
|
||
|
|
params: Record<string, unknown>;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
3. Create McpProxyService in `src/mcpd/src/services/mcp-proxy-service.ts`:
|
||
|
|
- Look up instance by serverId (auto-start if profile allows)
|
||
|
|
- Connect to the container via stdio or HTTP (depending on transport type)
|
||
|
|
- Execute the MCP JSON-RPC call
|
||
|
|
- Return the result
|
||
|
|
4. Handle MCP JSON-RPC protocol:
|
||
|
|
```typescript
|
||
|
|
async executeCall(instanceId: string, method: string, params: unknown) {
|
||
|
|
const instance = await this.instanceService.getInstance(instanceId);
|
||
|
|
const connection = await this.getOrCreateConnection(instance);
|
||
|
|
const result = await connection.call(method, params);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
5. Connection pooling: maintain persistent connections to running instances
|
||
|
|
6. Add route: `POST /api/v1/mcp/proxy` (must be behind auth middleware)
|
||
|
|
7. Add audit logging for all MCP proxy calls - include authenticated userId from request.userId
|
||
|
|
8. Handle errors: instance not found, instance not running, MCP call failed
|
||
|
|
|
||
|
|
## Authentication Endpoints
|
||
|
|
|
||
|
|
9. Create auth routes file: `src/mcpd/src/routes/auth.ts`
|
||
|
|
10. Implement `POST /api/v1/auth/login`:
|
||
|
|
- Request body: `{ username: string, password: string }`
|
||
|
|
- Validate credentials against User table (use bcrypt for password comparison)
|
||
|
|
- Create new Session record with token (use crypto.randomUUID or similar)
|
||
|
|
- Response: `{ token: string, expiresAt: string }`
|
||
|
|
11. Implement `POST /api/v1/auth/logout`:
|
||
|
|
- Requires Bearer token in Authorization header
|
||
|
|
- Delete/invalidate the Session record
|
||
|
|
- Response: `{ success: true }`
|
||
|
|
|
||
|
|
## Auth Integration Notes
|
||
|
|
|
||
|
|
- Existing auth middleware in `src/mcpd/src/middleware/auth.ts` validates Bearer tokens against Session table
|
||
|
|
- It sets `request.userId` on successful authentication
|
||
|
|
- MCP proxy endpoint MUST use this auth middleware
|
||
|
|
- Auth endpoints (login) should NOT require auth middleware
|
||
|
|
- Logout endpoint SHOULD require auth middleware to validate the session being invalidated
|
||
|
|
|
||
|
|
**Test Strategy:**
|
||
|
|
|
||
|
|
1. Unit test: Proxy service looks up correct instance
|
||
|
|
2. Unit test: JSON-RPC call is formatted correctly
|
||
|
|
3. Integration test: Full flow with a mock MCP server container
|
||
|
|
4. Test error handling: non-existent server returns 404
|
||
|
|
5. Test error handling: stopped instance returns appropriate error
|
||
|
|
6. Test audit log entries include authenticated userId
|
||
|
|
7. Test connection reuse for multiple calls to same instance
|
||
|
|
8. Test login endpoint: valid credentials return session token
|
||
|
|
9. Test login endpoint: invalid credentials return 401
|
||
|
|
10. Test logout endpoint: valid session is invalidated
|
||
|
|
11. Test logout endpoint: invalid/missing token returns 401
|
||
|
|
12. Test MCP proxy endpoint without auth token returns 401
|
||
|
|
13. Test MCP proxy endpoint with expired token returns 401
|
||
|
|
14. Test MCP proxy endpoint with valid token succeeds and logs userId in audit
|
||
|
|
|
||
|
|
## Subtasks
|
||
|
|
|
||
|
|
### 28.1. Create auth routes with login/logout endpoints
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** None
|
||
|
|
|
||
|
|
Create src/mcpd/src/routes/auth.ts with POST /api/v1/auth/login and POST /api/v1/auth/logout endpoints for mcpctl authentication.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Implement login endpoint: validate username/password against User table using bcrypt, create Session record with generated token and expiry. Implement logout endpoint: require auth middleware, delete/invalidate Session record. Login does NOT require auth, logout DOES require auth. Export registerAuthRoutes function and update routes/index.ts.
|
||
|
|
|
||
|
|
### 28.2. Create MCP proxy route file with auth middleware
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** 28.1
|
||
|
|
|
||
|
|
Create src/mcpd/src/routes/mcp-proxy.ts with POST /api/v1/mcp/proxy endpoint protected by auth middleware.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Define McpProxyRequest interface (serverId, method, params). Register route handler that extracts userId from request.userId (set by auth middleware). Apply auth middleware using preHandler hook. Validate request body schema.
|
||
|
|
|
||
|
|
### 28.3. Create McpProxyService for instance lookup and connection
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** None
|
||
|
|
|
||
|
|
Create src/mcpd/src/services/mcp-proxy-service.ts to handle instance lookup, connection management, and MCP call execution.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Implement getInstance to look up by serverId, auto-start if profile allows. Implement getOrCreateConnection for connection pooling. Handle both stdio and HTTP transports. Implement executeCall method that formats JSON-RPC call and returns result.
|
||
|
|
|
||
|
|
### 28.4. Implement MCP JSON-RPC call execution
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** 28.3
|
||
|
|
|
||
|
|
Implement the core JSON-RPC call logic in McpProxyService to execute tool calls on MCP server instances.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Format JSON-RPC 2.0 request with method and params. Send request over established connection (stdio/HTTP). Parse JSON-RPC response and handle errors. Return result or throw appropriate error for failed calls.
|
||
|
|
|
||
|
|
### 28.5. Add audit logging with userId for MCP proxy calls
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** 28.2, 28.4
|
||
|
|
|
||
|
|
Ensure all MCP proxy calls are logged to audit log including the authenticated userId from the session.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Use existing audit middleware/service. Include userId from request.userId in audit log entry. Log serverId, method, and outcome (success/failure). Log any errors that occur during MCP call execution.
|
||
|
|
|
||
|
|
### 28.6. Integrate auth and proxy routes into server.ts
|
||
|
|
|
||
|
|
**Status:** pending
|
||
|
|
**Dependencies:** 28.1, 28.2, 28.5
|
||
|
|
|
||
|
|
Register the new auth and mcp-proxy routes in the Fastify server with proper auth middleware wiring.
|
||
|
|
|
||
|
|
**Details:**
|
||
|
|
|
||
|
|
Update server.ts to register auth routes (no auth required for login). Register mcp-proxy routes with auth middleware. Ensure auth middleware is wired with findSession dependency from Prisma. Update routes/index.ts exports.
|