merge: AgentProject membership — the junction is now load-bearing
Merges feat/agent-project-membership (task 166/152). An agent can finally join many projects: membership routes, per-membership role and optional brain override, chat resolving context from the membership, and CLI attach-agent / detach-agent / get memberships. The legacy Agent.projectId fallback is kept for this release as the schema comment promises. Conflict resolved in main.ts: that branch added its RBAC case to mapUrlToPermission inline, while this branch had extracted the function to middleware/url-permission.ts so it could be tested. Kept the extraction and ported the case into it — joining a team is `edit:agents:<name>`, not `create:agents`, which is the authority to mint a whole agent. Also fixes something the extraction makes possible. security.test.ts contained a hand-copied reproduction of mapUrlToPermission, because main.ts self-invokes main() and nothing in it was importable. A security test asserting against a copy stops testing the system the moment the real one changes, and this copy had already drifted. It now imports the real function; all 18 assertions still pass, against the code that actually runs. Local: build clean, workspace 2550 passed, lint unchanged at 794 errors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4wNHWf7xSwnZCWpJcyv9p
This commit is contained in:
149
.taskmaster/tasks/task_028.md
Normal file
149
.taskmaster/tasks/task_028.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user