Skip to content

fix: make server add create-only across REST, MCP and Web UI (UX-01) - #1553

Closed
Dumbris wants to merge 13 commits into
mainfrom
fix/qa070-ux01-create-only-add
Closed

Dumbris wants to merge 13 commits into
mainfrom
fix/qa070-ux01-create-only-add

Conversation

@Dumbris

@Dumbris Dumbris commented Oct 10, 2026

Copy link
Copy Markdown
Member

Summary

UX-01: adding a server whose name already exists silently replaced it. The MCP upstream_servers add tool (which the Web UI Manual form calls) had no existence check, so an approved server was re-quarantined, re-argued, its created reset and its connection dropped. REST/CLI only failed in the sequential case, and the check-then-write in Server.AddServer was racy (40 parallel creates of one name gave up to 33 successes on main).

Changes

  • storage: BoltDB.CreateUpstream / Manager.CreateUpstreamServer do the existence check and write in one bbolt transaction and return ErrUpstreamExists. The record builder is shared with SaveUpstreamServer, so the two cannot drift. SaveUpstreamServer stays an upsert for update, patch, quarantine and reconcile.
  • server: one create-only door, Server.createServer, used by Server.AddServer (REST, CLI, registry, import) and by MCP upstream_servers add. Under one mutex it rejects names already in the runtime config or in storage, writes atomically, then publishes to the runtime config copy-on-write. A refused add changes nothing (no config publish, no activity row, no supervisor reconcile).
  • configWithAppendedServer now replaces a same-name entry instead of appending a second one.
  • MCP duplicate add returns an isError tool result: server 'X' already exists; use operation 'update' or 'patch' to modify it, or choose another name. It does not echo the existing config.
  • import: a rename onto an existing name is reported as skipped already_exists, and a failed post-add is reported in skipped/failed instead of being logged and still listed as imported.

Compatibility decisions

  • The error text server '%s' already exists is unchanged: REST 409, cliclient, upstream add --if-not-exists and the registry ErrDuplicateName mapping match on it.
  • MCP add is no longer an idempotent upsert. Callers re-adding a name get an error that names update/patch. Tool schema and description are untouched (frozen goldens unaffected).
  • Replace-as-a-separate-action is not built; the handoff accepts "fail".
  • Web UI needs no change: /api/v1/tools/call already turns the MCP error result into an error response, so the Manual form shows the message and its existing secret rollback runs.
  • Quarantine-by-default, the quarantine anti-lowering guard, write-mask refusals and activity redaction are untouched. The appctx.StorageManager interface is not changed.
  • Server edition: no separate add path exists; it goes through Server.AddServer.

Verification

  • go test -race on storage, server, httpapi (new tests listed in the commits), golangci-lint v2 with the CI config bare and --build-tags=server: no findings in changed files.
  • Rebuilt binary on a scratch big daemon (26 servers, large-review approved with 180 tools): duplicate add via REST (409), MCP (isError), CLI (exit 1, --if-not-exists exit 0, add-json exit 1), import (skipped), Web UI Manual form (error banner) all left args, quarantine, created, tool count and connection unchanged. 3x40 parallel REST creates, 12 parallel MCP creates and a mixed REST+MCP race each gave exactly one success. State persisted across a daemon restart.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: fix/qa070-ux01-create-only-add

Available Artifacts

  • archive-darwin-amd64 (31 MB)
  • archive-darwin-arm64 (28 MB)
  • archive-linux-amd64 (19 MB)
  • archive-linux-arm64 (17 MB)
  • archive-windows-amd64 (31 MB)
  • archive-windows-arm64 (27 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (27 MB)
  • installer-dmg-darwin-arm64 (24 MB)
  • smart-mcp-proxymcpproxy-goFYH6UZ.dockerbuild (0 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 38072457148 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: e0982f8
Status: ✅  Deploy successful!
Preview URL: https://317be927.mcpproxy-docs.pages.dev
Branch Preview URL: https://fix-qa070-ux01-create-only-a.mcpproxy-docs.pages.dev

View logs

…ver; complete review-screen refresh mock (UX-01)
…ds; reap removed servers a save resurrected (UX-01)
… keep pending removal when a config only carries the name forward (UX-01)
… lock; reap removals a save resurrected before a stale sync (UX-01)
… supervisor actions against the live config (UX-01)
…blication, gate process launch on retirement, purge approvals on config-driven removal (UX-01)
… commit, gate HTTP/SSE requests on retirement, retire review captures, purge prompt approvals (UX-01)
…ic on retirement, hide pending-removal servers from saves and the supervisor, serialize approvals with removal and bind scan approvals to the reviewed server, purge the index when an update quarantines (UX-01)
This was referenced Oct 11, 2026
Dumbris added a commit that referenced this pull request Oct 11, 2026
Server add is create-only on every surface: an atomic bbolt create plus a runtime-config check, create and publish under one mutex. Duplicate adds are refused with REST 409, an MCP isError result naming update/patch, CLI exit 1 (--if-not-exists exit 0) and a Web UI error, with no side effects. Concurrent creates of one name yield exactly one success. Delete then re-add of the same name works. Same-name config entries are replaced rather than appended, and import reports rename conflicts and post-add failures. Live-verified on a rebuilt daemon; OpenCode gpt-6.1-sol VERDICT: PASS at 2030ffe. Supersedes #1553; follow-ups #1558-#1564.
@Dumbris

Dumbris commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

Superseded by #1570 (minimal UX-01 create-only add), merged. The pre-existing config-commit, removal, retirement and OAuth gaps this branch was chasing are filed as #1558 through #1564.

@Dumbris Dumbris closed this Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants