- Добавить GlobalKeyboardService — выделенный поток с блокирующим Console.ReadKey, единственный источник клавишных событий для TUI - Убрать FocusManager из App.razor: перехватывал Tab до компонентов - Удалить @onkeydown с <Select>: RazorConsole не пробрасывает Tab/стрелки через этот механизм - Использовать FocusedValue вместо Value в Select для корректной подсветки - Обновить CLAUDE.md и AGENTS.md: архитектура TUI, RazorConsole gotchas - Добавить docs/tui_log.md: разбор проблемы и справочник по RazorConsole Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
2.5 KiB
C#
67 lines
2.5 KiB
C#
using LazyBear.MCP.Services.Confluence;
|
|
using LazyBear.MCP.Services.Jira;
|
|
using LazyBear.MCP.Services.Kubernetes;
|
|
using LazyBear.MCP.Services.Logging;
|
|
using LazyBear.MCP.Services.ToolRegistry;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
namespace LazyBear.MCP.Services.Mcp;
|
|
|
|
/// <summary>
|
|
/// Поднимает HTTP MCP endpoint в фоне, не вмешиваясь в основной TUI event loop.
|
|
/// Использует общие singleton-экземпляры из root host.
|
|
/// </summary>
|
|
public sealed class McpWebHostedService(
|
|
IServiceProvider rootServices,
|
|
IConfiguration configuration,
|
|
ILogger<McpWebHostedService> logger) : IHostedService
|
|
{
|
|
private WebApplication? _webApp;
|
|
|
|
public async Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
var builder = WebApplication.CreateBuilder();
|
|
var urls = Environment.GetEnvironmentVariable("ASPNETCORE_URLS") ?? "http://localhost:5000";
|
|
|
|
builder.WebHost.UseUrls(urls);
|
|
|
|
// Используем тот же IConfiguration и те же singleton-сервисы, что и в TUI host.
|
|
builder.Services.AddSingleton(configuration);
|
|
builder.Services.AddSingleton(rootServices.GetRequiredService<InMemoryLogSink>());
|
|
builder.Services.AddSingleton(rootServices.GetRequiredService<ToolRegistryService>());
|
|
builder.Services.AddSingleton(rootServices.GetRequiredService<K8sClientProvider>());
|
|
builder.Services.AddSingleton(rootServices.GetRequiredService<JiraClientProvider>());
|
|
builder.Services.AddSingleton(rootServices.GetRequiredService<ConfluenceClientProvider>());
|
|
|
|
foreach (var module in rootServices.GetServices<IToolModule>())
|
|
{
|
|
builder.Services.AddSingleton(module);
|
|
builder.Services.AddSingleton(typeof(IToolModule), module);
|
|
}
|
|
|
|
builder.Services.AddMcpServer()
|
|
.WithHttpTransport()
|
|
.WithToolsFromAssembly();
|
|
|
|
_webApp = builder.Build();
|
|
_webApp.MapMcp();
|
|
|
|
await _webApp.StartAsync(cancellationToken);
|
|
logger.LogInformation("HTTP MCP endpoint запущен на {Urls}", urls);
|
|
}
|
|
|
|
public async Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (_webApp is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
await _webApp.StopAsync(cancellationToken);
|
|
await _webApp.DisposeAsync();
|
|
_webApp = null;
|
|
}
|
|
}
|