Generated — do not edit by hand. This file is rendered from
roadmap.yamlbyscripts/gen-roadmap.py. Editroadmap.yamland re-run the generator.
The roadmap models cross-spec epics → tasks with a dependency DAG, execution status, priority, and links — the things a per-spec tasks.md checkbox list cannot express. Per-spec checkbox progress is recomputed live from each specs/<NNN>/tasks.md.
roadmap.yaml holds the working set (todo · in-progress · in-review · blocked · parked). Cold shipped epics are swept into roadmap.archive.yaml and surface in the Shipped table below, so the working file stays small while provenance survives. A depends_on: edge into the archive is satisfied by definition.
python3 scripts/gen-roadmap.py # writes ROADMAP.md
scripts/gen-roadmap # convenience wrapper (same thing)
python3 scripts/gen-roadmap.py --check # CI canary: fail if ROADMAP.md is stale
python3 scripts/gen-roadmap.py --check-github # cross-check statuses vs live GitHub PR state,
# spec links, depends_on ids, and status sanity
# (add --strict to fail on warnings; needs gh)
python3 scripts/gen-roadmap.py --archive --dry-run # preview the cold-done sweep
python3 scripts/gen-roadmap.py --archive # sweep into roadmap.archive.yaml + regenerate- epics[] — each has
id(stable slug, DAG node),title,status(todo·in_progress·in_review·blocked·done),priority(P0–P3),depends_on: [ids](DAG edges, prerequisite→dependent), optionalparked: true, and linksspec:/pr:/mcp:(external MCP-xxxx). - epics[].tasks[] — child tasks with the same fields; their
depends_onmay reference sibling tasks or other epics. - See the header comment in
roadmap.yamlfor the full field reference.
The cross-epic dependency graph — one node per epic, edges point prerequisite → dependent. Task-level detail lives in the collapsible sections below, and dependency-free epics are listed under the graph rather than drawn as disconnected boxes, so this stays legible at default zoom. Node colour = status: 🟢 done · 🔵 in-progress · 🟡 in-review · 🔴 blocked · ⚪ todo · ⚫ parked.
graph LR
sandbox_isolation["Non-Docker sandbox isolation (Landlock)"]
scanner_v2["Spec 076 deterministic offline tool-sca…"]
ux_audit["Web UI + macOS app UX audit"]
action_log_transparency["Action log / transparency — info at a g…"]
analytics_dashboard["Analytics dashboard as default page"]
scanner_simplification["Scanner simplification (deterministic d…"]
tpa_db["tpa-db: versioned TPA signature databas…"]
remote_access_tunnel["Remote access tunnel (feature-flagged M…"]
schema_deferred["Deferred-schema serialization for the d…"]
agent_scope_hardening["Agent-token scope hardening: every MCP…"]
auto_routing_mode["Auto routing mode: budget-fitted tool s…"]
token_bench["Token-efficiency benchmark: measured sa…"]
tool_graph["Tool co-occurrence graph (experimental,…"]
telemetry_identity["Telemetry identity & data quality (mach…"]
telemetry_v7_churn["Telemetry v7: honest funnel + churn ins…"]
profiles_v3["Spec 108 profiles v3: scoped profiles,…"]
upstream_resilience["Spec 113 upstream resilience: OAuth ref…"]
pending_call_outcome["Spec 114 typed pending-call outcome + c…"]
mcp_credential_lifecycle["Spec 115 admin MCP credentials tool: cl…"]
config_commit_consistency["Spec 116 config commit consistency: one…"]
review_bound_approvals["Spec 117 review-bound approvals: durabl…"]
quarantine_approval_pilot["Quarantine/approval testing pilot: inde…"]
scanner_v2 --> sandbox_isolation
ux_audit --> action_log_transparency
ux_audit --> analytics_dashboard
scanner_v2 --> scanner_simplification
scanner_simplification --> tpa_db
tpa_db --> remote_access_tunnel
ux_audit --> remote_access_tunnel
analytics_dashboard --> remote_access_tunnel
schema_deferred --> agent_scope_hardening
agent_scope_hardening --> auto_routing_mode
schema_deferred --> auto_routing_mode
token_bench --> auto_routing_mode
schema_deferred --> token_bench
analytics_dashboard --> tool_graph
telemetry_identity --> telemetry_v7_churn
upstream_resilience --> pending_call_outcome
profiles_v3 --> mcp_credential_lifecycle
config_commit_consistency --> review_bound_approvals
review_bound_approvals --> quarantine_approval_pilot
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef in_progress fill:#1f6feb,stroke:#0b3d91,color:#ffffff;
classDef in_review fill:#9a6700,stroke:#5c3d00,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class sandbox_isolation,scanner_v2,analytics_dashboard,scanner_simplification,schema_deferred,agent_scope_hardening,upstream_resilience,mcp_credential_lifecycle,config_commit_consistency,review_bound_approvals,quarantine_approval_pilot done;
class ux_audit,action_log_transparency,tpa_db,token_bench,telemetry_identity,telemetry_v7_churn,profiles_v3 in_progress;
class pending_call_outcome in_review;
class remote_access_tunnel,auto_routing_mode,tool_graph todo;
Independent epics (16) — no cross-epic prerequisites; each stands alone:
- 🔵 Release qualification gate (auto-QA matrix blocks the tag) — In progress · P0
- 🔵 MCP protocol upgrade to 2026-07-28 revision — In progress · P1
- 🔵 Spec 109 navigation, scope filters and cross-surface UX consistency — In progress · P1
- 🔵 Planning/docs truth automation — In progress · P2
- 🔵 Discovery-quality eval harness (Spec 065 second half) — In progress · P3
- ⚪ Windows native tray app — Todo · P2
- ⚫ Server marketplace — Todo · P3 · parked
- ⚫ Audit SIEM integration — Todo · P3 · parked
- ⚫ Paid-tier MVP (billing / seats / license) — Todo · P3 · parked
- ⚫ SDK v1 migration — Todo · P3 · parked
- ⚪ Security gateway Tracks C/D (per-arg least-privilege + signature provenance) — Todo · P3
- 🟢 Upgrade awareness & guided update — Done · P0
- 🟢 Connect step trust: preview, visible backup, one-click undo — Done · P0
- 🟢 Registries — easier search + add-server — Done · P1
- 🟢 Tray↔core decoupling: socket/REST API only, no config-file reads — Done · P2
- 🟢 Spec 107 server edition SSO front door hardened for real IdPs — Done · P2
Each epic's child tasks, their internal dependency graph, and tracker/PR links — collapsed by default, expand the ones you care about. Full metadata (priority, spec progress) is in the Epics table below.
🔵 Web UI + macOS app UX audit — In progress · P0
End-to-end UX pass across Web UI and the macOS tray app; the umbrella for the polish push. (No spec yet — 064 is the unrelated agent-fleet glass-cockpit spec.) 2026-08-29 truth-sync: both sweeps and every finding they raised SHIPPED in August (this file had them at todo). Audits: docs/qa/ux-audit-webui-2026-08.md (36 findings) and docs/qa/ux-audit-macos-tray-2026-08.md (16 findings); both carry a Resolution section mapping finding -> PR. What is left is regression-proofing, not findings.
graph LR
ux_audit_webui_sweep["Web UI heuristic + Playwright UX sweep"]
ux_audit_macos_sweep["macOS tray app UX sweep (settings parity, flo…"]
ux_audit_webui_fixes["Close the 36 Web UI findings"]
ux_audit_macos_fixes["Close the 16 macOS tray findings"]
ux_audit_recheck_defects["Five new defects found while re-checking the…"]
ux_audit_sweep_regressions["Fold the audit's regression assertions into t…"]
ux_audit_sweep_found_defects["Three defects the completed sweep found on ma…"]
ux_audit_tray_live_verify["Verify the 16 tray fixes on a running tray"]
ux_audit_webui_sweep --> ux_audit_webui_fixes
ux_audit_macos_sweep --> ux_audit_macos_fixes
ux_audit_webui_fixes --> ux_audit_recheck_defects
ux_audit_webui_fixes --> ux_audit_sweep_regressions
ux_audit_sweep_regressions --> ux_audit_sweep_found_defects
ux_audit_macos_fixes --> ux_audit_tray_live_verify
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class ux_audit_webui_sweep,ux_audit_macos_sweep,ux_audit_webui_fixes,ux_audit_macos_fixes,ux_audit_recheck_defects,ux_audit_sweep_regressions,ux_audit_sweep_found_defects done;
class ux_audit_tray_live_verify todo;
| Task | Status | Refs |
|---|---|---|
| Web UI heuristic + Playwright UX sweep | 🟢 Done | #1046 |
| macOS tray app UX sweep (settings parity, flows) | 🟢 Done | #1043 |
| Close the 36 Web UI findings | 🟢 Done | #1044 #1048 #1049 #1050 #1051 #1052 #1053 #1054 |
| Close the 16 macOS tray findings | 🟢 Done | #1055 #1056 |
| Five new defects found while re-checking the Web UI audit on v0.61.0 | 🟢 Done | #1062 #1072 #1077 |
| Fold the audit's regression assertions into the committed sweep (e2e/web-ui-sweep) | 🟢 Done | — |
| Three defects the completed sweep found on main | 🟢 Done | — |
| Verify the 16 tray fixes on a running tray | ⚪ Todo | — |
🔵 Release qualification gate (auto-QA matrix blocks the tag) — In progress · P0
Attacks the return cliff (48% of installs are one-and-done; day-1 return 31% — corrected 2026-07-10, identity-deduped; the earlier '17.7% day-2' figure was un-deduped anonymous_id churn) and the one conceded competitor advantage: stability. No release tag until the surface x server-type matrix (MCP/REST/CLI/Web UI x stdio/http/sse/docker/oauth) plus invariants (activity-log/token counters move, quarantine flow, reconnect survival, in-place upgrade) pass automatically; macOS app smoke is advisory until promoted (3 consecutive passes, spec 081 US4). Assembles existing assets: test-api-e2e.sh, Playwright sweep, scan-eval gate, mcpproxy-ui-test.
Spec: 081-release-qa-gate
graph LR
release_qa_gate_matrix["T1: tag-blocking release-gate workflow: serve…"]
release_qa_gate_playwright["T2: wire the Playwright Web UI sweep into the…"]
release_qa_gate_macos["T3: macOS app smoke on a macos runner, adviso…"]
release_qa_gate_consistency["T4: surface-state consistency check (tray/Web…"]
release_qa_gate_matrix --> release_qa_gate_playwright
release_qa_gate_matrix --> release_qa_gate_macos
release_qa_gate_matrix --> release_qa_gate_consistency
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef in_review fill:#9a6700,stroke:#5c3d00,color:#ffffff;
class release_qa_gate_matrix,release_qa_gate_playwright,release_qa_gate_consistency done;
class release_qa_gate_macos in_review;
| Task | Status | Refs |
|---|---|---|
| T1: tag-blocking release-gate workflow: server-type matrix (stdio/http/sse/docker/oauth) + invariants (activity-log/request-id, token+telemetry counters, quarantine flow, reconnect, upgrade-in-place), publish jobs gated on the verdict, scan-eval unconditional on tags | 🟢 Done | #819 |
| T2: wire the Playwright Web UI sweep into the gate (currently manual-trigger only) | 🟢 Done | #1030 |
| T3: macOS app smoke on a macos runner, advisory until 3 consecutive passes (today zero CI automation for the tray app) | 🟡 In review | #1669 |
| T4: surface-state consistency check (tray/Web UI/CLI agree with core on server states) | 🟢 Done | #1655 |
🔵 Action log / transparency — info at a glance — In progress · P1
Surface the most important activity/security/connection signals at a glance; reduce digging. Vision pillar 'feel control → transparency' — the activity log is a headline feature, polish it and bring it to the tray menu. Builds on the shipped activity-log backend + retention (spec 024, 95% shipped — this epic is the at-a-glance UX on top, not the backend, so 024 is not the progress driver).
graph LR
sessions_web_ui["Sessions in the Web UI: meaningful session na…"]
action_log_glance_view["At-a-glance action log view (top signals, hea…"]
action_log_tray_menu["Activity in the tray menu (recent tool calls…"]
tray_menu_open_telemetry["tray_menu_opened counter: Swift menuWillOpen…"]
action_log_retention_tie_in["Tie activity retention/size into the glance v…"]
activity_storage_bounds["Bound every activity-adjacent store: response…"]
action_log_glance_view --> action_log_tray_menu
action_log_glance_view --> action_log_retention_tie_in
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class sessions_web_ui,activity_storage_bounds done;
class action_log_glance_view,action_log_tray_menu,tray_menu_open_telemetry,action_log_retention_tie_in todo;
| Task | Status | Refs |
|---|---|---|
| Sessions in the Web UI: meaningful session names in the Activity Log filter + the existing /sessions page linked in the sidebar | 🟢 Done | — |
| At-a-glance action log view (top signals, health) | ⚪ Todo | — |
| Activity in the tray menu (recent tool calls + security events, jump to full log) | ⚪ Todo | — |
| tray_menu_opened counter: Swift menuWillOpen (MCPProxyApp.swift:192) -> lightweight POST /api/v1/telemetry/tray-menu-opened -> registry counter -> heartbeat tray_menu_opened_24h | ⚪ Todo | — |
| Tie activity retention/size into the glance view | ⚪ Todo | — |
| Bound every activity-adjacent store: response truncation on the write path (#1173/#1174), per-server tool_calls buckets (#1176), omitempty zero-erasure (#1175) | 🟢 Done | #1174 #1214 |
🔵 tpa-db: versioned TPA signature database for the offline scanner — In progress · P1
Vision pillar 'feel protected': the deterministic detect engine (Spec 076/077) ships with built-in checks but no updatable knowledge of in-the-wild Tool Poisoning Attacks. Build a versioned, offline-first signature/pattern database (known TPA campaigns, malicious phrase corpora, IoC hashes) that the engine consumes — bundled with the binary, refreshable out-of-band, community-contributable, and guarded by the existing scan-eval recall/FP CI gate. SPEC STAGE: specs/101-tpa-db MERGED as PR #1028 on 2026-08-27 (kept in this note, not in pr:, because pr: is implementation evidence and a docs(specs) merge is not that); 2026-10-20: US1 (tpa-db-format: signed four-key Ed25519 sidecar, verify-before-parse loader, per-authority anti-downgrade state, full-digest rollback, coverage degrade) shipped as #1701; US2 corpus in a sibling session (#1702, open); 2026-10-22: US3 (tpa-db-refresh, implements Spec 087 US1+US2: daily file+optional signed fetch refresh, activation self-check, freshness surfaces, cached re-protection sweep) shipped as #1720. Epic stays in_progress until the corpus (US2) lands.
Spec: 101-tpa-db
graph LR
tpa_db_format["Signature DB format + loader (versioned, sign…"]
tpa_db_corpus["Seed corpus: catalog known public TPA campaig…"]
tpa_db_refresh["Out-of-band refresh (offline-friendly: manual…"]
tpa_db_format --> tpa_db_corpus
tpa_db_format --> tpa_db_refresh
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class tpa_db_format,tpa_db_refresh done;
class tpa_db_corpus todo;
| Task | Status | Refs |
|---|---|---|
| Signature DB format + loader (versioned, signed, bundled default) | 🟢 Done | #1701 |
| Seed corpus: catalog known public TPA campaigns/patterns into the DB | ⚪ Todo | — |
| Out-of-band refresh (offline-friendly: manual file drop + optional fetch), eval-gated | 🟢 Done | #1720 |
🔵 Token-efficiency benchmark: measured savings, published results — In progress · P1
Measure the real token cost of every routing/savings mode combination — baseline, compact signatures (spec 085), deferred schemas (spec 102), optimistic calling via self-healing pre-dispatch validation, code_execution (spec 096) and stored scripts (spec 097) — on replayed real sessions and on public benchmarks, then publish the results on mcpproxy.app/blog. Every savings number we quote today is an estimate; this turns them into reproducible measurements. Sequenced after schema-deferred so the newest mode is in the matrix. Spec 103 landed 2026-08-31 (#1137 spec+plan, #1139 tasks) after 13 cross-model review rounds; three of its findings changed the design rather than the wording: a recording carries no prompt/conversation/completion oracle so replay CANNOT show agent behaviour (US1 deterministic cost vs US2 live loop are now separate stories); replay needs a FLEET INPUT because the export has no fleet snapshot; and bodies-off yields menu costs plus one cross-mode delta, never an absolute workload cost. The matrix is 5 distinct behaviours, not a 3x2x2 product.
Spec: 103-token-bench
graph LR
token_bench_harness["Replay harness: activity-log sessions re-run…"]
token_bench_public["Run public suites locally (τ-bench / BFCL / M…"]
token_bench_blog["Publish results + methodology on mcpproxy.app…"]
token_bench_telemetry["Heartbeat v10: per-tool_response_mode token c…"]
token_bench_harness --> token_bench_public
token_bench_public --> token_bench_blog
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class token_bench_harness done;
class token_bench_public,token_bench_blog,token_bench_telemetry todo;
| Task | Status | Refs |
|---|---|---|
| Replay harness: activity-log sessions re-run under each mode combo; tokens per completed task + first-call success + retries | 🟢 Done | #1141 #1147 #1151 #1153 #1160 |
| Run public suites locally (τ-bench / BFCL / MCP-specific — final list verified by a research pass) and record reproducible results | ⚪ Todo | — |
| Publish results + methodology on mcpproxy.app/blog | ⚪ Todo | — |
| Heartbeat v10: per-tool_response_mode token counters for real-world cohort validation | ⚪ Todo | — |
🔵 Telemetry identity & data quality (machine_id + CI-filter hardening) — In progress · P1
2026-07-11 source audit: the CLIENT half is DONE and RELEASED — the old framing ('add a hashed machine_id (schema v6)') is stale. machine_id (HMAC-SHA256 of the OS machine id, internal/telemetry/machine_id.go) is emitted unconditionally in every heartbeat (telemetry.go:789; telemetry is opt-out) and shipped in v0.47.0; the client schema is already v7, a version past the v6 this note described; CI is filtered client-side by disabling telemetry outright (env_overrides.go). Worker verified live in prod 2026-07-07 (machine_id 100% populated). The audit also found that the 79%-unknown launch_source was a CLIENT bug misfiled to mcpproxy-dash — a dashboard cannot display a value the client is incapable of sending. That is now fixed (see telemetry-launchsource-tray). Remaining: dashboard consumption (mcpproxy-dash) + snapshot-cron alerting.
graph LR
telemetry_machineid_client["Hashed machine_id in heartbeat (schema v6)"]
telemetry_machineid_worker["Worker migration: machine_id column + extract…"]
telemetry_launchsource_tray["Emit launch_source=tray — the 'tray' value wa…"]
telemetry_machineid_dash["Dashboard identityExpr prefers machine_id; ex…"]
telemetry_snapshot_alerting["Alerting on external-downloads snapshot cron…"]
telemetry_machineid_client --> telemetry_machineid_worker
telemetry_machineid_worker --> telemetry_machineid_dash
telemetry_launchsource_tray --> telemetry_machineid_dash
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class telemetry_machineid_client,telemetry_machineid_worker,telemetry_launchsource_tray done;
class telemetry_machineid_dash,telemetry_snapshot_alerting todo;
| Task | Status | Refs |
|---|---|---|
| Hashed machine_id in heartbeat (schema v6) | 🟢 Done | #796 |
| Worker migration: machine_id column + extraction (repo mcpproxy-telemetry) | 🟢 Done | mcpproxy-telemetry#3 |
| Emit launch_source=tray — the 'tray' value was UNREACHABLE in the client, and that (not the dashboard) was the 79%-unknown root cause | 🟢 Done | — |
| Dashboard identityExpr prefers machine_id; exclude %-dev versions from human cohort (repo mcpproxy-dash) | ⚪ Todo | — |
| Alerting on external-downloads snapshot cron (34-day outage went unnoticed) | ⚪ Todo | — |
🔵 Telemetry v7: honest funnel + churn instrumentation — In progress · P1
2026-07-06 recheck DEBUNKED the 72.4% connect-skip story: genuine never-connected skip = 0% (wizard dismiss stamped 'skipped' on users who connected via ConnectModal/CLI/manual config). 2026-07-10 recheck debunked the OTHER two spec-080 headline metrics as well: 'day-2 return 17.7%' was un-deduped anonymous_id churn (true, identity-deduped: one-and-done 48%, day-1 return 31%, day-7 16.6% — matches dashboard); '42% retrieve_tools -> 16% real call' was lifetime-flag vs windowed-counter asymmetry (true conversion ~90%; missing piece is a first_real_tool_call_ever activation flag). Real cliff = 48% one-and-done. 2026-07-11 source audit + fix: ALL of spec 080 is shipped and released in v0.47.0 (#813) — T1 wizard completed_external, T2 funnel fields, T3 pre-churn snapshot, US4 schema v7. The previous note claimed 'only cross-repo churn analytics (T4) remains'; that was WRONG — first_real_tool_call_ever had ZERO occurrences in Go code and was in-repo CLIENT work. It is now implemented, so the retrieve->call funnel is finally measurable lifetime-vs-lifetime. P0->P1: only cross-repo T4 now remains.
Spec: 080-telemetry-v7-churn
graph LR
telemetry_v7_wizard_fix["T1: wizard metric fix - on dismiss record con…"]
telemetry_v7_funnel_fields["T2: funnel observability fields (wizard_shown…"]
telemetry_v7_prechurn_snapshot["T3: pre-churn snapshot (previous_shutdown cle…"]
telemetry_v7_realcall_flag["first_real_tool_call_ever activation flag (sy…"]
telemetry_v7_churn_events["T4: cross-repo churn_events materialization +…"]
telemetry_v7_wizard_fix --> telemetry_v7_churn_events
telemetry_v7_funnel_fields --> telemetry_v7_churn_events
telemetry_v7_prechurn_snapshot --> telemetry_v7_churn_events
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class telemetry_v7_wizard_fix,telemetry_v7_funnel_fields,telemetry_v7_prechurn_snapshot,telemetry_v7_realcall_flag done;
class telemetry_v7_churn_events todo;
| Task | Status | Refs |
|---|---|---|
| T1: wizard metric fix - on dismiss record connect step as completed_external (not skipped) when the user already connected via another path | 🟢 Done | #813 |
| T2: funnel observability fields (wizard_shown, web_ui_opened counter, days_since_install, active_days_30d) | 🟢 Done | #813 |
| T3: pre-churn snapshot (previous_shutdown clean|crash via BBolt flag, last_error_code) so the final heartbeat doubles as cause-of-death | 🟢 Done | #813 |
| first_real_tool_call_ever activation flag (symmetric to first_retrieve_tools_call_ever) so the retrieve->call funnel step is measurable lifetime-vs-lifetime | 🟢 Done | — |
| T4: cross-repo churn_events materialization + dash Churn page with H1-H4 hypothesis signatures (repos mcpproxy-telemetry / mcpproxy-dash; tracked here for DAG visibility, out of scope of spec 080) | ⚪ Todo | — |
🔵 MCP protocol upgrade to 2026-07-28 revision — In progress · P1
STABLE GATE CLEARED 2026-09-02: mark3labs/mcp-go v1.0.0 (stable) released; go.mod still pins v0.57.0. Raised P3->P1 on the 2026-09-02 issue-prioritization pass — PLAN LANDED 2026-09-03 (research.md, plan.md, data-model.md, contracts/, quickstart.md) from a verified probe of mcp-go v1.0.0 STABLE. Production code compiles unchanged on both editions (only test symbol NewTestStreamableHTTPServer moved to server/servertest, 32 sites); the FULL internal/server suite under v1.0.0 fails on exactly the 2 known profile tests and nothing else. The bump ALONE flips the UPSTREAM-facing default to 2026-07-28 (connection_lifecycle.go:19 uses LATEST_PROTOCOL_VERSION), so the plan pins BOTH directions in the bump PR. Spec-057 conflict DECIDED: Option A (URL path = request-carried identity) plus 2 mandatory grafts (era-gate resolver tier 3, because stdio SessionID is the constant "stdio"; list-only resolver, which also fixes a PRE-EXISTING FR-012 violation on prompts/list). MRTR FR-015/016 cannot be met through the v1.0.0 public client API (CallTool hard-wires the round-trip loop; single-shot entries unexported) -> plan proposes detect-and-frame + a spec amendment, NEEDS MAINTAINER RATIFICATION before implementation. FR-018/SC-005 vacuous (no resource proxying). New security item R1: mcp-go inflightKey is ":" for every modern request, so one client can cancel another's call; masked by the FR-028 pin. Spec-032 hash drift measured: real mechanism, 0 of 1096 real tools affected, fix is a NormalizeJSON ref canonicalisation + guard test. Next step is speckit.tasks after ratification (tracker #532). Earlier: UNBLOCKED 2026-08-12: the mcp-go gate cleared — v1.0.0-beta.1 (mark3labs/mcp-go#951) ships full 2026-07-28 support with per-request era detection (the pin was v0.55.x, topping out at 2025-11-25). Spec 058 revision MERGED as PR #1033 on 2026-08-27 (kept in this note, not in pr:, because pr: is implementation evidence and a docs(specs) merge is not that): final error-code renumbering (-32020/-32021/-32022), FR-001..006 / FR-014..016 recast as adopt-and-verify, FR-028 legacy-only transport pin as the safe merge state, plus Risks & Watch Items. The cross-spec conflict named there (FR-012 vs shipped Spec 057) is the one RESOLVED above as Option A. 028 agent-token scoping is already compatible (header-carried). Tracker: #532.
Spec: 058-mcp-2026-upgrade
🔵 Spec 108 profiles v3: scoped profiles, client binding, scope-aware observability — In progress · P1
Shipped 2026-09-26..10-05 as PRs 108-a..l. Left open: T126 live run of the six audit acceptance checks on one isolated instance across all surfaces (task below), and issue #1449 (macOS review follow-ups).
Spec: 108-profiles-v3
graph LR
profiles_v3_impl["PRs 108-a..l: policy fields, enforcement, bin…"]
profiles_v3_live_acceptance["Live run of the six Spec 108 audit acceptance…"]
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class profiles_v3_impl done;
class profiles_v3_live_acceptance todo;
| Task | Status | Refs |
|---|---|---|
| PRs 108-a..l: policy fields, enforcement, bindings, CLI, MCP admin tool, Web UI, macOS, parity docs | 🟢 Done | #1380 #1411 #1430 #1436 #1441 #1442 #1443 #1444 #1448 #1456 #1500 |
| Live run of the six Spec 108 audit acceptance checks on one isolated instance (Web UI, macOS, CLI, MCP) — tasks.md T126 | ⚪ Todo | — |
🔵 Spec 109 navigation, scope filters and cross-surface UX consistency — In progress · P1
Shipped 2026-09-26..10-02 as PRs 109-a..m. Left open: T150 live run of every user story's independent test across surfaces (task below).
Spec: 109-ux-navigation-consistency
graph LR
ux_navigation_impl["PRs 109-a..m: attention list, review queue, c…"]
ux_navigation_live_acceptance["Live run of every Spec 109 user story's indep…"]
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class ux_navigation_impl done;
class ux_navigation_live_acceptance todo;
| Task | Status | Refs |
|---|---|---|
| PRs 109-a..m: attention list, review queue, catalog-first Add, grouped navigation, parity docs | 🟢 Done | #1376 #1377 #1382 #1399 #1400 #1409 #1412 #1424 #1425 #1427 #1428 #1461 |
| Live run of every Spec 109 user story's independent test on one isolated instance — tasks.md T150 | ⚪ Todo | — |
🔵 Planning/docs truth automation — In progress · P2
Automate the consistency checks this very audit had to do by hand: roadmap vs GitHub PR state, tasks.md updates on implementation PRs, volatile CLAUDE.md/README facts, and quickstart contract tests.
graph LR
hygiene_roadmap_github_check["gen-roadmap --check-github: cross-check roadm…"]
hygiene_tasks_reconcile["CI rule: PR touching specs/<id> implementatio…"]
hygiene_spec_evidence_check["scripts/check-spec-evidence.py: deterministic…"]
hygiene_spec_gardener["Weekly cloud routine: LLM judges only the res…"]
hygiene_docs_facts["Generate volatile CLAUDE.md/README facts (Go…"]
hygiene_quickstart_contract["Run top quickstart.md scenario per spec as co…"]
hygiene_spec_evidence_check --> hygiene_spec_gardener
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class hygiene_roadmap_github_check,hygiene_spec_evidence_check,hygiene_spec_gardener done;
class hygiene_tasks_reconcile,hygiene_docs_facts,hygiene_quickstart_contract todo;
| Task | Status | Refs |
|---|---|---|
| gen-roadmap --check-github: cross-check roadmap.yaml statuses vs gh PR state + dangling spec links | 🟢 Done | #800 |
| CI rule: PR touching specs/ implementation paths must update tasks.md | ⚪ Todo | — |
| scripts/check-spec-evidence.py: deterministic check that every TICKED task cites code that exists | 🟢 Done | — |
| Weekly cloud routine: LLM judges only the residue the evidence-check cannot decide, opens/updates one propose-only PR | 🟢 Done | #824 #870 #999 #842 |
| Generate volatile CLAUDE.md/README facts (Go version, built-in tool list, sample config) from code with --check | ⚪ Todo | — |
| Run top quickstart.md scenario per spec as contract test in test-api-e2e.sh | ⚪ Todo | — |
🔵 Discovery-quality eval harness (Spec 065 second half) — In progress · P3
IN PROGRESS — 2026-08-31 audit, corrected on cross-model review: both halves of the HARNESS shipped INDEPENDENTLY (not via token-bench-harness), but spec 065 is NOT fully met, so this is not done. FR-009 and SC-005 require CI to FAIL on a discovery regression beyond tolerance; the retrieval-D1 job is continue-on-error on pull requests, so on the PR path it does not fail — eval.yml itself records the promotion to PR-blocking as still open (MCP-742). A second, weaker tension to adjudicate rather than assume: CN-002 asks that scoring never run against a live drifting corpus, and D1 does boot a live mcpproxy serving 7 reference servers — but #931 pinned all seven upstreams to freeze-era versions and the job gates on the exact corpus ID set, so the corpus is reproducible in practice. Decide whether that satisfies CN-002 or whether a committed snapshot is required. Remaining work is therefore the gating promotion, not the harness. The earlier 'superseded / folded into token-bench-harness' framing was wrong on its own terms: token-bench-harness is still unbuilt, so nothing could have been folded into it. Security recall/FP half: cmd/scan-eval, backing the Spec 076/077 gate in eval.yml. Discovery-quality half: the eval.yml retrieval-d1 job boots mcpproxy and scores retrieval_golden_v1.json against a committed baseline at --tolerance 0.05 via the pinned external mcp-eval repo — note continue-on-error is scoped to github.event_name == 'pull_request', so the job is REPORT-ONLY on PRs (npx/uvx fetch flake) and BLOCKING on both the nightly schedule and manual workflow_dispatch runs. Promoting it to PR-blocking after a green soak is still open (MCP-742). NB the workflow's own inline comment says 'blocking on the nightly schedule' and omits workflow_dispatch. A second in-repo implementation lives in bench/: metrics.go defines RecallAtK/NDCGAtK, and the SC-003 recall@5 = 0.68 +/- 0.05 parity gate through the production Bleve index is asserted in bench/armindex_test.go (armindex.go supplies the production index wiring, not the assertion). Kept as a stable depends_on target; do not build a standalone harness.
Spec: 065-evaluation-foundation
graph LR
discovery_eval_pr_blocking["Promote retrieval-D1 from report-only to PR-b…<br/>MCP-742"]
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class discovery_eval_pr_blocking todo;
| Task | Status | Refs |
|---|---|---|
| Promote retrieval-D1 from report-only to PR-blocking (spec 065 FR-009/SC-005), and adjudicate the CN-002 frozen-corpus question | ⚪ Todo | MCP-742 |
🟡 Spec 114 typed pending-call outcome + call correlation for long-running stdio tool calls — In review · P2
Spec-only PR #1536 open; implementation follows the spec review. Tracks issue #1321 (follow-up to #1317).
PR: #1536
⚪ Auto routing mode: budget-fitted tool surface per session (spec 104) — Todo · P1
routing_mode: auto measures, per session and on the catalog that session will actually see, the three candidate surfaces (direct full, direct deferred, retrieve compact — the Spec 103 bench cell names) with the real tokenizer and serves the richest rung under a 12,000-token budget, so the small-fleet developer gets the whole menu with schemas and the 1,000-tool fleet stays on search — the current default is strictly worse than no proxy for the first population. Decision record (rung, three measurements, budget, counts, scope label, reason, time) surfaces in the routing API, doctor, tray, Web UI and telemetry; hysteresis so a 1% catalog change never flips a live session. Spec: 14 astra rounds, ready-for-plan 2026-09-07; its fixed-surface corrections were split out as Spec 105 (FR-016 states the invariant 105 makes true), hence the hard dependency. P1 = US1-4 (rung selection, session stability, scoped measurement, routing API + doctor); P2 = US5-6 (hysteresis reporting, tray/Web UI rendering, telemetry).
Spec: 104-auto-routing-mode
graph LR
auto_routing_p1["P1 (US1-4): per-session measurement of the th…"]
auto_routing_p2["P2 (US5-6): hysteresis reporting on catalog c…"]
auto_routing_p1 --> auto_routing_p2
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class auto_routing_p1,auto_routing_p2 todo;
| Task | Status | Refs |
|---|---|---|
| P1 (US1-4): per-session measurement of the three candidates on the scoped catalog, rung selection under the budget, stable sessions, decision record in routing API + doctor | ⚪ Todo | — |
| P2 (US5-6): hysteresis reporting on catalog change, tray + Web UI rendering of the decision, telemetry counters | ⚪ Todo | — |
⚪ Windows native tray app — Todo · P2 · MCP-43
No spec: link — this epic is the native TRAY app; specs/002-windows-installer is the unrelated INSTALLER spec (35/60) and its badge said nothing about tray progress (wrong link removed 2026-07-10). Option C: WebView2 window reusing shipped Web UI. Most exit criteria already ship; gaps = native window, toasts, profile submenu, Win11 smoke. Telemetry: Windows = ~23% of GitHub downloads but only ~4% of active installs (downloads→actives ~12:1 vs macOS ~4:1) — gate WebView2 work on finding the funnel break first. 2026-08-31 audit: reset from in_review to todo. Scoped precisely: Windows tray support DID ship in 2025 via the cross-platform Go/systray build (#74, merged 2025-10-23, cmd/mcpproxy-tray/ + internal/tray under GOOS=windows) — what this epic tracks is the NATIVE WebView2 replacement, and for that no PR is open or merged and native/windows/ holds only a README placeholder with no WebView2 code anywhere in the tree. So 'in review' had no PR to point at.
graph LR
windows_tray_funnel_qa["Windows first-run QA pass (downloads→actives…"]
windows_tray_window["WebView2 native window + profile submenu<br/>MCP-43"]
windows_tray_funnel_qa --> windows_tray_window
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class windows_tray_funnel_qa,windows_tray_window todo;
| Task | Status | Refs |
|---|---|---|
| Windows first-run QA pass (downloads→actives 12:1 vs macOS 4:1 — find the funnel break before WebView2 work) | ⚪ Todo | — |
| WebView2 native window + profile submenu | ⚪ Todo | MCP-43 |
⚪ Remote access tunnel (feature-flagged MVP, spec 089) — Todo · P2
One-button Web UI exposure of /mcp via external tunnel binary (cloudflared quick tunnel first) so Claude custom connectors (all tiers incl. Free, syncs to iOS/Android) can reach local MCP servers (e.g. Obsidian) — behind a feature flag, off by default, mandatory OAuth 2.1+PKCE+DCR gate, per-server exposure allowlist, remote-origin activity logging. Research: docs/research/remote-access-tunnel-research-2026-07-29.html (25/25 claims verified; niche unoccupied — Docker MCP Gateway lacks it). Sequenced after tpa-db (+ shipped scanner work 086-088), macOS tray redesign (ux-audit) and analytics-dashboard per owner decision 2026-07-29. No hosted relay/payments in MVP.
Spec: 089-remote-access-tunnel
graph LR
tunnel_oauth_gate["OAuth 2.1 authorization-server gate for tunne…"]
tunnel_orchestration["cloudflared quick-tunnel orchestration (detec…"]
tunnel_exposure_allowlist["Per-server exposure allowlist (default none;…"]
tunnel_webui_tray["Web UI open/close button + URL/QR/instruction…"]
tunnel_oauth_gate --> tunnel_exposure_allowlist
tunnel_orchestration --> tunnel_webui_tray
tunnel_exposure_allowlist --> tunnel_webui_tray
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class tunnel_oauth_gate,tunnel_orchestration,tunnel_exposure_allowlist,tunnel_webui_tray todo;
| Task | Status | Refs |
|---|---|---|
| OAuth 2.1 authorization-server gate for tunnel-origin traffic (PKCE, DCR, Anthropic callback allowlist, token lifecycle/revocation) | ⚪ Todo | — |
| cloudflared quick-tunnel orchestration (detect/launch/supervise/parse URL) + feature flag + never-auto-start | ⚪ Todo | — |
| Per-server exposure allowlist (default none; quarantined non-exposable; hot-reload) | ⚪ Todo | — |
| Web UI open/close button + URL/QR/instructions + warning banner; tray active-state indicator; remote-origin activity marker | ⚪ Todo | — |
⚪ Tool co-occurrence graph (experimental, feature-flagged) — Todo · P2
Local-only co-occurrence graph mined from the activity log: suggests likely-next tools to agents and surfaces usage-chain analytics. Everything sits behind experimental.tool_graph, off by default — nothing leaves the machine.
graph LR
tool_graph_core["Co-occurrence graph from the activity log + r…"]
tool_graph_ranking["Session-aware rank boost in retrieve_tools"]
tool_graph_mining["Workflow mining: frequent chains → suggested…"]
tool_graph_analytics["Usage-chain analytics on the dashboard/stats…"]
tool_graph_core --> tool_graph_ranking
tool_graph_core --> tool_graph_mining
tool_graph_core --> tool_graph_analytics
classDef todo fill:#6e7781,stroke:#3d4248,color:#ffffff;
class tool_graph_core,tool_graph_ranking,tool_graph_mining,tool_graph_analytics todo;
| Task | Status | Refs |
|---|---|---|
| Co-occurrence graph from the activity log + related_tools hint in call_tool responses (flag-gated) | ⚪ Todo | — |
| Session-aware rank boost in retrieve_tools | ⚪ Todo | — |
| Workflow mining: frequent chains → suggested stored scripts (spec 097 synergy) | ⚪ Todo | — |
| Usage-chain analytics on the dashboard/stats page | ⚪ Todo | — |
⚪ Security gateway Tracks C/D (per-arg least-privilege + signature provenance) — Todo · P3
Track A→Spec 056, Track B→Spec 059 (both shipped). UNBUILT: Track C per-ARGUMENT allow-listing (per-tool scope exists in mcp_direct_scope.go); Track D provenance + human-readable signature diff (SHA-256 pinning exists via Spec 032). Build ON 032/028, don't re-implement; honor the rug-pull re-quarantine interaction rule vs 032 auto-approve.
Spec: 054-mcp-security-gateway
⚫ Server marketplace — Todo · parked · P3 · MCP-37
PARKED. ~60% already ships (browse/search/one-click add). No spec yet; gaps tracked as MCP-3246..3250 (tray entries, metadata, telemetry). (070 is the registries-search-add spec, not a marketplace spec.)
⚫ Audit SIEM integration — Todo · parked · P3 · MCP-39
PARKED. Splunk HEC / Elastic _bulk / syslog shippers reusing JSONL export pipeline.
⚫ Paid-tier MVP (billing / seats / license) — Todo · parked · P3 · MCP-40
PARKED. Server-edition revenue motion: Ed25519 license tokens, seats, Stripe checkout. Behind //go:build server.
⚫ SDK v1 migration — Todo · parked · P3
PARKED. Migrate to the v1 MCP Go SDK surface.
🟢 Upgrade awareness & guided update — Done · P0
Corrected CI-filtered telemetry (2026-07-02): ~60% of last-14d active installs run pre-v0.40; latest stable v0.46.0 only 18.7%. Turn the existing internal/updatecheck background poll into a universal, non-intrusive, channel-aware upgrade nudge across every surface. Never blocks/modals; silent offline/CI. 2026-08-29 truth-sync: this epic was marked done, but FR-002's release/age delta was never built — the four shipped tasks are US-slices and the FR belonged to none of them. Spec 079 has only spec.md (no plan.md/tasks.md), so no checkbox surface could catch it; the deferral survived only as TODO(spec-079/FR-002) code comments, which is how an outside contributor found it (#1081). RESOLVED 2026-08-29 in #1085; all five tasks are now done and the epic is complete.
Spec: 079-upgrade-nudge
graph LR
upgrade_nudge_status_log["US1 slice: update availability in mcpproxy st…"]
upgrade_nudge_surfacing["US1 remainder: dismissible Web UI banner + up…"]
upgrade_nudge_channel["US2: channel-aware guided update command (bre…"]
upgrade_nudge_quiet["US3: operator control + CI/offline quiet + no…"]
upgrade_nudge_delta["FR-002 remainder: human-readable 'N releases…"]
upgrade_nudge_status_log --> upgrade_nudge_surfacing
upgrade_nudge_surfacing --> upgrade_nudge_channel
upgrade_nudge_surfacing --> upgrade_nudge_quiet
upgrade_nudge_channel --> upgrade_nudge_delta
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class upgrade_nudge_status_log,upgrade_nudge_surfacing,upgrade_nudge_channel,upgrade_nudge_quiet,upgrade_nudge_delta done;
| Task | Status | Refs |
|---|---|---|
| US1 slice: update availability in mcpproxy status + deduped startup log | 🟢 Done | #798 |
| US1 remainder: dismissible Web UI banner + update_check config block | 🟢 Done | #805 |
| US2: channel-aware guided update command (brew/dmg/deb/rpm/docker/go-install detection, build-time channel marker) | 🟢 Done | #818 |
| US3: operator control + CI/offline quiet + no prerelease downgrade nudges | 🟢 Done | #911 |
| FR-002 remainder: human-readable "N releases / M weeks behind" delta on status, doctor, startup log, Web UI and the tray | 🟢 Done | #1085 |
🟢 Connect step trust: preview, visible backup, one-click undo — Done · P0
Legacy wizard telemetry APPEARED to show 72.4% of engaged users skipping the connect step - debunked 2026-07-06: an instrumentation artifact, genuine never-connected skip = 0% (the wizard stamped skipped on users who connected via ConnectModal/CLI/manual config); real cliff is one-and-done installs ~48% (day-1 return 31%, identity-deduped 2026-07-10), see specs/080. Completers retain ~50% at two weeks vs 6% for non-engaged (correlation with engagement, not causation by the connect step). Backups already exist (internal/connect/backup.go) but are invisible in the Web UI. Close the trust gap: preview the exact config diff, surface the backup, offer one-click undo, explain the macOS TCC prompt.
Spec: 078-connect-trust-preview
graph LR
connect_trust_preview["US1: preview API + wizard diff UI (exact entr…"]
connect_trust_backup_visibility["US1: surface backup_path in Web UI + retentio…"]
connect_trust_undo["US2: one-click undo/disconnect in wizard"]
connect_trust_tcc_copy["US2: pre-emptive macOS TCC explanation in wiz…"]
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class connect_trust_preview,connect_trust_backup_visibility,connect_trust_undo,connect_trust_tcc_copy done;
| Task | Status | Refs |
|---|---|---|
| US1: preview API + wizard diff UI (exact entry, API-key masking) | 🟢 Done | #802 |
| US1: surface backup_path in Web UI + retention policy | 🟢 Done | #799 |
| US2: one-click undo/disconnect in wizard | 🟢 Done | #804 |
| US2: pre-emptive macOS TCC explanation in wizard | 🟢 Done | #910 |
🟢 Spec 116 config commit consistency: one commit section, atomic removal, upstream retirement — Done · P0
Shipped 2026-10-12..10-14. Unticked tasks.md boxes are stale (the work merged); spec-gardener #1594 syncs them.
Spec: 116-config-commit-consistency · PR: #1590 #1600 #1608 #1612 #1621
🟢 Spec 117 review-bound approvals: durable baselines, hash-bound approvals, ordered tool inventories — Done · P0
Shipped 2026-10-12..10-13 (PR-1..3).
Spec: 117-review-bound-approvals · PR: #1604 #1605 #1609
🟢 Non-Docker sandbox isolation (Landlock) — Done · P1 · MCP-34
Landlock LSM + setrlimit native sandbox for stdio upstreams; no userns (Ubuntu 24.04 safe). Originated from roadmap item #11 (no dedicated spec — 054 is the unrelated security-gateway spec). Code in internal/sandbox/; PRs #754/#759/#768/#781/#782.
graph LR
sandbox_spike["Landlock sandbox spike (MCP-34.1)<br/>MCP-3232"]
sandbox_mode_config["isolation.mode enum + resolver (MCP-34.2)<br/>MCP-3233"]
sandbox_launcher["Native sandbox launcher Landlock+rlimits (MCP…<br/>MCP-3234"]
sandbox_scanner_parity["Scanner-flow parity under sandbox (MCP-34.4)<br/>MCP-3235"]
sandbox_snap_docker_it["snap-docker integration tests + CI (MCP-34.5)<br/>MCP-3236"]
sandbox_spike --> sandbox_mode_config
sandbox_mode_config --> sandbox_launcher
sandbox_launcher --> sandbox_scanner_parity
sandbox_scanner_parity --> sandbox_snap_docker_it
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class sandbox_spike,sandbox_mode_config,sandbox_launcher,sandbox_scanner_parity,sandbox_snap_docker_it done;
| Task | Status | Refs |
|---|---|---|
| Landlock sandbox spike (MCP-34.1) | 🟢 Done | MCP-3232 #754 |
| isolation.mode enum + resolver (MCP-34.2) | 🟢 Done | MCP-3233 #759 |
| Native sandbox launcher Landlock+rlimits (MCP-34.3) | 🟢 Done | MCP-3234 #768 |
| Scanner-flow parity under sandbox (MCP-34.4) | 🟢 Done | MCP-3235 #781 |
| snap-docker integration tests + CI (MCP-34.5) | 🟢 Done | MCP-3236 #782 |
🟢 Spec 076 deterministic offline tool-scanner — Done · P1 · MCP-3574
Deterministic offline signal pipeline replaces ~10%-recall scanner; scan-eval --gate (recall>=0.90 / FP<=5%) in CI.
Spec: 076-deterministic-tool-scanner
graph LR
scanner_v2_foundation["detect-engine foundation (T1)<br/>MCP-3575"]
scanner_v2_hard_checks["3 hard checks + scanner wiring (US1 MVP)<br/>MCP-3576"]
scanner_v2_soft_checks["3 soft checks + patterns confidence (US2)<br/>MCP-3577"]
scanner_v2_consensus["Consensus risk-score + report transparency (U…<br/>MCP-3578"]
scanner_v2_eval_gate["Eval corpus + CI recall/FP gate (US3)<br/>MCP-3579"]
scanner_v2_docs["Tool-scanner detect-engine docs (T22)<br/>MCP-3683"]
scanner_v2_foundation --> scanner_v2_hard_checks
scanner_v2_foundation --> scanner_v2_soft_checks
scanner_v2_hard_checks --> scanner_v2_consensus
scanner_v2_soft_checks --> scanner_v2_consensus
scanner_v2_hard_checks --> scanner_v2_eval_gate
scanner_v2_eval_gate --> scanner_v2_docs
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class scanner_v2_foundation,scanner_v2_hard_checks,scanner_v2_soft_checks,scanner_v2_consensus,scanner_v2_eval_gate,scanner_v2_docs done;
| Task | Status | Refs |
|---|---|---|
| detect-engine foundation (T1) | 🟢 Done | MCP-3575 #769 |
| 3 hard checks + scanner wiring (US1 MVP) | 🟢 Done | MCP-3576 #770 |
| 3 soft checks + patterns confidence (US2) | 🟢 Done | MCP-3577 #775 |
| Consensus risk-score + report transparency (US4) | 🟢 Done | MCP-3578 #776 |
| Eval corpus + CI recall/FP gate (US3) | 🟢 Done | MCP-3579 #777 |
| Tool-scanner detect-engine docs (T22) | 🟢 Done | MCP-3683 #780 |
🟢 Analytics dashboard as default page — Done · P1
Per-server / per-tool token-drain graphs; make the dashboard the default landing page. 2026-07-10 truth-sync: spec 069 is SHIPPED (25/26 — the only open task is a Playwright verification sweep), so the graphs half is done. 2026-08-31 audit: the default-landing half shipped too - frontend/src/router/index.ts routes path '/' to the Dashboard component, guarded by frontend/tests/unit/dashboard-default-landing.spec.ts. Spec 069's one remaining task (T023) is a local Playwright verification sweep that leaves no committed artifact: a human can run it and tick the box, but no code evidence can ever confirm it, so it cannot gate the epic. The epic is complete.
Spec: 069-observability-usage-graphs
graph LR
analytics_token_drain_graphs["Per-server / per-tool token-drain graphs"]
analytics_default_landing["Make dashboard the default landing page"]
analytics_token_drain_graphs --> analytics_default_landing
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class analytics_token_drain_graphs,analytics_default_landing done;
| Task | Status | Refs |
|---|---|---|
| Per-server / per-tool token-drain graphs | 🟢 Done | — |
| Make dashboard the default landing page | 🟢 Done | #1044 |
🟢 Registries — easier search + add-server — Done · P1
Lower the friction of finding a server in a registry and adding it; lean on the official registry protocol work. 2026-07-10 truth-sync: both children shipped — spec 070 is 21/24 (the 3 open tasks are pre-PR chores: worktree baseline, run gates, apply gate decisions) and 071 is 12/12. depends_on [ux-audit] dropped: a done epic cannot depend on a todo one.
Spec: 070-registry-easy-upstream-add
graph LR
registries_search_ux["Improved registry search UX"]
registries_official_protocol["Official registry protocol integration"]
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class registries_search_ux,registries_official_protocol done;
| Task | Status | Refs |
|---|---|---|
| Improved registry search UX | 🟢 Done | — |
| Official registry protocol integration | 🟢 Done | — |
🟢 Scanner simplification (deterministic default, opt-in deep scan) — Done · P1
Make the Spec 076 detect engine the always-on offline default; demote Docker scanners + source extraction to opt-in deep scan that never blocks/degrades the baseline; single unified report. COMPLETE: US1 #786, US2 #792, US4 #794, US3 + deep-scan trust fixes + docs truth sweep (T037-T039) #793 — all merged; shipped in v0.47.0-rc.2. Remaining 4 unchecked tasks in tasks.md are documented scope-outs. First of the 5 personal-edition polish verticals.
Spec: 077-scanner-simplification
graph LR
scanner_simpl_baseline["US1: deterministic offline baseline default +…"]
scanner_simpl_unified_report["US2: single merged report + cross-scanner con…"]
scanner_simpl_deep_optin["US3: opt-in deep scan (off by default), never…"]
scanner_simpl_notifications["US4: collapse scan-notification storm into on…"]
scanner_simpl_deepscan_fixes["Deep-scan trust fixes: nil-Security gating bu…"]
scanner_simpl_baseline --> scanner_simpl_unified_report
scanner_simpl_baseline --> scanner_simpl_deep_optin
scanner_simpl_unified_report --> scanner_simpl_deep_optin
scanner_simpl_unified_report --> scanner_simpl_notifications
scanner_simpl_deep_optin --> scanner_simpl_deepscan_fixes
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class scanner_simpl_baseline,scanner_simpl_unified_report,scanner_simpl_deep_optin,scanner_simpl_notifications,scanner_simpl_deepscan_fixes done;
| Task | Status | Refs |
|---|---|---|
| US1: deterministic offline baseline default + curated hard phrase_injection check (delete duplicate legacy rules) | 🟢 Done | #786 |
| US2: single merged report + cross-scanner consensus confidence | 🟢 Done | #792 |
| US3: opt-in deep scan (off by default), never blocks/degrades baseline; config migration | 🟢 Done | #793 |
| US4: collapse scan-notification storm into one debounced settled event (MCP-2207) | 🟢 Done | #794 |
| Deep-scan trust fixes: nil-Security gating bug (source fetch runs with deep scan off on default configs), FR-014 verdict inversion (Dangerous deep finding < Warning), surface silently-skipped Docker scanners (non-nil deep_scan descriptor + CLI hint on security enable) | 🟢 Done | #793 |
🟢 Deferred-schema serialization for the direct tools/list surface (spec 102) — Done · P1
Direct mode enumerates every upstream tool but always ships full inputSchema (~30K tokens for a 100-tool fleet; Spec 083 profiling put ~77% of the payload in schemas agents rarely read). Deferred serialization keeps every tool name, description and annotation and appends the Spec 085 compact signature instead of the schema, with describe_tool on the direct surface to recover it and the shipped pre-dispatch validation turning a wrong guess into one self-healing retry. Not a new routing_mode — a serialization mode of the direct surface, on the same tool_response_mode axis that already governs retrieve_tools. Spec merged in #1035 (issue #971, maintainer-accepted direction). COMPLETE: all 89 tasks shipped in #1063; the settings UI for both serialization axes followed in #1082; #1083/#1084 fixed in #1086. MEASURED SAVINGS FELL WELL SHORT OF THE ~88% ORIGINALLY PROJECTED: 29.7% on the frozen 45-tool reference corpus and 34.8% on a 527-tool snapshot, with 38.9% the arithmetic ceiling even if both the schema and the signature were deleted. The projection assumed schemas dominate the payload; names, descriptions and annotations turn out to carry most of it. SC-001 was RESTATED per corpus shape (maintainer decision 2026-08-29): now >=25% on the 45-tool corpus and >=30% at fleet scale, both asserted in internal/server/mcp_routing_deferred_tokens_test.go, with the original 70% kept as an upper tripwire. Unblocks token-bench — and that measured shortfall is the first thing token-bench has to explain.
Spec: 102-schema-deferred · PR: #1063
🟢 Agent-token scope hardening: every MCP request authorized by its own scope (spec 105) — Done · P1
The Spec 104 cross-model review verified 'an agent token sees and uses only its granted servers, profile and tiers' against the code one surface at a time and found eight places where a legitimately narrow token could learn about or act on servers outside its grant: cached responses, set_profile and profile-URL responses, retrieve_tools metadata, direct-publication filtering, target-tier execution, aggregated prompts, per-server management ops, and refusal shapes. Spec 105 is the acceptance contract (19 astra rounds, ready-for-plan 2026-09-07). Five fix sessions ran in parallel from the review and MERGED 2026-09-08 (#1223 target tier, #1224 tail_log, #1225 set_profile, #1226 read_cache provenance, #1227 prompt owner + deleted-pin enumeration), each live-verified against a baseline binary and astra-reviewed to CLEAN. Each of those PR bodies carries a 'Follow-ups / Spec 105 gaps' checklist — the todo tasks below are those lists grouped by FR. Prerequisite for auto-routing-mode: Spec 104 FR-016 states the invariant these corrections make true.
Spec: 105-agent-scope-hardening
graph LR
scope_fix_target_tier["FR-009 (dispatch half): call_tool_* requires…"]
scope_fix_tail_log["FR-007 (name half): upstream_servers tail_log…"]
scope_fix_set_profile["FR-003: set_profile reports token ∩ profile,…"]
scope_fix_read_cache["FR-001: cached responses carry the producer's…"]
scope_fix_prompts_profile_url["FR-006 + FR-004 (deleted pin): aggregated pro…"]
scope_retrieve_tools["FR-005: retrieve_tools filters by scope BEFOR…"]
scope_direct_publication["FR-008: direct-surface definitions take owner…"]
scope_refusal_shapes["FR-010: scope-first refusal precedence; dispa…"]
scope_selectable_profile_predicate["FR-003/FR-004 remainder: selectable-profile p…"]
scope_cache_legacy_invalidation["FR-002 + FR-001 remainder: legacy/unstamped a…"]
scope_log_attribution["FR-007 remainder: per-record canonical log ow…"]
scope_target_identity_producers["FR-009 remainder: producer-side exact-name id…"]
scope_fix_stored_script_admin["FR-012: stored-script enumeration is administ…"]
scope_regression_suite["FR-011/FR-013/FR-014: two-fixture differentia…"]
scope_retrieve_tools --> scope_refusal_shapes
scope_fix_set_profile --> scope_selectable_profile_predicate
scope_fix_prompts_profile_url --> scope_selectable_profile_predicate
scope_fix_read_cache --> scope_cache_legacy_invalidation
scope_fix_tail_log --> scope_log_attribution
scope_fix_target_tier --> scope_target_identity_producers
scope_retrieve_tools --> scope_regression_suite
scope_direct_publication --> scope_regression_suite
scope_refusal_shapes --> scope_regression_suite
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class scope_fix_target_tier,scope_fix_tail_log,scope_fix_set_profile,scope_fix_read_cache,scope_fix_prompts_profile_url,scope_retrieve_tools,scope_direct_publication,scope_refusal_shapes,scope_selectable_profile_predicate,scope_cache_legacy_invalidation,scope_log_attribution,scope_target_identity_producers,scope_fix_stored_script_admin,scope_regression_suite done;
| Task | Status | Refs |
|---|---|---|
| FR-009 (dispatch half): call_tool_* requires the TARGET tool's tier, fail closed on unresolved tiers; approval records keep exact ns:name identity | 🟢 Done | #1223 |
| FR-007 (name half): upstream_servers tail_log authorizes the server against effective scope before lookup, non-disclosing | 🟢 Done | #1224 |
| FR-003: set_profile reports token ∩ profile, selectable-profile predicate, non-selectable == nonexistent | 🟢 Done | #1225 |
| FR-001: cached responses carry the producer's authorization snapshot; read_cache and the REST cache branch refuse narrower readers | 🟢 Done | #1226 |
| FR-006 + FR-004 (deleted pin): aggregated prompts authorized by canonical registration owner; profile URL / set_profile stop enumerating on a deleted pin | 🟢 Done | #1227 |
| FR-005: retrieve_tools filters by scope BEFORE limiting; indexed counts, usage ranking, debug output and session risk computed over the authorized population only | 🟢 Done | #1325 |
| FR-008: direct-surface definitions take owner and tier from their own registration identity at every publication seam, both skew directions, full and deferred | 🟢 Done | #1326 |
| FR-010: scope-first refusal precedence; dispatch denials and 'available servers' never name hidden servers; describe_tool not-found and alias resolution computed over the authorized corpus | 🟢 Done | #1328 |
| FR-003/FR-004 remainder: selectable-profile predicate for UNPINNED tokens on /mcp/p/, /mcp/p, /mcp/p/ and set_profile; identical status+body across missing / deleted / not-selectable / pin-mismatch / no-profiles (#1225 + #1227 follow-up lists) | 🟢 Done | #1283 |
| FR-002 + FR-001 remainder: legacy/unstamped and internal (registry, guesser) cache entries refused for every caller and durably invalidated; monotone recursive provenance; existence-non-disclosing refusal on MCP and REST (#1226 follow-up list) | 🟢 Done | #1282 |
| FR-007 remainder: per-record canonical log ownership (a/b vs a_b share one file), filter-before-limit + authorized lines_returned, subject-bound OAuth-callback logging, canonical container ownership in Docker cleanup (#1224 follow-up list) | 🟢 Done | #1284 |
| FR-009 remainder: producer-side exact-name identity (checkToolApprovals / differential index collapse ns:erase to erase), direct-name dispatch + preflight share lookupToolApproval, unresolved/stale identity refuses scoped callers, full 54-cell acceptance tables (#1223 follow-up list) | 🟢 Done | #1279 |
| FR-012: stored-script enumeration is administrator-only (PR H0) | 🟢 Done | #1285 |
| FR-011/FR-013/FR-014: two-fixture differential oracle with sentinels across the applicability matrix, credential-authenticated HTTP matrix over every /mcp surface, admin p95 perf gate on the frozen 527-tool snapshot | 🟢 Done | #1332 |
🟢 Spec 113 upstream resilience: OAuth refresh, discovery, call-error taxonomy, session re-init — Done · P1
Shipped 2026-10-06..10-17 (113-a..f, plus #1650 serializing session re-init with in-flight requests). tasks.md checkboxes were never ticked (0/100); spec-gardener #1594 syncs them.
Spec: 113-upstream-resilience · PR: #1495 #1498 #1499 #1501 #1502 #1504 #1510 #1650
🟢 Spec 115 admin MCP credentials tool: client credentials + agent token lifecycle — Done · P1
Shipped 2026-10-10. #1579 (activity table fold + orphan seed honouring the Spec 115 guard) is an open follow-up fix.
Spec: 115-mcp-credential-lifecycle · PR: #1557
🟢 Quarantine/approval testing pilot: independent policy model, scenario inventory, mutation gate — Done · P1
Shipped 2026-10-13..10-16: internal/qapilot model, S01-S26 scenarios, check ledger + mutation set run by quarantine-pilot.yml; #1634 fixed an approval-hash collision the pilot found. Docs: docs/development/quarantine-approval-pilot.md.
PR: #1619 #1631 #1634
🟢 Tray↔core decoupling: socket/REST API only, no config-file reads — Done · P2
Architecture rule (CLAUDE.md): the tray holds no state and talks to the core only via socket/REST + SSE. 2026-07-11 source-of-truth re-audit + fix: Swift tray was already clean (MCPProxyApp.swift opens the config in an external editor, never parses it); the Go tray's update-check gate was already reworked to core-API gating (#805). The last violation — config.LoadFromFile in the Go tray's OAuth login path, live since ff03db92 (2026-05-18, #477) — turned out to be FUNCTIONALLY DEAD: the loaded config fed only two debug log lines, while the actual trigger was already the core-API TriggerOAuthLogin. Deleted rather than ported to REST. Bootstrap reads (socket path, config PATH without parsing, CA cert) are allowed and remain. Now enforced by a test so the rule cannot silently rot.
graph LR
tray_oauth_config_read["Delete the dead config read in the Go tray OA…"]
tray_config_import_guard["Test guard (internal/tray/config_import_guard…"]
tray_oauth_config_read --> tray_config_import_guard
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class tray_oauth_config_read,tray_config_import_guard done;
| Task | Status | Refs |
|---|---|---|
| Delete the dead config read in the Go tray OAuth path (config.LoadFromFile) + drop the now-unused internal/config import. GetConfigPath stays on the interface — openConfigDir still needs the path to reveal the dir in the file manager. | 🟢 Done | — |
| Test guard (internal/tray/config_import_guard_test.go) failing any tray-side call to config.LoadFromFile/Load/SaveConfig/... Parses source on disk, so a violation cannot hide behind an inactive build tag. Bans config FILE I/O, not the config package — cmd/mcpproxy-tray legitimately references the config.LogConfig type for its own logger. | 🟢 Done | — |
🟢 Spec 107 server edition SSO front door hardened for real IdPs — Done · P2
Generic OIDC, IdP-group -> server allowlist, attributable JSONL audit line; freeze the latent multiuser/credential-injection code. Research: docs/research/server-edition-2026-09-14 (#1281).
Spec: 107-server-edition-sso-hardening
graph LR
sso_pr_a_freeze_cut["PR-A freeze/cut latent code + config normalis…"]
sso_pr_b_oidc_front_door["PR-B generic OIDC provider + front door behin…"]
sso_pr_c_group_allowlist["PR-C one entitlement predicate, group grants,…"]
sso_pr_d_audit_line["PR-D attributable JSONL audit line + auth_eve…"]
sso_pr_a_freeze_cut --> sso_pr_b_oidc_front_door
sso_pr_b_oidc_front_door --> sso_pr_c_group_allowlist
sso_pr_c_group_allowlist --> sso_pr_d_audit_line
classDef done fill:#1f7a1f,stroke:#0d3d0d,color:#ffffff;
class sso_pr_a_freeze_cut,sso_pr_b_oidc_front_door,sso_pr_c_group_allowlist,sso_pr_d_audit_line done;
| Task | Status | Refs |
|---|---|---|
| PR-A freeze/cut latent code + config normaliser + per-owner token cap (US5, US6) | 🟢 Done | #1287 |
| PR-B generic OIDC provider + front door behind ingress + telemetry v13 (US2, US7) | 🟢 Done | #1292 |
| PR-C one entitlement predicate, group grants, tenant Web UI session principal (US1, US4) | 🟢 Done | #1293 |
| PR-D attributable JSONL audit line + auth_event + config/doctor/metrics (US3) | 🟢 Done | #1296 |
| Epic | Status | Priority | Progress | Spec | PR |
|---|---|---|---|---|---|
| Web UI + macOS app UX audit | In progress | P0 | — | ||
| Release qualification gate (auto-QA matrix blocks the tag) | In progress | P0 | 4/4 (100%) | 081-release-qa-gate | |
| Action log / transparency — info at a glance | In progress | P1 | — | ||
| tpa-db: versioned TPA signature database for the offline scanner | In progress | P1 | 81/81 (100%) | 101-tpa-db | |
| Token-efficiency benchmark: measured savings, published results | In progress | P1 | 62/64 (97%) | 103-token-bench | |
| Telemetry identity & data quality (machine_id + CI-filter hardening) | In progress | P1 | — | ||
| Telemetry v7: honest funnel + churn instrumentation | In progress | P1 | — | 080-telemetry-v7-churn | |
| MCP protocol upgrade to 2026-07-28 revision | In progress | P1 | 40/81 (49%) | 058-mcp-2026-upgrade | |
| Spec 108 profiles v3: scoped profiles, client binding, scope-aware observability | In progress | P1 | 194/195 (99%) | 108-profiles-v3 | |
| Spec 109 navigation, scope filters and cross-surface UX consistency | In progress | P1 | 257/258 (100%) | 109-ux-navigation-consistency | |
| Planning/docs truth automation | In progress | P2 | — | ||
| Discovery-quality eval harness (Spec 065 second half) | In progress | P3 | — | 065-evaluation-foundation | |
| Spec 114 typed pending-call outcome + call correlation for long-running stdio tool calls | In review | P2 | — | #1536 | |
| Auto routing mode: budget-fitted tool surface per session (spec 104) | Todo | P1 | — | 104-auto-routing-mode | |
Windows native tray app MCP-43 |
Todo | P2 | — | ||
| Remote access tunnel (feature-flagged MVP, spec 089) | Todo | P2 | — | 089-remote-access-tunnel | |
| Tool co-occurrence graph (experimental, feature-flagged) | Todo | P2 | — | ||
| Security gateway Tracks C/D (per-arg least-privilege + signature provenance) | Todo | P3 | — | 054-mcp-security-gateway | |
Server marketplace MCP-37 |
Todo (parked) | P3 | — | ||
Audit SIEM integration MCP-39 |
Todo (parked) | P3 | — | ||
Paid-tier MVP (billing / seats / license) MCP-40 |
Todo (parked) | P3 | — | ||
| SDK v1 migration | Todo (parked) | P3 | — | ||
| Upgrade awareness & guided update | Done | P0 | — | 079-upgrade-nudge | |
| Connect step trust: preview, visible backup, one-click undo | Done | P0 | — | 078-connect-trust-preview | |
| Spec 116 config commit consistency: one commit section, atomic removal, upstream retirement | Done | P0 | 81/124 (65%) | 116-config-commit-consistency | #1590 #1600 #1608 #1612 #1621 |
| Spec 117 review-bound approvals: durable baselines, hash-bound approvals, ordered tool inventories | Done | P0 | 46/50 (92%) | 117-review-bound-approvals | #1604 #1605 #1609 |
Non-Docker sandbox isolation (Landlock) MCP-34 |
Done | P1 | — | ||
Spec 076 deterministic offline tool-scanner MCP-3574 |
Done | P1 | 22/24 (92%) | 076-deterministic-tool-scanner | |
| Analytics dashboard as default page | Done | P1 | 25/26 (96%) | 069-observability-usage-graphs | |
| Registries — easier search + add-server | Done | P1 | 21/24 (88%) | 070-registry-easy-upstream-add | |
| Scanner simplification (deterministic default, opt-in deep scan) | Done | P1 | 38/42 (90%) | 077-scanner-simplification | |
| Deferred-schema serialization for the direct tools/list surface (spec 102) | Done | P1 | 89/89 (100%) | 102-schema-deferred | #1063 |
| Agent-token scope hardening: every MCP request authorized by its own scope (spec 105) | Done | P1 | 111/113 (98%) | 105-agent-scope-hardening | |
| Spec 113 upstream resilience: OAuth refresh, discovery, call-error taxonomy, session re-init | Done | P1 | 0/100 (0%) | 113-upstream-resilience | #1495 #1498 #1499 #1501 #1502 #1504 #1510 #1650 |
| Spec 115 admin MCP credentials tool: client credentials + agent token lifecycle | Done | P1 | 86/87 (99%) | 115-mcp-credential-lifecycle | #1557 |
| Quarantine/approval testing pilot: independent policy model, scenario inventory, mutation gate | Done | P1 | — | #1619 #1631 #1634 | |
| Tray↔core decoupling: socket/REST API only, no config-file reads | Done | P2 | — | ||
| Spec 107 server edition SSO front door hardened for real IdPs | Done | P2 | 126/126 (100%) | 107-server-edition-sso-hardening |
Swept out of the working set by --archive once done, merged and cooled off. Full entries — notes, child tasks, PR refs — live in roadmap.archive.yaml.
| Epic | Shipped | Archived | PRs |
|---|---|---|---|
Profiles v2 (per-profile tool views) MCP-33 |
2026-06-24 | 2026-07-10 | #756 #761 #766 #767 |
TypeScript code-execution GA + cookbook MCP-38 |
2026-06-24 | 2026-07-10 | #753 |
Legend: shipped ≥95% checked · in-flight 1–94% · drafted 0% · — no tasks.md. This aggregate is regenerated here rather than overwriting the hand-maintained specs/README.md, which keeps its curated prose, runbooks and design-doc links.