feat(macos): full native settings (REST config editor) in the tray app#537
Merged
Conversation
Deploying mcpproxy-docs with
|
| Latest commit: |
7d8fa80
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://76e108f2.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://061-macos-settings-tray.mcpproxy-docs.pages.dev |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
📦 Build ArtifactsWorkflow Run: View Run Available Artifacts
How to DownloadOption 1: GitHub Web UI (easiest)
Option 2: GitHub CLI gh run download 26655181691 --repo smart-mcp-proxy/mcpproxy-go
|
The MCP config pointed at /tmp/mcpproxy-ui-test, which gets wiped → the server failed to start with ENOENT. Add run.sh: it builds the binary from source (kept in this project) into .bin/ if missing or stale (module cache under .build/, build logs to stderr so they don't corrupt the stdio JSON-RPC stream), then execs it. Point the MCP config at run.sh so the tool self-heals after a clean checkout or /tmp wipe. .bin/ is gitignored.
Add a HIG-idiomatic Settings window opened from a new tray "Settings…" item (⌘,). Tabbed layout (General / Connection) hosted in a content-sized NSWindow, using the app's proven activation-policy-flip pattern so it shows reliably from an .accessory menu-bar app. - General: launch-at-login (SMAppService via AutoStartService), interface text size (appState.fontScale), "Open full configuration in browser…" (web UI), version. - Connection: endpoint + live connection status, Open Web UI. Per Constitution III the tray stays a stateless controller — only OS-level prefs (launch-at-login, text size) live here; all backend config defers to the web UI. Verified end-to-end with the mcpproxy-ui-test tools (menu item present, opens the window, renders all controls). Relates to native macOS tray UX.
Replace the thin Settings (launch-at-login + browser shortcut) with a full alternative-client config editor. The tray now edits all backend settings over REST — GET /api/v1/config to load, PATCH /api/v1/config (deep-merge, only changed fields) to save — never reading/writing the config JSON file directly. - SettingsCatalog.swift: Swift port of the web UI field catalogue (Security / General / Advanced sections) + validation + dot-path helpers. - ConfigSettingsView.swift: ConfigStore (load/save via REST) + reusable field rows and per-section save with dirty-tracking, validation, danger confirms (incl. telemetry info-tone), restart badges, and doc links. - SettingsView tabs: App (OS prefs: launch-at-login, text size) + Security + General + Advanced. Window made resizable. - APIClient: getConfig() + patchConfig(partial). Depends on PATCH /api/v1/config (Spec 060). Relates to native macOS tray UX.
dba3f7c to
e74dd39
Compare
DisclosureGroup only toggled when the chevron itself was clicked. Replace it with a custom collapsible whose entire header row is a plain Button with contentShape(Rectangle()), so clicking anywhere on the section title (or chevron) expands/collapses it. Relates to #537.
The app menu's 'Settings…' / ⌘, was wired to a leftover SwiftUI
`Settings {}` placeholder scene ('Use the MCPProxy tray menu to access
settings.'), a separate window from the real config window the tray
opens. Driving the SwiftUI Settings scene programmatically from a
menu-bar (.accessory) app proved unreliable (sendAction no-ops; even the
native ⌘, was flaky), so route every entry point to the one AppKit
config window instead:
- ⌘, is intercepted in the existing local key monitor.
- A click on the app-menu 'Settings…' item is repointed to
showSettingsWindow() in setupMainMenu().
- The SwiftUI Settings scene is reduced to a 1x1 bridge that, if ever
opened, hands off to the config window and dismisses itself — so the
stub can never reappear.
- Activation-policy restore is now driven by a global window-close
observer (the scene window isn't ours), replacing the delegate-only
check.
Verified ⌘, opens the real Settings window; final on-device screenshot
pending (screen was locked during the run).
…ab in Settings The main-window 'Configuration' sidebar item duplicated the new Settings window AND violated the REST-only contract: ConfigView read/wrote ~/.mcpproxy/mcp_config.json directly (Data(contentsOf:) / write(to:)), which bypasses the core's deep-merge (can clobber redacted secret headers), races the file watcher, and breaks entirely against a remote core. - Remove the 'Configuration' sidebar item and delete ConfigView.swift. - Add a read-only 'Raw' tab to the Settings window, sourced over REST (GET /api/v1/config via ConfigStore.prettyJSON) with a Copy button. Editing stays in the App/Security/General/Advanced forms; the Raw tab only mirrors the effective config the core is running. - Wire ⌘5 for the new tab. Main window is now operational-only (Dashboard/Servers/Activity/Secrets); all configuration lives in Settings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the macOS tray a full alternative client to the core: every backend setting is edited natively over REST, mirroring the web UI Configuration page. The tray never reads or writes the config JSON file directly — it loads via
GET /api/v1/configand saves only the changed fields via the deep-mergePATCH /api/v1/config(Spec 060, now on main), so unrelated settings and redacted secrets are never clobbered (Constitution III).Settings window — tabs (⌘1–⌘4)
Opened from a tray "Settings…" (⌘,) item using the activation-policy-flip pattern for
.accessoryapps. Per-section dirty-tracking + Save, inline validation (host:port, byte-size, durations, etc.), danger confirms (telemetry opt-out = gentle info tone), restart badges, and docs links — ported from the web UI.Implementation
SettingsCatalog.swift— Swift port of the web UI field catalogue + validation + dot-path helpers.ConfigSettingsView.swift—ConfigStore(REST load/save) + reusable field rows & per-section save.APIClient.getConfig()/patchConfig().run.shlauncher repairing themcpproxy-ui-testMCP server.Verification (mcpproxy-ui-test)
Built a PATCH-capable core, attached the tray via the unix socket (Core: Connected), and captured all four tabs via
screenshot_window(⌘1–⌘4 to navigate). The General tab shows a value set viaPATCH(search limit 17), confirming live REST reads. Save callsPATCH /config(confirmed at the API layer + the Spec 060 web-UI suite). QA report kept local per policy.Depends on #536 (merged).