Add interactive TUI dashboard for managing MCP servers#4680
Add interactive TUI dashboard for managing MCP servers#4680
Conversation
Add a terminal dashboard (thv tui) for managing MCP servers with: - Real-time workload list with status indicators and filtering - Tabbed panels for logs, server info, tools, proxy logs, and inspector - Tool inspector with form-based calling and JSON tree response viewer - Registry browser with search and detail view - Log search with case-insensitive highlighting and match navigation - Horizontal scrolling for long log lines - Keyboard-driven navigation with contextual help overlay The codebase is organized into focused files by area (inspector, registry, search, navigation) with shared form field helpers and sub-structs for clean state management. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow launching MCP servers directly from the registry browser. Press 'r' in the registry detail view to open a form with the workload name and environment variable fields pre-populated from registry metadata. Secret fields use password masking. On submit, the TUI spawns 'thv run' as a subprocess and refreshes the workload list on completion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Truncate long tool descriptions in the inspector form to 2 lines with an ellipsis and [i] hint to view the full text in the detail modal. This prevents verbose MCP tool descriptions from pushing form fields off screen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sort environment variable keys alphabetically before rendering in the server info panel. Go maps have non-deterministic iteration order, which caused env vars to shuffle on every 5-second refresh cycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover core logic functions with 130+ subtests across 8 test files: registry (sanitize, filter), view helpers (wrap, truncate, count), inspector (required set, field values, result formatting), logs (split, diff), log formatting (parse, level style), JSON tree (parse, flatten, collapse, roundtrip), search (highlight), and form helpers (navigation, blur). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Large PR Detected
This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.
How to unblock this PR:
Add a section to your PR description with the following format:
## Large PR Justification
[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformationAlternative:
Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.
See our Contributing Guidelines for more details.
This review will be automatically dismissed once you add the justification section.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4680 +/- ##
==========================================
- Coverage 68.84% 65.99% -2.86%
==========================================
Files 508 528 +20
Lines 52604 55348 +2744
==========================================
+ Hits 36215 36525 +310
- Misses 13587 16012 +2425
- Partials 2802 2811 +9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Escape single quotes in buildCurlStr to prevent shell injection when the generated curl command is pasted into a terminal (CodeQL finding). Cap log buffers at 10k lines to prevent unbounded memory growth during long-running sessions. Bound horizontal scroll to the longest line. Extract shared newBackendClientAndTarget helper to deduplicate fetchTools/callTool setup. Remove unused parameter from renderRegistryOverlay. Complete the --help keybinding list (8 → 20 bindings). Document diffLines duplicate-line limitation and secrets process-visibility tradeoff. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a new thv tui subcommand that launches an interactive Bubble Tea terminal dashboard for monitoring and operating MCP servers (workloads) from a single view, including logs, server info, tools, tool inspector, and a registry browser.
Changes:
- Add
thv tuiCobra command entrypoint and register it on the root CLI. - Introduce a new
pkg/tuiBubble Tea model with update/view logic for workload navigation, log streaming/search, tool inspection/calls, and registry browsing/run. - Add shared CLI/TUI UI helpers (styles, help rendering, spinner, slog handlers) and new dependencies (clipboard + Charmbracelet components).
Reviewed changes
Copilot reviewed 38 out of 39 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/thv/app/tui.go | Adds the thv tui command to start the Bubble Tea dashboard and route WARN/ERROR logs to the TUI. |
| cmd/thv/app/commands.go | Registers the new tui subcommand on the root command. |
| cmd/thv/app/ui/styles.go | Introduces shared color palette and ANSI-aware width/padding helpers used by the TUI. |
| cmd/thv/app/ui/spinner.go | Adds a simple TTY-only spinner utility for CLI progress output. |
| cmd/thv/app/ui/log_handler.go | Adds slog handlers for styled CLI output and for sending WARN/ERROR records into the TUI. |
| cmd/thv/app/ui/help.go | Updates styled CLI help output to include and describe the new tui command. |
| go.mod | Adds clipboard + bubbles + charmbracelet/x/ansi and bumps related Charmbracelet indirect deps. |
| go.sum | Records checksums for newly added/updated Go module dependencies. |
| pkg/tui/model.go | Defines core Bubble Tea model state (panels, filters, viewports, streams, overlays). |
| pkg/tui/init.go | Initializes the TUI model and default viewports with initial workload listing. |
| pkg/tui/update.go | Implements the main Bubble Tea update loop, message handling, and streaming orchestration. |
| pkg/tui/update_navigation.go | Adds key handling for navigation, actions (stop/restart/delete), panel switching, scrolling, and searches. |
| pkg/tui/update_search.go | Implements shared case-insensitive log/proxy-log search with highlighting and match navigation. |
| pkg/tui/update_inspector.go | Implements inspector-specific key handling (tool filter, form focus, JSON tree navigation/copy, tool calls). |
| pkg/tui/update_registry.go | Implements registry overlay navigation, filter input, detail view, and run-form interactions. |
| pkg/tui/actions.go | Adds async commands for workload operations and for running registry items via a thv run subprocess. |
| pkg/tui/tools.go | Adds MCP client/target setup and tool fetching from running servers. |
| pkg/tui/logs.go | Implements workload log polling + line-diffing helpers. |
| pkg/tui/proxylogs.go | Implements proxy log polling + streaming into the TUI. |
| pkg/tui/logformat.go | Adds structured slog JSON parsing + formatting and ANSI-aware horizontal scrolling. |
| pkg/tui/inspector.go | Builds inspector form fields from tool schemas and formats curl + tool call results. |
| pkg/tui/json_tree.go | Implements a collapsible JSON tree for tool call responses (parse/flatten/render/copy). |
| pkg/tui/registry.go | Adds registry fetching plus helpers for filtering and building run-form fields. |
| pkg/tui/form_helpers.go | Adds reusable focus/blur/forward-key helpers for form fields. |
| pkg/tui/view.go | Renders the overall layout frame (sidebar + main panel + status bar) and overlays. |
| pkg/tui/view_statusbar.go | Renders the status/help bar and the help modal content. |
| pkg/tui/view_helpers.go | Adds shared rendering utilities (form fields, curl line highlighting, wrapping, truncation). |
| pkg/tui/view_info.go | Renders the Info panel combining workload runtime info and loaded RunConfig details. |
| pkg/tui/view_inspector.go | Renders the 3-column inspector (tool list + form + request/response + JSON tree/logs). |
| pkg/tui/view_registry.go | Renders registry overlays (list/detail/run form) and helper formatting/builders. |
| pkg/tui/*_test.go | Adds unit tests for pure helpers: logs diff/split, search highlighting, registry filtering, JSON tree ops, inspector helpers, form helpers, etc. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Single-quote and escape all dynamic values from registry metadata (server name, transport, permission profile, env var names) in the generated `thv run` command that is copied to clipboard. Without escaping, a malicious registry entry containing shell metacharacters could lead to arbitrary command execution when the user pastes the command into a terminal. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace single-line matching with a 3-line suffix sequence match to reliably detect the boundary between old and new log lines when the same message repeats. Falls back to single-line matching when prev has fewer than 3 lines or no sequence match is found. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix --secret flag format: pass secret env vars as --env NAME=VALUE since the run form collects actual values, not secrets-manager references - Add height < 2 guard in View() to prevent index-out-of-bounds panic on very small terminal resize events - Remove unused base-frame parameter from renderHelpOverlay and update its comment to match actual behavior - Fix three UTF-8 backspace bugs (registry filter, sidebar filter, inspector tool filter) that sliced by byte instead of by rune - Rewrite highlightSubstring to operate on rune indices so Unicode case mappings that change byte length cannot desync slice positions - Add defer in tuiCmdFunc to emit OSC 111 background-colour reset on abnormal exit paths (panics) that bypass View()'s quitting branch - Add unit tests for buildRunCmd covering transport, permission-profile, required/optional env vars, and combined flag cases Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review. |
Large PR justification has been provided. Thank you!
- gci: fix import block ordering in actions.go and json_tree.go - exhaustive: add all ContentType cases to formatInspResult switch; extract per-panel status bar hint helpers so renderStatusBar switch covers every activePanel value explicitly - gocyclo: suppress with nolint on inherently complex key-handler and renderer switch statements (handleInspectorKey, handleNormalKey, handleMsg, renderMain, renderInspResponse, renderStatusBar, renderJSONItem) - gosec G115: annotate uintptr→int conversions in help.go and spinner.go - gosec G204: annotate exec.CommandContext in actions.go - lll: break long runFromRegistry signature onto multiple lines - revive: add godoc comment to Model.View; rename unused width param to _ in renderTools - staticcheck: replace sb.WriteString(fmt.Sprintf(...)) with fmt.Fprintf - thelper: add t.Helper() to inline check closures in inspector_test.go - unparam: remove n parameter from makeFormFields (always 3) - unused: delete unreachable rebuildLogSearch and rebuildProxyLogSearch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Guard runFormSubmit against empty fields slice before indexing fields[0] - Initialize toolsView viewport in New() to avoid zero-width renders before the first WindowSizeMsg arrives - Cap inspector slog buffer at 500 lines (same pattern as logLines) - Validate that env var and secret keys do not contain '=' before constructing --env NAME=VALUE arguments - Clarify buildRunCmd comment: --secret references a secrets-manager entry, not an inline value; distinguish from runFromRegistry --env path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- errcheck: wrap deferred fmt.Fprint to discard return values - gci/gofmt: fix struct field alignment in keys.go (Space, CopyNode); add missing final newline in model.go; add spaces around arithmetic operators in view.go lipgloss chain - gosec G115: annotate three IsTerminal uintptr→int casts in spinner.go - lll: shorten nolint comment in view_inspector.go to fit 130-char limit - staticcheck QF1012: replace remaining sb.WriteString(fmt.Sprintf(...)) with fmt.Fprintf in help.go (footerHint, RenderCommandUsage, renderParentHelp) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Managing MCP servers through individual CLI commands requires remembering flags and switching between multiple terminal windows. An interactive dashboard lets users monitor, inspect, and operate servers from a single view.
thv tuicommand with a real-time terminal dashboard built on Bubble Teacommands.goto register the subcommandCloses #4370
Type of change
Test plan
task test)task lint-fix)Manually verified: launching
thv tui, browsing workloads, switching tabs, inspecting/calling tools, searching logs, browsing the registry, running a server from registry, and keyboard navigation including help overlay.Changes
cmd/thv/app/tui.gothv tuicommand entry pointcmd/thv/app/commands.gocmd/thv/app/ui/pkg/tui/model.gopkg/tui/init.gopkg/tui/update.gopkg/tui/update_navigation.gopkg/tui/update_inspector.gopkg/tui/update_registry.gopkg/tui/update_search.gopkg/tui/view*.gopkg/tui/actions.gopkg/tui/inspector.gopkg/tui/registry.gopkg/tui/json_tree.gopkg/tui/logformat.gopkg/tui/*_test.goDoes this introduce a user-facing change?
Yes. Users can now run
thv tuito open an interactive terminal dashboard for monitoring and managing MCP servers. The dashboard provides real-time status, log viewing, tool inspection and calling, and registry browsing — all from a single terminal window.Special notes for reviewers
commands.goare new — no existing command logic or packages were modified.bubbletea) — main TUI framework (already a dependency before this branch)bubbles) — companion component library (text inputs, viewports, spinners, etc.)lipgloss) — styling and layout (already a dependency before this branch)thv runas a subprocess rather than calling internal APIs directly, keeping the TUI decoupled from runtime internals.Large PR Justification
This PR is large because it introduces an entirely self-contained new feature with no modifications to existing packages. All ~7000 lines are new files in
pkg/tui/andcmd/thv/app/ui/— the only change to existing code is a single line incommands.goto register the subcommand. Splitting this into smaller PRs would either ship a non-functional intermediate state or require artificial scaffolding that would be immediately removed.Generated with Claude Code