feat: внедрение RazorConsole TUI с runtime-управлением MCP-инструментами
- Добавлен RazorConsole.Core для интерактивного TUI-дашборда - ToolRegistryService: живое включение/отключение модулей и отдельных методов - InMemoryLogSink: кольцевой буфер логов с фильтрацией по модулю - TUI: 3 таба (Overview, Logs, Settings) - IToolModule: generic-интерфейс для легкого добавления новых MCP-модулей - Guard-проверка TryCheckEnabled() во всех существующих инструментах
This commit is contained in:
@@ -1,23 +1,42 @@
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using ModelContextProtocol.Server;
|
||||
using RestSharp;
|
||||
|
||||
namespace LazyBear.MCP.Services.Jira;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration configuration)
|
||||
public sealed class JiraIssueTools(
|
||||
JiraClientProvider provider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry)
|
||||
{
|
||||
private readonly RestClient? _client = provider.Client;
|
||||
private readonly string? _clientInitializationError = provider.InitializationError;
|
||||
private readonly string _token = configuration["Jira:Token"] ?? string.Empty;
|
||||
private readonly string _defaultProject = configuration["Jira:Project"] ?? string.Empty;
|
||||
|
||||
private const string ModuleName = "Jira";
|
||||
|
||||
private bool TryCheckEnabled(string toolName, out string error)
|
||||
{
|
||||
if (!registry.IsToolEnabled(ModuleName, toolName))
|
||||
{
|
||||
error = $"Инструмент '{toolName}' модуля Jira отключён в TUI.";
|
||||
return false;
|
||||
}
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
[McpServerTool, Description("Получить задачу Jira по ключу")]
|
||||
public async Task<string> GetIssue(
|
||||
[Description("Ключ задачи, например PROJ-123")] string issueKey,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetIssue", out var enabledError)) return enabledError;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(issueKey))
|
||||
{
|
||||
return "Ключ задачи Jira не задан.";
|
||||
@@ -60,6 +79,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Максимум задач в ответе")] int maxResults = 20,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListIssues", out var enabledError)) return enabledError;
|
||||
|
||||
if (!TryGetClient(out var client, out var error))
|
||||
{
|
||||
return error;
|
||||
@@ -118,6 +139,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Описание задачи")] string? description = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("CreateIssue", out var enabledError)) return enabledError;
|
||||
|
||||
if (!TryGetClient(out var client, out var error))
|
||||
{
|
||||
return error;
|
||||
@@ -190,6 +213,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Новое описание")] string? description = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("UpdateIssue", out var enabledError)) return enabledError;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(summary) && string.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
return $"Нет полей для обновления задачи '{issueKey}'.";
|
||||
@@ -256,6 +281,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Ключ задачи")] string issueKey,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetIssueStatuses", out var enabledError)) return enabledError;
|
||||
|
||||
if (!TryGetClient(out var client, out var error))
|
||||
{
|
||||
return error;
|
||||
@@ -301,6 +328,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Максимум комментариев")] int limit = 20,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListIssueComments", out var enabledError)) return enabledError;
|
||||
|
||||
if (!TryGetClient(out var client, out var error))
|
||||
{
|
||||
return error;
|
||||
@@ -349,6 +378,8 @@ public sealed class JiraIssueTools(JiraClientProvider provider, IConfiguration c
|
||||
[Description("Текст комментария")] string body,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("AddComment", out var enabledError)) return enabledError;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
return "Текст комментария Jira не задан.";
|
||||
|
||||
20
LazyBear.MCP/Services/Jira/JiraToolModule.cs
Normal file
20
LazyBear.MCP/Services/Jira/JiraToolModule.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
|
||||
namespace LazyBear.MCP.Services.Jira;
|
||||
|
||||
public sealed class JiraToolModule : IToolModule
|
||||
{
|
||||
public string ModuleName => "Jira";
|
||||
public string Description => "Jira: задачи, комментарии, переходы статусов";
|
||||
|
||||
public IReadOnlyList<string> ToolNames =>
|
||||
[
|
||||
"GetIssue",
|
||||
"ListIssues",
|
||||
"CreateIssue",
|
||||
"UpdateIssue",
|
||||
"GetIssueStatuses",
|
||||
"ListIssueComments",
|
||||
"AddComment"
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user