--- story_id: story_15 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: 3 --- # Story 15: Resource Migration to SDK Attributes **Parent Epic**: [Story 0](sprint_5_story_0.md) - Integrate Microsoft .NET MCP SDK **Phase**: 3 - Resource Migration (Week 5) **Priority**: P0 - Critical **Estimated Effort**: 5 days (1 week) **Dependencies**: Story 14 (Tool migration complete) ## User Story **As** a backend developer, **I want** to migrate all 11 MCP Resources from custom implementation to SDK attribute-based registration, **So that** we reduce boilerplate code while preserving multi-tenant isolation and Redis caching. ## Business Value - **Code Reduction**: Remove 200-250 lines of custom Resource infrastructure - **Performance**: SDK optimizations improve query speed by 30-40% - **Caching**: Preserve Redis caching with minimal changes - **Multi-Tenant**: Maintain 100% tenant isolation ## Resources to Migrate (11 Total) ### Core Resources (P0) 1. `projects.list` - List all projects 2. `projects.get/{id}` - Get project details 3. `issues.search` - Search issues with filters 4. `issues.get/{id}` - Get issue details 5. `sprints.current` - Get active Sprint ### Supporting Resources (P1) 6. `sprints.list` - List all Sprints 7. `users.list` - List team members 8. `docs.prd/{projectId}` - Get PRD document ### Advanced Resources (P2) 9. `reports.daily/{date}` - Daily status report 10. `reports.velocity` - Sprint velocity report 11. `audit.history/{entityId}` - Audit log history ## Migration Pattern ### Before (Custom Implementation) ```csharp public class ProjectsListResource : IMcpResource { public string Uri => "colaflow://projects.list"; public string Name => "Projects List"; public string Description => "List all projects"; public string MimeType => "application/json"; private readonly IProjectRepository _repo; private readonly ITenantContext _tenant; public async Task GetContentAsync( McpResourceRequest request, CancellationToken ct) { var projects = await _repo.GetAllAsync(_tenant.CurrentTenantId); return new McpResourceContent { Uri = Uri, MimeType = MimeType, Text = JsonSerializer.Serialize(new { projects }) }; } } ``` ### After (SDK Attributes) ```csharp [McpResource( Uri = "colaflow://projects.list", Name = "Projects List", Description = "List all projects in current tenant", MimeType = "application/json" )] public class ProjectsListResource { private readonly IProjectRepository _repo; private readonly ITenantContext _tenant; private readonly IDistributedCache _cache; // Redis preserved public ProjectsListResource( IProjectRepository repo, ITenantContext tenant, IDistributedCache cache) { _repo = repo; _tenant = tenant; _cache = cache; } public async Task GetContentAsync( McpContext context, CancellationToken cancellationToken) { // Preserve Redis caching var cacheKey = $"mcp:projects:list:{_tenant.CurrentTenantId}"; var cached = await _cache.GetStringAsync(cacheKey, cancellationToken); if (cached != null) { return McpResourceContent.Json(cached); } // Preserve multi-tenant filtering var projects = await _repo.GetAllAsync( _tenant.CurrentTenantId, cancellationToken); var json = JsonSerializer.Serialize(new { projects }); // Cache for 5 minutes await _cache.SetStringAsync( cacheKey, json, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5) }, cancellationToken); return McpResourceContent.Json(json); } } ``` ## Key Changes ### What Changes - ✅ Resource registration (custom → SDK attributes) - ✅ URI declaration (property → attribute) - ✅ Metadata (Name, Description in attribute) ### What Stays the Same - ✅ TenantContext filtering (preserved) - ✅ Redis caching logic (preserved) - ✅ Query logic (unchanged) - ✅ Response format (unchanged) ## Acceptance Criteria - [ ] All 11 Resources migrated to `[McpResource]` attributes - [ ] Multi-tenant isolation 100% verified - [ ] Redis cache hit rate >80% maintained - [ ] Response time <200ms (P95) - [ ] Integration tests pass - [ ] Claude Desktop can query all Resources - [ ] Zero breaking changes for MCP clients ## Tasks Breakdown - [ ] [Task 1](sprint_5_story_15_task_1.md) - Migrate P0 Resources (projects, issues, sprints.current) - 2 days - [ ] [Task 2](sprint_5_story_15_task_2.md) - Migrate P1 Resources (sprints.list, users, docs) - 1 day - [ ] [Task 3](sprint_5_story_15_task_3.md) - Migrate P2 Resources (reports, audit) - 1 day - [ ] [Task 4](sprint_5_story_15_task_4.md) - Multi-tenant isolation testing and cache verification - 1 day **Progress**: 0/4 tasks completed (0%) ## Testing Strategy ### Multi-Tenant Isolation Tests - Verify TenantContext extraction from McpContext - Test cross-tenant access attempts (should return 404) - Validate Global Query Filters applied ### Cache Performance Tests - Measure cache hit rate (target: >80%) - Verify cache invalidation on data changes - Test TTL expiration ### Integration Tests - Claude Desktop resource queries - Query parameter handling - Error responses (404, 403, 500) ## Success Metrics - **Code Reduction**: -200 lines (Resource infrastructure) - **Performance**: +30-40% faster queries - **Cache Hit Rate**: Maintain >80% - **Multi-Tenant**: 100% isolation verified ## Definition of Done - [ ] All 11 Resources migrated to SDK attributes - [ ] Multi-tenant isolation 100% verified - [ ] Redis caching verified (>80% hit rate) - [ ] Performance benchmarks show ≥30% improvement - [ ] Integration tests pass - [ ] Code reviewed and approved --- **Created**: 2025-11-09 by Product Manager Agent **Owner**: Backend Team **Start Date**: 2025-12-23 (Week 5) **Target Date**: 2025-12-27 (End of Week 5) **Status**: Not Started