Files
ColaFlow/colaflow-api/src/Modules/Mcp/ColaFlow.Modules.Mcp.Application/SdkResources/ProjectsSdkResource.cs
Yaojia Wang 34a379750f
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Clean up
2025-11-15 08:58:48 +01:00

107 lines
3.8 KiB
C#

using System.ComponentModel;
using System.Text.Json;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
namespace ColaFlow.Modules.Mcp.Application.SdkResources;
/// <summary>
/// MCP Resource: Projects (SDK-based implementation)
/// Provides access to project data in the current tenant
/// </summary>
[McpServerResourceType]
public class ProjectsSdkResource
{
private readonly IProjectRepository _projectRepository;
private readonly ITenantContext _tenantContext;
private readonly ILogger<ProjectsSdkResource> _logger;
public ProjectsSdkResource(
IProjectRepository projectRepository,
ITenantContext tenantContext,
ILogger<ProjectsSdkResource> logger)
{
_projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
_tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[McpServerResource]
[Description("List all projects in current tenant")]
public async Task<string> ListProjectsAsync(CancellationToken cancellationToken = default)
{
var tenantId = _tenantContext.GetCurrentTenantId();
_logger.LogDebug("Fetching projects list for tenant {TenantId} (SDK)", tenantId);
// Get all projects (read-only)
var projects = await _projectRepository.GetAllProjectsReadOnlyAsync(cancellationToken);
// Map to DTOs
var projectDtos = projects.Select(p => new
{
id = p.Id.Value,
name = p.Name,
key = p.Key.ToString(),
description = p.Description,
status = p.Status.ToString(),
createdAt = p.CreatedAt,
updatedAt = p.UpdatedAt,
epicCount = p.Epics?.Count ?? 0
}).ToList();
var result = JsonSerializer.Serialize(new
{
projects = projectDtos,
total = projectDtos.Count
}, new JsonSerializerOptions { WriteIndented = true });
_logger.LogInformation("Retrieved {Count} projects for tenant {TenantId} (SDK)", projectDtos.Count, tenantId);
return result;
}
[McpServerResource]
[Description("Get detailed information about a specific project")]
public async Task<string> GetProjectAsync(
[Description("The project ID")] Guid projectId,
CancellationToken cancellationToken = default)
{
var tenantId = _tenantContext.GetCurrentTenantId();
_logger.LogDebug("Fetching project {ProjectId} for tenant {TenantId} (SDK)", projectId, tenantId);
var project = await _projectRepository.GetByIdAsync(
ProjectManagement.Domain.ValueObjects.ProjectId.From(projectId),
cancellationToken);
if (project == null)
{
throw new InvalidOperationException($"Project with ID {projectId} not found");
}
var result = JsonSerializer.Serialize(new
{
id = project.Id.Value,
name = project.Name,
key = project.Key.ToString(),
description = project.Description,
status = project.Status.ToString(),
createdAt = project.CreatedAt,
updatedAt = project.UpdatedAt,
epics = project.Epics?.Select(e => new
{
id = e.Id.Value,
title = e.Name, // Epic uses Name instead of Title
status = e.Status.ToString()
}).ToList() ?? (object)new List<object>()
}, new JsonSerializerOptions { WriteIndented = true });
_logger.LogInformation("Retrieved project {ProjectId} for tenant {TenantId} (SDK)", projectId, tenantId);
return result;
}
}