Files
LazyBearWorks/CLAUDE.md

3.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Language Conventions

  • Output / explanations: Russian
  • Code: English
  • Comments, commit messages: Russian

Commands

# Build
dotnet build

# Run (starts TUI + HTTP MCP endpoint on port 5000)
dotnet run --project LazyBear.MCP

# Test MCP tool wiring (only needed after changing transport or tool registration)
npx @modelcontextprotocol/inspector dotnet run --project LazyBear.MCP

There are no test projects. After making changes, run dotnet build. If MCP wiring changed (new tool, new module, transport changes), also run the inspector.

Port is controlled via the ASPNETCORE_URLS environment variable (default http://localhost:5000). Ignore launchSettings.json — it shows a different port that is not used.

Architecture

LazyBear is a .NET 10 MCP server exposing Jira, Confluence, and Kubernetes integrations to AI clients. It runs in two simultaneous modes that share a single DI container:

  1. TUI (foreground) — RazorConsole terminal UI (App.razor), owns the console, handles keyboard navigation
  2. HTTP MCP endpoint (background)McpWebHostedService runs as a hosted service, serves MCP tool calls on port 5000

Both share the same singletons: ToolRegistryService, InMemoryLogSink, and the three client providers.

Plugin System (IToolModule)

Each integration implements IToolModule (in Services/ToolRegistry/IToolModule.cs) and declares its ModuleName, ToolNames[], and Description. Tool classes are auto-discovered at startup via reflection using WithToolsFromAssembly() — classes are annotated with [McpServerToolType], methods with [McpServerTool]. Registering a new module requires only: implement IToolModule, create tool classes with attributes, and add DI registration in Program.cs.

ToolRegistryService

Singleton that tracks enabled/disabled state for both modules and individual tools at runtime (no restart needed). Uses ConcurrentDictionary for thread safety. Fires StateChanged event on toggles; TUI components subscribe to re-render. Tool keys use the format "ModuleName::ToolName".

Provider Pattern

Each client (K8sClientProvider, JiraClientProvider, ConfluenceClientProvider) is a lazy singleton. If initialization fails (missing config, unreachable endpoint), it captures an InitializationError string. Tools return error strings instead of throwing exceptions — this is intentional so MCP clients see the configuration issue gracefully.

Logging

InMemoryLogSink maintains a 500-entry circular ConcurrentQueue. All .NET logs flow through InMemoryLoggerProvider → sink → OnLog event → TUI Logs tab live view.

TUI Navigation

Tabs: Overview → Logs → Settings (switch with Tab/Shift+Tab). In Settings: arrow keys navigate the module→tool tree, Space toggles enable/disable, Enter expands/collapses. In Overview, Enter on a module jumps to its Settings entry.

Configuration Gotchas

  • Jira:Url is required; if missing, all Jira tools return string errors
  • K8s kubeconfig fallback order: explicit Kubernetes:KubeconfigPath~/.kube/config → in-cluster config
  • Source of truth: Program.cs, not README.md (README is aspirational)
  • Pages/ directory exists but Razor Pages are not enabled in Program.cs — do not use them

Key Dependencies

Package Role
ModelContextProtocol.AspNetCore 1.2.0 HTTP MCP transport
KubernetesClient 19.0.2 K8s API
RestSharp 112.0.0 Jira / Confluence HTTP
RazorConsole.Core 0.5.0 Terminal UI framework
Polly 8.4.2 Retry/resilience policies