Clean up
This commit is contained in:
301
docs/plans/sprint_5_story_16.md
Normal file
301
docs/plans/sprint_5_story_16.md
Normal file
@@ -0,0 +1,301 @@
|
||||
---
|
||||
story_id: story_16
|
||||
sprint_id: sprint_5
|
||||
parent_story_id: story_0
|
||||
status: not_started
|
||||
priority: P0
|
||||
assignee: backend
|
||||
created_date: 2025-11-09
|
||||
estimated_days: 5
|
||||
phase: 4
|
||||
---
|
||||
|
||||
# Story 16: Transport Layer Migration to SDK
|
||||
|
||||
**Parent Epic**: [Story 0](sprint_5_story_0.md) - Integrate Microsoft .NET MCP SDK
|
||||
**Phase**: 4 - Transport Layer (Week 6)
|
||||
**Priority**: P0 - Critical
|
||||
**Estimated Effort**: 5 days (1 week)
|
||||
**Dependencies**: Story 15 (Resource migration complete)
|
||||
|
||||
## User Story
|
||||
|
||||
**As** a backend developer,
|
||||
**I want** to replace custom HTTP middleware with SDK transport layer,
|
||||
**So that** we support both stdio (CLI) and HTTP/SSE (web) transports with minimal code.
|
||||
|
||||
## Business Value
|
||||
|
||||
- **Multi-Transport**: Support stdio (Claude Desktop) + HTTP/SSE (web clients)
|
||||
- **Code Reduction**: Remove 150-200 lines of custom middleware
|
||||
- **Standard Compliance**: SDK handles MCP transport specification
|
||||
- **Future-Proof**: Easy to add WebSocket in future
|
||||
|
||||
## Current vs. Target Architecture
|
||||
|
||||
### Current (Custom Middleware)
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ Custom HTTP Middleware │
|
||||
├─────────────────────────────┤
|
||||
│ McpProtocolMiddleware │
|
||||
│ - JSON-RPC parsing │
|
||||
│ - Request routing │
|
||||
│ - Error handling │
|
||||
│ │
|
||||
│ ApiKeyAuthMiddleware │
|
||||
│ - API Key extraction │
|
||||
│ - Validation │
|
||||
│ - TenantContext setup │
|
||||
└─────────────────────────────┘
|
||||
↓
|
||||
MCP Handlers
|
||||
```
|
||||
|
||||
### Target (SDK Transport)
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ SDK Transport Layer │
|
||||
├─────────────────────────────┤
|
||||
│ stdio Transport │
|
||||
│ - Standard In/Out │
|
||||
│ - For CLI tools │
|
||||
│ │
|
||||
│ HTTP/SSE Transport │
|
||||
│ - REST API │
|
||||
│ - Server-Sent Events │
|
||||
│ - For web clients │
|
||||
└─────────────────────────────┘
|
||||
↓
|
||||
SDK Protocol Handler
|
||||
↓
|
||||
Custom Auth/Authz
|
||||
↓
|
||||
MCP Handlers
|
||||
```
|
||||
|
||||
## Transport Configuration
|
||||
|
||||
### stdio Transport (Claude Desktop)
|
||||
```csharp
|
||||
services.AddMcpServer(options =>
|
||||
{
|
||||
// stdio transport for CLI tools
|
||||
options.UseStdioTransport();
|
||||
});
|
||||
```
|
||||
|
||||
**Use Cases**:
|
||||
- Claude Desktop
|
||||
- VS Code Continue extension
|
||||
- CLI tools (Cline, etc.)
|
||||
|
||||
**Characteristics**:
|
||||
- Single-user mode
|
||||
- Process lifetime tied to parent process
|
||||
- No HTTP overhead
|
||||
- Fast and simple
|
||||
|
||||
---
|
||||
|
||||
### HTTP/SSE Transport (Web Clients)
|
||||
```csharp
|
||||
services.AddMcpServer(options =>
|
||||
{
|
||||
// HTTP/SSE transport for web clients
|
||||
options.UseHttpTransport(http =>
|
||||
{
|
||||
http.BasePath = "/mcp"; // Base URL
|
||||
http.EnableSse = true; // Server-Sent Events for notifications
|
||||
http.EnableCors = true; // CORS for web clients
|
||||
});
|
||||
});
|
||||
|
||||
// Map MCP endpoints
|
||||
app.MapMcpEndpoints("/mcp");
|
||||
```
|
||||
|
||||
**Endpoints**:
|
||||
- `POST /mcp/initialize` - Handshake
|
||||
- `POST /mcp/tools/list` - List Tools
|
||||
- `POST /mcp/tools/call` - Execute Tool
|
||||
- `POST /mcp/resources/list` - List Resources
|
||||
- `GET /mcp/resources/read` - Query Resource
|
||||
- `GET /mcp/sse` - SSE stream for notifications
|
||||
|
||||
**Use Cases**:
|
||||
- Web-based MCP clients
|
||||
- Custom integrations
|
||||
- Future ChatGPT plugin
|
||||
|
||||
**Characteristics**:
|
||||
- Multi-user mode
|
||||
- Stateless (requires API Key)
|
||||
- Supports SSE for real-time updates
|
||||
- CORS-enabled
|
||||
|
||||
---
|
||||
|
||||
## Custom Authentication Integration
|
||||
|
||||
### Preserve API Key Authentication
|
||||
```csharp
|
||||
services.AddMcpServer(options =>
|
||||
{
|
||||
options.UseStdioTransport();
|
||||
options.UseHttpTransport();
|
||||
|
||||
// Custom authentication handler
|
||||
options.AddAuthentication<ApiKeyAuthenticationHandler>();
|
||||
});
|
||||
|
||||
public class ApiKeyAuthenticationHandler : IMcpAuthenticationHandler
|
||||
{
|
||||
private readonly IMcpApiKeyService _apiKeyService;
|
||||
private readonly ITenantContext _tenantContext;
|
||||
|
||||
public async Task<McpAuthenticationResult> AuthenticateAsync(
|
||||
McpRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Extract API Key from header
|
||||
var apiKey = request.Headers["X-Api-Key"];
|
||||
|
||||
if (string.IsNullOrEmpty(apiKey))
|
||||
{
|
||||
return McpAuthenticationResult.Fail("API Key required");
|
||||
}
|
||||
|
||||
// Validate API Key (existing logic)
|
||||
var validationResult = await _apiKeyService.ValidateAsync(
|
||||
apiKey,
|
||||
cancellationToken);
|
||||
|
||||
if (!validationResult.IsValid)
|
||||
{
|
||||
return McpAuthenticationResult.Fail("Invalid API Key");
|
||||
}
|
||||
|
||||
// Setup TenantContext
|
||||
_tenantContext.SetTenant(validationResult.TenantId);
|
||||
|
||||
return McpAuthenticationResult.Success(new McpPrincipal
|
||||
{
|
||||
TenantId = validationResult.TenantId,
|
||||
UserId = validationResult.UserId,
|
||||
ApiKeyId = validationResult.ApiKeyId
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Preserve Field-Level Authorization
|
||||
```csharp
|
||||
services.AddMcpServer(options =>
|
||||
{
|
||||
// Custom authorization handler
|
||||
options.AddAuthorization<FieldLevelAuthorizationHandler>();
|
||||
});
|
||||
|
||||
public class FieldLevelAuthorizationHandler : IMcpAuthorizationHandler
|
||||
{
|
||||
private readonly IFieldPermissionService _fieldPermission;
|
||||
|
||||
public async Task<bool> AuthorizeAsync(
|
||||
McpPrincipal principal,
|
||||
string operation,
|
||||
object resource,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Check field-level permissions
|
||||
return await _fieldPermission.HasAccessAsync(
|
||||
principal.TenantId,
|
||||
principal.UserId,
|
||||
operation,
|
||||
resource,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] stdio transport works (Claude Desktop compatible)
|
||||
- [ ] HTTP/SSE transport works (web client compatible)
|
||||
- [ ] API Key authentication functional
|
||||
- [ ] Field-level permissions enforced
|
||||
- [ ] Custom middleware removed (McpProtocolMiddleware, ApiKeyAuthMiddleware)
|
||||
- [ ] Zero breaking changes for existing MCP clients
|
||||
- [ ] CORS configured for web clients
|
||||
- [ ] SSE notifications working
|
||||
|
||||
## Tasks Breakdown
|
||||
|
||||
- [ ] [Task 1](sprint_5_story_16_task_1.md) - Configure SDK transports (stdio + HTTP/SSE) - 1 day
|
||||
- [ ] [Task 2](sprint_5_story_16_task_2.md) - Migrate API Key authentication to SDK pipeline - 1 day
|
||||
- [ ] [Task 3](sprint_5_story_16_task_3.md) - Migrate field-level authorization to SDK pipeline - 1 day
|
||||
- [ ] [Task 4](sprint_5_story_16_task_4.md) - Remove custom middleware and test end-to-end - 1 day
|
||||
- [ ] [Task 5](sprint_5_story_16_task_5.md) - CORS configuration and SSE notification testing - 1 day
|
||||
|
||||
**Progress**: 0/5 tasks completed (0%)
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### stdio Transport Tests
|
||||
- Claude Desktop connection
|
||||
- Tool calls via stdio
|
||||
- Resource queries via stdio
|
||||
- Error handling
|
||||
|
||||
### HTTP/SSE Transport Tests
|
||||
- HTTP POST endpoints
|
||||
- SSE connection establishment
|
||||
- Real-time notifications
|
||||
- CORS preflight requests
|
||||
|
||||
### Authentication Tests
|
||||
- Valid API Key
|
||||
- Invalid API Key
|
||||
- Expired API Key
|
||||
- Missing API Key
|
||||
|
||||
### Authorization Tests
|
||||
- Field-level permission checks
|
||||
- Unauthorized field access attempts
|
||||
|
||||
## Code to Remove
|
||||
|
||||
After migration complete:
|
||||
- `McpProtocolMiddleware.cs` (~150 lines)
|
||||
- `ApiKeyAuthMiddleware.cs` (~80 lines)
|
||||
- `McpEndpointRouting.cs` (~100 lines)
|
||||
|
||||
**Total**: ~330 lines removed
|
||||
|
||||
## Success Metrics
|
||||
|
||||
- **Code Reduction**: -330 lines (middleware)
|
||||
- **Transport Support**: 2 transports (stdio + HTTP/SSE)
|
||||
- **Compatibility**: 100% (Claude Desktop + web clients)
|
||||
- **Performance**: No regression (<5ms overhead)
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] SDK transports configured (stdio + HTTP/SSE)
|
||||
- [ ] Custom middleware removed
|
||||
- [ ] API Key authentication working
|
||||
- [ ] Field-level permissions enforced
|
||||
- [ ] Integration tests pass (both transports)
|
||||
- [ ] Claude Desktop compatibility verified
|
||||
- [ ] Web client compatibility verified
|
||||
- [ ] Code reviewed and approved
|
||||
|
||||
---
|
||||
|
||||
**Created**: 2025-11-09 by Product Manager Agent
|
||||
**Owner**: Backend Team
|
||||
**Start Date**: 2025-12-30 (Week 6)
|
||||
**Target Date**: 2026-01-03 (End of Week 6)
|
||||
**Status**: Not Started
|
||||
Reference in New Issue
Block a user