Skip to content

Latest commit

 

History

History
194 lines (133 loc) · 8.33 KB

File metadata and controls

194 lines (133 loc) · 8.33 KB

Feature Specification: Structured Server State

Feature Branch: 013-structured-server-state Created: 2025-12-13 Updated: 2025-12-16 Status: Ready for Implementation Depends On: #192 (Unified Health Status) - merged to main

Problem Statement

The system has two separate data sources for server health:

  1. Health Status (server.health) - Per-server health with action buttons
  2. Diagnostics (/api/v1/diagnostics) - System-wide aggregation with CLI hints

These systems detect the same issues independently, leading to:

  • Duplicate banners on the Dashboard showing identical information
  • Inconsistent data between CLI (mcpproxy doctor) and Web UI
  • "Fix" buttons that show CLI hints instead of navigating to relevant pages

Goal: Health becomes the single source of truth for per-server issues. Diagnostics aggregates from Health for system-wide views.

User Scenarios & Testing

User Story 1 - Fix Server Issues via Web UI (Priority: P1)

As a developer, when I see a server health issue, I want the "Fix" button to navigate me to the right place to fix it.

Acceptance Scenarios:

  1. Given a server with a missing secret, When I click Fix, Then I navigate to /ui/secrets
  2. Given a server with OAuth config issue, When I click Fix, Then I navigate to server config tab
  3. Given a server with connection error, When I click Restart, Then the server restarts

User Story 2 - Consistent CLI and Web UI (Priority: P1)

As a developer, I want mcpproxy doctor and the Web UI to show the same issues.

Acceptance Scenarios:

  1. Given a missing secret, When I run mcpproxy doctor, Then I see the same servers affected as in the Web UI
  2. Given an OAuth issue, When I view Dashboard, Then I see the same information as mcpproxy doctor --json

User Story 3 - Single Health Banner (Priority: P2)

As a developer, I want to see ONE consolidated health display on the Dashboard.

Acceptance Scenarios:

  1. Given servers with issues, When I view Dashboard, Then I see one "Servers Needing Attention" section (not two separate banners)

User Story 4 - Tray Shows Correct Actions (Priority: P1)

As a developer, when I click on a server in the macOS tray menu, I want to see the appropriate action based on the server's health status.

Acceptance Scenarios:

  1. Given a stdio OAuth server needing login (e.g., npx @anthropic/mcp-gcal), When I click on it in the tray, Then I see "⚠️ Login Required" as a menu option
  2. Given a server with health.action == "login", When I view tray, Then "Login Required" appears regardless of whether server uses URL or command
  3. Given a healthy server, When I view tray status, Then the tray shows the same connected count as Web UI

User Story 5 - Web UI Shows Clean Error State (Priority: P2)

As a developer, when a server needs authentication, I don't want to see redundant technical error messages.

Acceptance Scenarios:

  1. Given a server with health.action == "login", When I view it in Web UI, Then I see only the "Login" button, not a verbose error alert
  2. Given a server with health.action == "set_secret", When I view it, Then I see only the "Set Secret" button, not the underlying error

Requirements

Health as Source of Truth

  • FR-001: Health MUST detect missing secrets and set action: "set_secret" with secret name in detail
  • FR-002: Health MUST detect OAuth config issues and set action: "configure" with error in detail
  • FR-003: Health MUST be the single source of truth for all per-server issues

Health Actions

  • FR-004: Health actions MUST include: login, restart, enable, approve, set_secret, configure, view_logs, ""
  • FR-005: Each action MUST map to a UI navigation target or in-place action
Action UI Behavior
login Trigger OAuth flow
restart Restart the server
enable Enable the server
approve Unquarantine the server
set_secret Navigate to /ui/secrets
configure Navigate to server config tab
view_logs Navigate to server logs tab
"" No action needed

Diagnostics Aggregation

  • FR-006: Diagnostics MUST aggregate from individual server Health objects
  • FR-007: Diagnostics MUST NOT have independent detection logic for issues that Health already detects
  • FR-008: Diagnostics MUST group set_secret issues by secret name (cross-cutting: one secret affects multiple servers)
  • FR-009: Diagnostics MUST include system-level checks (Docker status) that aren't per-server

Web UI

  • FR-010: Dashboard MUST display ONE consolidated health section
  • FR-011: Fix/action buttons MUST navigate to relevant pages, not show CLI hints

CLI

  • FR-012: upstream list MUST handle new Health actions with appropriate CLI hints

Tray Application

  • FR-013: Tray MUST use health.level for server status icons, not legacy connected field
  • FR-014: Tray MUST use health.action to determine available actions, not URL heuristics
  • FR-015: Tray MUST show "Login" action when health.action == "login", regardless of transport protocol (stdio/http)
  • FR-016: Tray MUST use health.summary for status text, not construct from legacy fields
  • FR-017: Tray MUST use health.detail for tooltip details, not last_error
Health Action Tray Menu Item Behavior
login "⚠️ Login Required" Opens OAuth flow
restart "🔄 Restart" Restarts server
enable "Enable" Enables server
approve "Approve" Unquarantines server
set_secret "⚠️ Set Secret" Opens Web UI secrets page
configure "⚠️ Configure" Opens Web UI server config
view_logs "View Logs" Opens Web UI logs page
"" (standard menu) No special action needed

Web UI Error Display

  • FR-018: Web UI MUST NOT show redundant last_error when health.action already conveys the issue
  • FR-019: When health.action is login, set_secret, or configure, the action button is sufficient - suppress verbose error alert

Success Criteria

  • SC-001: Users see exactly ONE health section on Dashboard
  • SC-002: mcpproxy doctor output is derived from same data as Web UI
  • SC-003: All action buttons navigate to appropriate fix locations
  • SC-004: Missing secrets show which servers are affected (aggregated by secret name)
  • SC-005: Tray shows "Login Required" for stdio OAuth servers (e.g., Google Calendar via npx)
  • SC-006: Tray connected count matches Web UI and CLI (all use health.level)
  • SC-007: Web UI does not show verbose error message when login button is already displayed

Health Status Reference

Levels

  • healthy - No issues
  • degraded - Minor issues (connecting, token expiring)
  • unhealthy - Needs attention

Admin States

  • enabled - Normal operation
  • disabled - User disabled
  • quarantined - Pending approval

Actions (Updated)

Scenario Level Action Detail Web UI CLI Hint
Healthy healthy "" - - -
Connecting degraded "" - - -
Token expiring degraded login expiry time OAuth flow auth login --server=X
Connection error unhealthy restart error message Restarts server upstream restart X
OAuth needed unhealthy login - OAuth flow auth login --server=X
Missing secret unhealthy set_secret secret name /ui/secrets Set SECRET_NAME
OAuth config issue unhealthy configure error/param Server config tab Edit config
Disabled healthy enable - Enables server upstream enable X
Quarantined healthy approve - Approves server Approve in Web UI

Out of Scope

  • Adding new health checks (disk space, index health, latency metrics)
  • Removing deprecated flat fields on Server struct
  • Changes to the MCP protocol tool responses

Commit Message Conventions

Issue References

  • Use: Related #[issue-number] - Links without auto-closing
  • Do NOT use: Fixes #, Closes #, Resolves # - These auto-close on merge

Co-Authorship

  • Do NOT include AI attribution in commits