fix(backend): Fix MCP module compilation errors by using correct exception classes
Replaced non-existent ColaFlow.Shared.Kernel.Exceptions namespace references with ColaFlow.Modules.Mcp.Domain.Exceptions in 5 files: Changes: - McpToolRegistry.cs: Use McpInvalidParamsException and McpNotFoundException - AddCommentTool.cs: Use McpInvalidParamsException and McpNotFoundException - CreateIssueTool.cs: Use McpInvalidParamsException, McpNotFoundException, and ProjectId.From() - UpdateStatusTool.cs: Use McpNotFoundException - ToolParameterParser.cs: Use McpInvalidParamsException for all validation errors All BadRequestException -> McpInvalidParamsException All NotFoundException -> McpNotFoundException Also fixed CreateIssueTool to convert Guid to ProjectId value object. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
using System.Text.Json;
|
||||
using ColaFlow.Modules.Mcp.Application.DTOs;
|
||||
using ColaFlow.Modules.Mcp.Application.Services;
|
||||
using ColaFlow.Modules.Mcp.Application.Tools.Validation;
|
||||
using ColaFlow.Modules.Mcp.Contracts.Tools;
|
||||
using ColaFlow.Modules.Mcp.Domain.Exceptions;
|
||||
using ColaFlow.Modules.Mcp.Domain.Services;
|
||||
using ColaFlow.Modules.IssueManagement.Domain.Enums;
|
||||
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
|
||||
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
|
||||
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ColaFlow.Modules.Mcp.Application.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// MCP Tool: create_issue
|
||||
/// Creates a new Issue (Epic, Story, Task, or Bug)
|
||||
/// Generates a Diff Preview and creates a PendingChange for approval
|
||||
/// </summary>
|
||||
public class CreateIssueTool : IMcpTool
|
||||
{
|
||||
private readonly IPendingChangeService _pendingChangeService;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly ITenantContext _tenantContext;
|
||||
private readonly DiffPreviewService _diffPreviewService;
|
||||
private readonly ILogger<CreateIssueTool> _logger;
|
||||
|
||||
public string Name => "create_issue";
|
||||
|
||||
public string Description => "Create a new issue (Epic, Story, Task, or Bug) in a ColaFlow project. " +
|
||||
"The issue will be created in 'Backlog' status and requires human approval before being created.";
|
||||
|
||||
public McpToolInputSchema InputSchema => new()
|
||||
{
|
||||
Type = "object",
|
||||
Properties = new Dictionary<string, JsonSchemaProperty>
|
||||
{
|
||||
["projectId"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
Format = "uuid",
|
||||
Description = "The ID of the project to create the issue in"
|
||||
},
|
||||
["title"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
MinLength = 1,
|
||||
MaxLength = 200,
|
||||
Description = "Issue title (max 200 characters)"
|
||||
},
|
||||
["description"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
MaxLength = 2000,
|
||||
Description = "Detailed issue description (optional, max 2000 characters)"
|
||||
},
|
||||
["type"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
Enum = new[] { "Epic", "Story", "Task", "Bug" },
|
||||
Description = "Issue type"
|
||||
},
|
||||
["priority"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
Enum = new[] { "Low", "Medium", "High", "Critical" },
|
||||
Description = "Issue priority (optional, defaults to Medium)"
|
||||
},
|
||||
["assigneeId"] = new()
|
||||
{
|
||||
Type = "string",
|
||||
Format = "uuid",
|
||||
Description = "User ID to assign the issue to (optional)"
|
||||
}
|
||||
},
|
||||
Required = new List<string> { "projectId", "title", "type" }
|
||||
};
|
||||
|
||||
public CreateIssueTool(
|
||||
IPendingChangeService pendingChangeService,
|
||||
IProjectRepository projectRepository,
|
||||
ITenantContext tenantContext,
|
||||
DiffPreviewService diffPreviewService,
|
||||
ILogger<CreateIssueTool> logger)
|
||||
{
|
||||
_pendingChangeService = pendingChangeService ?? throw new ArgumentNullException(nameof(pendingChangeService));
|
||||
_projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
|
||||
_tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
|
||||
_diffPreviewService = diffPreviewService ?? throw new ArgumentNullException(nameof(diffPreviewService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public async Task<McpToolResult> ExecuteAsync(
|
||||
McpToolCall toolCall,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Executing create_issue tool");
|
||||
|
||||
// 1. Parse and validate input
|
||||
var projectId = ToolParameterParser.ParseGuid(toolCall.Arguments, "projectId", required: true)!.Value;
|
||||
var title = ToolParameterParser.ParseString(toolCall.Arguments, "title", required: true);
|
||||
var description = ToolParameterParser.ParseString(toolCall.Arguments, "description") ?? string.Empty;
|
||||
var type = ToolParameterParser.ParseEnum<IssueType>(toolCall.Arguments, "type", required: true)!.Value;
|
||||
var priority = ToolParameterParser.ParseEnum<IssuePriority>(toolCall.Arguments, "priority") ?? IssuePriority.Medium;
|
||||
var assigneeId = ToolParameterParser.ParseGuid(toolCall.Arguments, "assigneeId");
|
||||
|
||||
// Validate title
|
||||
if (string.IsNullOrWhiteSpace(title))
|
||||
throw new McpInvalidParamsException("Issue title cannot be empty");
|
||||
|
||||
if (title.Length > 200)
|
||||
throw new McpInvalidParamsException("Issue title cannot exceed 200 characters");
|
||||
|
||||
if (description.Length > 2000)
|
||||
throw new McpInvalidParamsException("Issue description cannot exceed 2000 characters");
|
||||
|
||||
// 2. Verify project exists
|
||||
var project = await _projectRepository.GetByIdAsync(ProjectId.From(projectId), cancellationToken);
|
||||
if (project == null)
|
||||
throw new McpNotFoundException("Project", projectId.ToString());
|
||||
|
||||
// 3. Build "after data" object for diff preview
|
||||
var afterData = new
|
||||
{
|
||||
projectId = projectId,
|
||||
title = title,
|
||||
description = description,
|
||||
type = type.ToString(),
|
||||
priority = priority.ToString(),
|
||||
status = IssueStatus.Backlog.ToString(), // Default status
|
||||
assigneeId = assigneeId
|
||||
};
|
||||
|
||||
// 4. Generate Diff Preview (CREATE operation)
|
||||
var diff = _diffPreviewService.GenerateCreateDiff(
|
||||
entityType: "Issue",
|
||||
afterEntity: afterData,
|
||||
entityKey: null // No key yet (will be generated on approval)
|
||||
);
|
||||
|
||||
// 5. Create PendingChange (do NOT execute yet)
|
||||
var pendingChange = await _pendingChangeService.CreateAsync(
|
||||
new CreatePendingChangeRequest
|
||||
{
|
||||
ToolName = Name,
|
||||
Diff = diff,
|
||||
ExpirationHours = 24
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"PendingChange created: {PendingChangeId} - CREATE Issue: {Title}",
|
||||
pendingChange.Id, title);
|
||||
|
||||
// 6. Return pendingChangeId to AI (NOT the created issue)
|
||||
return new McpToolResult
|
||||
{
|
||||
Content = new[]
|
||||
{
|
||||
new McpToolContent
|
||||
{
|
||||
Type = "text",
|
||||
Text = $"Issue creation request submitted for approval.\n\n" +
|
||||
$"**Pending Change ID**: {pendingChange.Id}\n" +
|
||||
$"**Status**: Pending Approval\n" +
|
||||
$"**Issue Type**: {type}\n" +
|
||||
$"**Title**: {title}\n" +
|
||||
$"**Priority**: {priority}\n" +
|
||||
$"**Project**: {project.Name}\n\n" +
|
||||
$"A human user must approve this change before the issue is created. " +
|
||||
$"The change will expire at {pendingChange.ExpiresAt:yyyy-MM-dd HH:mm} UTC if not approved."
|
||||
}
|
||||
},
|
||||
IsError = false
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error executing create_issue tool");
|
||||
|
||||
return new McpToolResult
|
||||
{
|
||||
Content = new[]
|
||||
{
|
||||
new McpToolContent
|
||||
{
|
||||
Type = "text",
|
||||
Text = $"Error: {ex.Message}"
|
||||
}
|
||||
},
|
||||
IsError = true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user