Skip to content

Commit 087cfdd

Browse files
docs: update 013 spec to reflect current implementation state
Mark completed items from smart-mcp-proxy#192 (Unified Health Status): - HealthStatus struct and calculator implemented - Health field on Server struct - Frontend HealthStatus interface and component integration - Action buttons working in ServerCard and Dashboard Narrow remaining scope to: - Structured state objects (OAuthState, ConnectionState) - Doctor() aggregation from Health - Dashboard UI consolidation
1 parent d31b8ba commit 087cfdd

7 files changed

Lines changed: 1162 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Specification Quality Checklist: Structured Server State
2+
3+
**Purpose**: Validate specification completeness and quality before proceeding to planning
4+
**Created**: 2025-12-13
5+
**Feature**: [spec.md](../spec.md)
6+
7+
## Content Quality
8+
9+
- [x] No implementation details (languages, frameworks, APIs)
10+
- [x] Focused on user value and business needs
11+
- [x] Written for non-technical stakeholders
12+
- [x] All mandatory sections completed
13+
14+
## Requirement Completeness
15+
16+
- [x] No [NEEDS CLARIFICATION] markers remain
17+
- [x] Requirements are testable and unambiguous
18+
- [x] Success criteria are measurable
19+
- [x] Success criteria are technology-agnostic (no implementation details)
20+
- [x] All acceptance scenarios are defined
21+
- [x] Edge cases are identified
22+
- [x] Scope is clearly bounded
23+
- [x] Dependencies and assumptions identified
24+
25+
## Feature Readiness
26+
27+
- [x] All functional requirements have clear acceptance criteria
28+
- [x] User scenarios cover primary flows
29+
- [x] Feature meets measurable outcomes defined in Success Criteria
30+
- [x] No implementation details leak into specification
31+
32+
## Notes
33+
34+
- All items pass validation
35+
- Spec is ready for `/speckit.clarify` or `/speckit.plan`
36+
- Key design decisions captured from prior conversation:
37+
- Structured state objects (OAuthState, ConnectionState) added to Server
38+
- Flat fields kept for backwards compatibility
39+
- Health calculated server-side from structured state
40+
- Doctor() aggregates from Health (single source of truth)
41+
- DockerStatus remains the only system-level check
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# API Contract Changes: Structured Server State
2+
3+
**Feature**: 013-structured-server-state
4+
**Date**: 2025-12-13
5+
**Updated**: 2025-12-16
6+
7+
## Implementation Status
8+
9+
| Change | Status | Notes |
10+
|--------|--------|-------|
11+
| `health` field on Server | ✅ DONE | Merged in #192 |
12+
| `oauth_state` field on Server | ❌ TODO | Proposed in this doc |
13+
| `connection_state` field on Server | ❌ TODO | Proposed in this doc |
14+
| Diagnostics aggregation from Health | ❌ TODO | Doctor() still uses raw fields |
15+
16+
## Overview
17+
18+
This document describes the API changes for the structured server state feature. All changes are **additive** - existing fields remain unchanged for backwards compatibility.
19+
20+
## Affected Endpoints
21+
22+
| Endpoint | Change Type | Description |
23+
|----------|-------------|-------------|
24+
| `GET /api/v1/servers` | Additive | Add `oauth_state`, `connection_state` to each server |
25+
| `GET /api/v1/diagnostics` | Modified | Aggregate from `server.Health` instead of separate logic |
26+
| `GET /events` (SSE) | No change | Existing `servers.changed` events include updated data |
27+
28+
## Schema Changes
29+
30+
### Server Object (Additive)
31+
32+
**New Fields**:
33+
34+
```yaml
35+
Server:
36+
type: object
37+
properties:
38+
# ... existing properties unchanged ...
39+
40+
oauth_state:
41+
$ref: '#/components/schemas/OAuthState'
42+
description: OAuth authentication state (only present if OAuth configured)
43+
nullable: true
44+
45+
connection_state:
46+
$ref: '#/components/schemas/ConnectionState'
47+
description: Connection state (always present)
48+
```
49+
50+
### New Schema: OAuthState
51+
52+
```yaml
53+
OAuthState:
54+
type: object
55+
required:
56+
- status
57+
- retry_count
58+
- user_logged_out
59+
- has_refresh_token
60+
properties:
61+
status:
62+
type: string
63+
enum: [authenticated, expired, error, none]
64+
description: Current OAuth authentication status
65+
token_expires_at:
66+
type: string
67+
format: date-time
68+
description: When the access token expires (ISO 8601)
69+
last_attempt:
70+
type: string
71+
format: date-time
72+
description: When the last OAuth flow was attempted
73+
retry_count:
74+
type: integer
75+
minimum: 0
76+
description: Number of OAuth retry attempts
77+
user_logged_out:
78+
type: boolean
79+
description: True if the user explicitly logged out
80+
has_refresh_token:
81+
type: boolean
82+
description: True if auto-refresh is possible
83+
error:
84+
type: string
85+
description: Last OAuth error message (if any)
86+
```
87+
88+
### New Schema: ConnectionState
89+
90+
```yaml
91+
ConnectionState:
92+
type: object
93+
required:
94+
- status
95+
- retry_count
96+
- should_retry
97+
properties:
98+
status:
99+
type: string
100+
enum: [disconnected, connecting, ready, error]
101+
description: Current connection status
102+
connected_at:
103+
type: string
104+
format: date-time
105+
description: When the connection was established
106+
last_error:
107+
type: string
108+
description: Last connection error message
109+
retry_count:
110+
type: integer
111+
minimum: 0
112+
description: Number of connection retry attempts
113+
last_retry_at:
114+
type: string
115+
format: date-time
116+
description: When the last retry was attempted
117+
should_retry:
118+
type: boolean
119+
description: True if a retry is pending based on backoff
120+
```
121+
122+
## Example Response
123+
124+
### GET /api/v1/servers
125+
126+
```json
127+
{
128+
"success": true,
129+
"data": {
130+
"servers": [
131+
{
132+
"id": "abc123",
133+
"name": "github-server",
134+
"enabled": true,
135+
"quarantined": false,
136+
137+
"oauth_state": {
138+
"status": "authenticated",
139+
"token_expires_at": "2025-12-14T12:00:00Z",
140+
"last_attempt": "2025-12-13T10:00:00Z",
141+
"retry_count": 0,
142+
"user_logged_out": false,
143+
"has_refresh_token": true,
144+
"error": null
145+
},
146+
147+
"connection_state": {
148+
"status": "ready",
149+
"connected_at": "2025-12-13T10:01:00Z",
150+
"last_error": null,
151+
"retry_count": 0,
152+
"last_retry_at": null,
153+
"should_retry": false
154+
},
155+
156+
"health": {
157+
"level": "healthy",
158+
"admin_state": "enabled",
159+
"summary": "Connected (5 tools)",
160+
"detail": null,
161+
"action": ""
162+
},
163+
164+
"authenticated": true,
165+
"oauth_status": "authenticated",
166+
"connected": true,
167+
"last_error": "",
168+
"tool_count": 5
169+
}
170+
],
171+
"stats": { ... }
172+
}
173+
}
174+
```
175+
176+
### GET /api/v1/diagnostics
177+
178+
**Response structure unchanged** - Diagnostics is populated by aggregating `server.Health`:
179+
180+
```json
181+
{
182+
"success": true,
183+
"data": {
184+
"total_issues": 2,
185+
"upstream_errors": [
186+
{
187+
"server_name": "failing-server",
188+
"error_message": "Connection refused",
189+
"timestamp": "2025-12-13T11:00:00Z"
190+
}
191+
],
192+
"oauth_required": [
193+
{
194+
"server_name": "oauth-server",
195+
"state": "expired",
196+
"message": "Run: mcpproxy auth login --server=oauth-server"
197+
}
198+
],
199+
"oauth_issues": [],
200+
"missing_secrets": [],
201+
"runtime_warnings": [],
202+
"docker_status": {
203+
"available": true,
204+
"version": "24.0.5"
205+
},
206+
"timestamp": "2025-12-13T11:30:00Z"
207+
}
208+
}
209+
```
210+
211+
## Backwards Compatibility
212+
213+
| Existing Field | Status | Notes |
214+
|----------------|--------|-------|
215+
| `authenticated` | ✅ KEPT | Returns same value as `oauth_state.status == "authenticated"` |
216+
| `oauth_status` | ✅ KEPT | Returns same value as `oauth_state.status` |
217+
| `connected` | ✅ KEPT | Returns same value as `connection_state.status == "ready"` |
218+
| `connecting` | ✅ KEPT | Returns same value as `connection_state.status == "connecting"` |
219+
| `last_error` | ✅ KEPT | Returns same value as `connection_state.last_error` |
220+
| `reconnect_count` | ✅ KEPT | Returns same value as `connection_state.retry_count` |
221+
| `should_retry` | ✅ KEPT | Returns same value as `connection_state.should_retry` |
222+
| `health` | ✅ IMPLEMENTED | Added in #192, fully functional |
223+
224+
## Migration Path
225+
226+
1. **Phase 1**: Add new fields alongside existing (this feature)
227+
2. **Phase 2** (future): Deprecation warnings in API docs
228+
3. **Phase 3** (future): Remove flat fields in major version bump

0 commit comments

Comments
 (0)