Skip to content

Commit 41b5301

Browse files
authored
Merge branch 'main' into 012-unified-health-status
2 parents 5d49835 + 0500460 commit 41b5301

41 files changed

Lines changed: 3249 additions & 50 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,5 +331,8 @@ See `docs/github-actions-windows-wix-research.md` for CI setup.
331331
See `docs/prerelease-builds.md` for download instructions.
332332

333333
## Active Technologies
334-
- Go 1.24.0 + mcp-go (MCP protocol), zap (logging), chi (HTTP router), Vue 3/TypeScript (frontend) (012-unified-health-status)
335-
- BBolt embedded database (`~/.mcpproxy/config.db`) - existing, no schema changes (012-unified-health-status)
334+
- Go 1.24 (toolchain go1.24.10) (001-update-version-display)
335+
- In-memory only for version cache (no persistence per clarification) (001-update-version-display)
336+
337+
## Recent Changes
338+
- 001-update-version-display: Added Go 1.24 (toolchain go1.24.10)

cmd/mcpproxy/doctor_cmd.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,33 @@ func runDoctorClientMode(ctx context.Context, dataDir string, logger *zap.Logger
9191
socketPath := socket.DetectSocketPath(dataDir)
9292
client := cliclient.NewClient(socketPath, logger.Sugar())
9393

94+
// Call GET /api/v1/info for version and update info
95+
info, err := client.GetInfo(ctx)
96+
if err != nil {
97+
logger.Debug("Failed to get info from daemon", zap.Error(err))
98+
// Non-fatal: continue with diagnostics even if info fails
99+
}
100+
94101
// Call GET /api/v1/diagnostics
95102
diag, err := client.GetDiagnostics(ctx)
96103
if err != nil {
97104
return fmt.Errorf("failed to get diagnostics from daemon: %w", err)
98105
}
99106

100-
return outputDiagnostics(diag)
107+
return outputDiagnostics(diag, info)
101108
}
102109

103-
func outputDiagnostics(diag map[string]interface{}) error {
110+
func outputDiagnostics(diag map[string]interface{}, info map[string]interface{}) error {
104111
switch doctorOutput {
105112
case "json":
106-
output, err := json.MarshalIndent(diag, "", " ")
113+
// Combine diagnostics with info for JSON output
114+
combined := map[string]interface{}{
115+
"diagnostics": diag,
116+
}
117+
if info != nil {
118+
combined["info"] = info
119+
}
120+
output, err := json.MarshalIndent(combined, "", " ")
107121
if err != nil {
108122
return fmt.Errorf("failed to format output: %w", err)
109123
}
@@ -115,6 +129,30 @@ func outputDiagnostics(diag map[string]interface{}) error {
115129
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
116130
fmt.Println("🔍 MCPProxy Health Check")
117131
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
132+
133+
// Display version information
134+
if info != nil {
135+
version := getStringField(info, "version")
136+
if version != "" {
137+
// Check for update info
138+
if updateInfo, ok := info["update"].(map[string]interface{}); ok {
139+
updateAvailable := getBoolField(updateInfo, "available")
140+
latestVersion := getStringField(updateInfo, "latest_version")
141+
releaseURL := getStringField(updateInfo, "release_url")
142+
143+
if updateAvailable && latestVersion != "" {
144+
fmt.Printf("Version: %s (update available: %s)\n", version, latestVersion)
145+
if releaseURL != "" {
146+
fmt.Printf("Download: %s\n", releaseURL)
147+
}
148+
} else {
149+
fmt.Printf("Version: %s (latest)\n", version)
150+
}
151+
} else {
152+
fmt.Printf("Version: %s\n", version)
153+
}
154+
}
155+
}
118156
fmt.Println()
119157

120158
if totalIssues == 0 {

cmd/mcpproxy/doctor_cmd_test.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestOutputDiagnostics_JSONFormat(t *testing.T) {
3030
defer func() { os.Stdout = oldStdout }()
3131

3232
doctorOutput = "json"
33-
err := outputDiagnostics(diag)
33+
err := outputDiagnostics(diag, nil)
3434

3535
w.Close()
3636
var buf bytes.Buffer
@@ -47,9 +47,13 @@ func TestOutputDiagnostics_JSONFormat(t *testing.T) {
4747
t.Errorf("JSON output is invalid: %v", err)
4848
}
4949

50-
// Verify data preserved
51-
if getIntField(parsed, "total_issues") != 2 {
52-
t.Errorf("Expected total_issues=2, got %v", parsed["total_issues"])
50+
// Verify data preserved (now nested under "diagnostics")
51+
diagData, ok := parsed["diagnostics"].(map[string]interface{})
52+
if !ok {
53+
t.Errorf("Expected diagnostics object in JSON output")
54+
}
55+
if getIntField(diagData, "total_issues") != 2 {
56+
t.Errorf("Expected total_issues=2, got %v", diagData["total_issues"])
5357
}
5458
}
5559

@@ -65,7 +69,7 @@ func TestOutputDiagnostics_PrettyFormat_NoIssues(t *testing.T) {
6569
defer func() { os.Stdout = oldStdout }()
6670

6771
doctorOutput = "pretty"
68-
err := outputDiagnostics(diag)
72+
err := outputDiagnostics(diag, nil)
6973

7074
w.Close()
7175
var buf bytes.Buffer
@@ -107,7 +111,7 @@ func TestOutputDiagnostics_PrettyFormat_WithUpstreamErrors(t *testing.T) {
107111
defer func() { os.Stdout = oldStdout }()
108112

109113
doctorOutput = "pretty"
110-
err := outputDiagnostics(diag)
114+
err := outputDiagnostics(diag, nil)
111115

112116
w.Close()
113117
var buf bytes.Buffer
@@ -154,7 +158,7 @@ func TestOutputDiagnostics_PrettyFormat_WithOAuthRequired(t *testing.T) {
154158
defer func() { os.Stdout = oldStdout }()
155159

156160
doctorOutput = "pretty"
157-
err := outputDiagnostics(diag)
161+
err := outputDiagnostics(diag, nil)
158162

159163
w.Close()
160164
var buf bytes.Buffer
@@ -201,7 +205,7 @@ func TestOutputDiagnostics_PrettyFormat_WithMissingSecrets(t *testing.T) {
201205
defer func() { os.Stdout = oldStdout }()
202206

203207
doctorOutput = "pretty"
204-
err := outputDiagnostics(diag)
208+
err := outputDiagnostics(diag, nil)
205209

206210
w.Close()
207211
var buf bytes.Buffer
@@ -246,7 +250,7 @@ func TestOutputDiagnostics_PrettyFormat_WithRuntimeWarnings(t *testing.T) {
246250
defer func() { os.Stdout = oldStdout }()
247251

248252
doctorOutput = "pretty"
249-
err := outputDiagnostics(diag)
253+
err := outputDiagnostics(diag, nil)
250254

251255
w.Close()
252256
var buf bytes.Buffer
@@ -300,7 +304,7 @@ func TestOutputDiagnostics_PrettyFormat_MultipleIssueTypes(t *testing.T) {
300304
defer func() { os.Stdout = oldStdout }()
301305

302306
doctorOutput = "pretty"
303-
err := outputDiagnostics(diag)
307+
err := outputDiagnostics(diag, nil)
304308

305309
w.Close()
306310
var buf bytes.Buffer
@@ -347,7 +351,7 @@ func TestOutputDiagnostics_PrettyFormat_SingleIssue(t *testing.T) {
347351
defer func() { os.Stdout = oldStdout }()
348352

349353
doctorOutput = "pretty"
350-
err := outputDiagnostics(diag)
354+
err := outputDiagnostics(diag, nil)
351355

352356
w.Close()
353357
var buf bytes.Buffer
@@ -377,7 +381,7 @@ func TestOutputDiagnostics_EmptyFormat(t *testing.T) {
377381

378382
// Empty string should default to pretty format
379383
doctorOutput = ""
380-
err := outputDiagnostics(diag)
384+
err := outputDiagnostics(diag, nil)
381385

382386
w.Close()
383387
var buf bytes.Buffer
@@ -542,7 +546,7 @@ func TestOutputDiagnostics_WarningWithoutTitle(t *testing.T) {
542546
defer func() { os.Stdout = oldStdout }()
543547

544548
doctorOutput = "pretty"
545-
err := outputDiagnostics(diag)
549+
err := outputDiagnostics(diag, nil)
546550

547551
w.Close()
548552
var buf bytes.Buffer
@@ -577,7 +581,7 @@ func TestOutputDiagnostics_HighSeverityWarning(t *testing.T) {
577581
defer func() { os.Stdout = oldStdout }()
578582

579583
doctorOutput = "pretty"
580-
err := outputDiagnostics(diag)
584+
err := outputDiagnostics(diag, nil)
581585

582586
w.Close()
583587
var buf bytes.Buffer
@@ -615,7 +619,7 @@ func TestOutputDiagnostics_SecretWithoutOptionalFields(t *testing.T) {
615619
defer func() { os.Stdout = oldStdout }()
616620

617621
doctorOutput = "pretty"
618-
err := outputDiagnostics(diag)
622+
err := outputDiagnostics(diag, nil)
619623

620624
w.Close()
621625
var buf bytes.Buffer

docs/api/rest-api.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,51 @@ Run health checks (same as `mcpproxy doctor` CLI).
188188

189189
#### GET /api/v1/info
190190

191-
Get application info and version.
191+
Get application info, version, and update availability.
192+
193+
**Response:**
194+
```json
195+
{
196+
"success": true,
197+
"data": {
198+
"version": "v1.2.3",
199+
"web_ui_url": "http://127.0.0.1:8080/?apikey=xxx",
200+
"listen_addr": "127.0.0.1:8080",
201+
"endpoints": {
202+
"http": "127.0.0.1:8080",
203+
"socket": "/Users/user/.mcpproxy/mcpproxy.sock"
204+
},
205+
"update": {
206+
"available": true,
207+
"latest_version": "v1.3.0",
208+
"release_url": "https://github.com/smart-mcp-proxy/mcpproxy-go/releases/tag/v1.3.0",
209+
"checked_at": "2025-01-15T10:30:00Z",
210+
"is_prerelease": false
211+
}
212+
}
213+
}
214+
```
215+
216+
**Response Fields:**
217+
218+
| Field | Type | Description |
219+
|-------|------|-------------|
220+
| `version` | string | Current MCPProxy version |
221+
| `web_ui_url` | string | URL to access the web control panel |
222+
| `listen_addr` | string | Server listen address |
223+
| `endpoints.http` | string | HTTP API endpoint address |
224+
| `endpoints.socket` | string | Unix socket path (empty if disabled) |
225+
| `update` | object | Update information (may be null if not checked yet) |
226+
| `update.available` | boolean | Whether a newer version is available |
227+
| `update.latest_version` | string | Latest version available on GitHub |
228+
| `update.release_url` | string | URL to the GitHub release page |
229+
| `update.checked_at` | string | ISO 8601 timestamp of last update check |
230+
| `update.is_prerelease` | boolean | Whether the latest version is a prerelease |
231+
| `update.check_error` | string | Error message if update check failed |
232+
233+
:::tip Update Checking
234+
MCPProxy automatically checks for updates every 4 hours. The update information is exposed via this endpoint and used by the tray application and web UI to show update notifications.
235+
:::
192236

193237
### Docker
194238

0 commit comments

Comments
 (0)