feat(046): adaptive onboarding wizard with state-driven steps#433
Merged
Conversation
Deploying mcpproxy-docs with
|
| Latest commit: |
0d4f403
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://44f35901.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://046-local-first-onboarding.mcpproxy-docs.pages.dev |
|
Codecov Report❌ Patch coverage is 📢 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 25172546396 --repo smart-mcp-proxy/mcpproxy-go
|
This was referenced Apr 28, 2026
Adds a first-run onboarding wizard that adapts to the user's state. Two predicates drive which steps render — "any AI client connected to mcpproxy?" and "any upstream MCP server configured?". With both false the wizard shows two steps; with one false it shows just that one; with both true the dashboard loads directly. Skip on any step lands on the dashboard; once engaged, the wizard never auto-shows again. A "Run setup wizard" link in the dashboard re-runs it on demand. Backend reuses Spec 039's connect endpoint and the existing add-server flow; the wizard never duplicates either. Quarantine remains the trust boundary — the server step explains it plainly but does not change quarantine behaviour. ## Changes Backend (Go): - internal/storage/models.go + bbolt.go + manager.go: new OnboardingBucket and OnboardingState record (engaged, first-shown, per-step status); thread-safe Get/Save accessors. - internal/runtime/runtime.go + internal/server/server.go: pass-through wrappers to storage. - internal/connect/connect.go: GetConnectedCount() and GetConnectedIDs() helpers reusing the existing per-client adapter table. - internal/httpapi/onboarding.go (new): GET /api/v1/onboarding/state returns live predicates plus the persisted record plus a derived should_show_wizard flag; POST /api/v1/onboarding/mark updates per-step status, first-shown timestamp, and engagement. - internal/httpapi/server.go: ServerController interface gains GetOnboardingState / SaveOnboardingState; routes registered alongside /api/v1/connect. - Test mocks (security_test.go, contracts_test.go) updated. Frontend (Vue 3 + Pinia): - frontend/src/types/api.ts: OnboardingState, OnboardingStateResponse, OnboardingMarkRequest. - frontend/src/services/api.ts: getOnboardingState() and markOnboardingState(). - frontend/src/stores/onboarding.ts (new): Pinia store with derived visibleSteps driving adaptive rendering plus per-step mark helpers. - frontend/src/components/OnboardingWizard.vue (new): adaptive 1-2 step modal with progress indicator, per-step skip, and a quarantine explainer in the server step. Reuses the existing AddServerModal for server addition. - frontend/src/views/Dashboard.vue: auto-show on mount when should_show_wizard, plus a "Run setup wizard" link below "Connect Clients" for manual re-run. Spec: - specs/046-local-first-onboarding/spec.md plus checklist. OpenAPI: - oas/docs.go and oas/swagger.yaml regenerated with the new /onboarding endpoints. ## Testing - Storage / connect / httpapi unit tests pass. - Manual verification through Chrome browser automation across all four state combinations (none / clients-only / servers-only / both) with the dev backend on :18080. Auto-show, step advancement, skip, re-run, and engaged-suppression all confirmed. Funnel data (first-shown, engaged-at, per-step status) persisted in BBolt. ## What's deferred - US2 tier-2 client adapters (Antigravity, Zed, OpenCode, etc.) — purely additive to the existing adapter table; one-PR-per-adapter. - US3 heartbeat fields and Cloudflare D1 schema migration — backend signals are already exposed; just need to wire into HeartbeatPayload and migrate the D1 schema. Related #46
cd981ea to
4729cc1
Compare
…ame, activity panel Related #46 Reframes the first-run wizard as a persistent, idempotent setup surface driven by the activation funnel telemetry (SynapBus #27345, 78.2% → 11.7% cliff at IDE connect). Replaces the linear v1 flow with three idempotent tabs (Clients · Servers · Verify), a top-pinned sidebar entry with an animated badge, and a passive Verify tab that flips green automatically on the first successful MCP `initialize` round-trip — closing the loop on the cliff in-product. ## Changes Spec - specs/046-local-first-onboarding/spec.md: appended a "v2 — Wizard Surface Redesign" section. v1 text preserved verbatim. Backend (Go) - internal/httpapi/onboarding.go: extended /api/v1/onboarding/state with first_mcp_client_ever, mcp_clients_seen_ever, incomplete_tab_count. ShouldShowWizard semantics widened to cover Verify. - internal/httpapi/server.go + internal/server/server.go + internal/runtime/runtime.go: new GetActivationFirstMCPClient() reads Spec 044's existing FirstMCPClientEver / MCPClientsSeenEver from the ActivationStore. No new BBolt buckets, no new MCP hook. - internal/httpapi/import.go: ImportFromPathRequest gains skip_quarantine query param ("Import as active") and a rename map applied after parsing — so the wizard can disambiguate cross-source name collisions like "mcpproxy" appearing in both Claude Code and Claude Desktop. Frontend (Vue 3 + Pinia) - frontend/src/components/OnboardingWizard.vue: full rewrite as a 3-tab modal at min(960px, 90vw) × min(640px, 85vh). Tabs are bidirectionally clickable; per-tab idempotent state. - Clients tab: detected sort -> always-pinned trio (Claude Code / Codex / Gemini) -> "Show N more" collapse. Inline security expander. - Servers tab: sectioned checkbox list with indented server rows under each section header; per-section "select all" with proper indeterminate state; cross-source name collisions render an inline rename pill ("→ <renamed>"); sticky non-scrollable footer with selection count, conflict count, and two equal-width action buttons (Import & quarantine, Import as active). Compact toggles for Docker isolation and quarantine_enabled with inline Docker- availability warning. Educational note about post-hoc scanning. - Verify tab: passive, flips green on FirstMCPClientEver. Three sample prompts annotated with the built-in tool each one exercises. Recent Activity panel below shows the last 5 records with status badges and "View all in Activity Log" link. - frontend/src/components/SidebarNav.vue: top-pinned "Setup" entry above Dashboard for personal edition. - frontend/src/views/Dashboard.vue: removed the v1 "Run setup wizard" button. - frontend/src/stores/onboarding.ts + types/api.ts + services/api.ts: store gains firstMCPClientEver, mcpClientsSeenEver, incompleteTabCount computeds. importServersFromPath supports skip_quarantine + rename. OpenAPI - oas/swagger.yaml + oas/docs.go: ImportFromPathRequest gains rename. Verification - specs/046-local-first-onboarding/verification/: 7 Playwright-captured PNGs and a self-contained report.html (1.4 MB, base64-embedded screenshots). ## Testing - internal/httpapi unit + contract tests pass; mocks updated. - frontend vue-tsc clean. - Playwright sweep on a fresh data dir: all scenarios pass; out-of-band curl confirms rename produces mcpproxy_claude_code / mcpproxy_claude_desktop with quarantined=true.
Adds local browser-driven Playwright coverage for:
- engagement persistence (no auto-popup, sidebar reopens)
- select-all toggle off (footer state)
- per-section indeterminate state on partial selection
- "View all in Activity Log →" link navigation
- Docker isolation + quarantine toggle visual feedback
- skip-import flow (no servers added on Close)
Renders updated report.html with 14 scenarios + a "Local browser test
run" section noting the Docker/quarantine toggle persistence finding:
the wizard wraps the apply payload in `{config: …}` but the backend
expects the bare Config — UI flips locally but server-side persistence
falls back to best-effort. Dedicated PATCH endpoint works.
Related #46
Related #46 The wizard's `patchConfig` was wrapping the body in `{config: merged}`, but `/api/v1/config/apply` decodes the body directly into `config.Config`. Result: every toggle (require_mcp_auth, docker_isolation, quarantine_enabled) flipped the UI state but the server-side apply rejected the wrapped payload with a stale field-validation error ("tools_limit: must be between 1 and 1000"). Surfaced by the v2 verification subagent (scenarios 12, 13). Settings.vue calls `api.applyConfig(config)` with a bare config object — the wizard now matches that contract. Also surfaces the apply response's `success` flag so a server-side rejection produces a visible "Save failed" toast instead of silently swallowing the error. Verified end-to-end: setting quarantine_enabled=false + require_mcp_auth=true via the wizard now persists to disk and a fresh `GET /api/v1/config` reflects the new values.
…tion docs Related #46 Reworks the Servers tab security toggles per the latest UX feedback: - Renamed "Quarantine new tools" → "Quarantine new servers". - Pulled both toggles out of the scrollable list into a sticky non- scrollable footer panel framed as global settings, not per-import options. - Wrapped them in a collapsed-by-default <details> labeled "Runtime isolation and MCP server quarantine" with a "global settings — apply to every imported server" summary hint. - Each toggle is now a card with long-form security explanation, links to docs.mcpproxy.app/security/{docker-isolation,quarantine}, and (for Docker) a green "Docker detected" or warning "Docker not detected" badge with an inline Docker Desktop install hint. - Quarantine description leads with bold "Recommended." and "Important:" clauses calling out that the AI agent itself can register upstream servers via mcpproxy's built-in MCP tools. - Docker toggle disables when Docker isn't detected. - "Import & quarantine" disables when Quarantine new servers is off (with a hover hint). "Import as active" stays enabled — opting out is an explicit user choice. Companion docs: - specs/046-local-first-onboarding/verification/srv-*.png + appended "Servers tab — toggles overhaul" section in report.html (6 scenarios). - CLAUDE.md gains a "Verifying Web UI changes" section describing the Playwright + base64-embedded HTML report workflow plus gotchas.
Related #46 Per UX feedback: the "global settings — apply to every imported server" hint on the Servers-tab security panel summary was muted opacity-50 text and the wording suggested the toggles only affected the current import. Both toggles are actually backed by the persistent mcpproxy config — flipping them writes through to mcp_config.json and stays in effect forever. - Promote "Global settings" to a bold primary-color badge (badge-primary badge-sm font-semibold) so it reads at a glance. - Replace the right-side caption with "saved to your mcpproxy config" so the persistence story is explicit, not implied. - Caption hides on narrow viewports (badge alone is enough).
Related #46 The "Docker detected" / "Docker not detected" pills next to the Docker isolation title were redundant — the install hint already appears below the description when the daemon is missing, and the toggle's disabled state is the real signal. Same for the "Recommended" badge next to "Quarantine new servers" — the description already opens with bold "Recommended." which carries the weight. Removing both leaves the panel uncluttered: just the title row, description with bold-emphasised security context, and the docs link. The prominent "Global settings — saved to your mcpproxy config" header still sits top-right of the panel summary so users know they're editing persistent state. Verification spec updated to no longer assert the badge count.
4 tasks
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
Adds a first-run onboarding wizard that adapts to the user's state. Two predicates drive which steps render — any AI client connected to mcpproxy? and any upstream MCP server configured?. With both false the wizard shows two steps; with one false it shows just that one; with both true the dashboard loads directly. Skip on any step lands on the dashboard; once engaged, the wizard never auto-shows again. A "Run setup wizard" link in the dashboard re-runs it on demand.
Reuses Spec 039's connect endpoint and the existing add-server flow — never duplicates either. Quarantine remains the trust boundary; the server step explains it plainly but does not change quarantine behaviour.
Spec:
specs/046-local-first-onboarding/spec.md. This PR delivers US1 (adaptive wizard) end-to-end. US2 (tier-2 client adapters) and US3 (heartbeat funnel telemetry + D1 schema migration) are tracked as follow-up work; signals required by US3 are already exposed by this PR.Why now
Production telemetry over 1,491 unique installs (2026-03-23 → 2026-04-28) shows the dominant onboarding gap is the retention cliff (11.8% day-2 retention), not server addition (97.9% of installs already have servers via import). The wizard's high-leverage primary path is therefore connecting an AI client, with adding a server treated as a secondary step that explains quarantine rather than gating addition.
Backend
internal/storage/models.go+bbolt.go+manager.go— newOnboardingBucketandOnboardingStaterecord (engaged, first-shown timestamp, per-step status); thread-safe Get/Save accessors.internal/runtime/runtime.go+internal/server/server.go— pass-through wrappers to storage.internal/connect/connect.go—GetConnectedCount()/GetConnectedIDs()reusing Spec 039's adapter table.internal/httpapi/onboarding.go(new):GET /api/v1/onboarding/state→ live predicates (has_connected_client,has_configured_server,connected_client_count,connected_client_ids,configured_server_count) + persisted record + derivedshould_show_wizard.POST /api/v1/onboarding/mark→ updates per-step status, first-shown timestamp, engagement.internal/httpapi/server.go—ServerControllerinterface gainsGetOnboardingState/SaveOnboardingState; routes registered alongside/api/v1/connect.security_test.go,contracts_test.go) updated.Frontend
frontend/src/types/api.ts—OnboardingState,OnboardingStateResponse,OnboardingMarkRequest.frontend/src/services/api.ts—getOnboardingState()/markOnboardingState().frontend/src/stores/onboarding.ts(new) — Pinia store with derivedvisibleStepsand per-step mark helpers.frontend/src/components/OnboardingWizard.vue(new) — adaptive 1-2 step modal with progress indicator, per-step skip, quarantine explainer in the server step. Reuses the existingAddServerModalfor server addition.frontend/src/views/Dashboard.vue— auto-show on mount whenshould_show_wizard, "Run setup wizard" link for manual re-run.OpenAPI
oas/docs.goandoas/swagger.yamlregenerated with the new/onboardingendpoints.Test plan
Out of scope (follow-ups)
connected_client_count,connected_client_ids,wizard_funnel_state) + Cloudflare D1 schema migration + website/telemetrypage docs. Backend signals are already exposed; next PR wires them intoHeartbeatPayload.Related #46