You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a1101fb
Browse filesBrowse the repository at this point in the historyBrowse files
Docs, changelog and verified fixes from a first-run, upgrade and
user-test pass on `main` (335477e).
## Docs
- `docs/features/profiles.md`: profiles are optional. Without an
effective profile, no profile-level restriction applies (a scoped
credential's own grant still does). The quick start is presented as
being for scoped access.
- `docs/configuration.md` (`quarantined` row): explains the real
default. A server added through the UI, CLI or API follows its trust
mode. A first-seen config-file server with no `quarantined` key and no
`config.db` record is held for review. An explicit value wins, and a
recorded server keeps its state. Links to the admission rules.
- `docs/features/security-quarantine.md`: the hand-editing section names
the extra conditions: quarantine is enabled, and the trust mode is not
`auto` (including legacy `auto_approve_tool_changes`/`skip_quarantine`
resolving to `auto`), matching `ServerConfig.EffectiveTrustMode`.
- `docs/getting-started/quick-start.mdx`: a plain note that a server
added by editing the file is held for review until approved.
- `CHANGELOG.md`: the security, review, catalog, telemetry, CLI and
first-run fixes merged since v0.69.0 (#1463, #1467–#1473, #1481) plus
this PR's.
## Fixes (each reproduced in an isolated instance, regression test fails
on main)
- **Upgrade start advisory repeated.** `reportPreFixAdmissions` ran on
every gate pass (initial gate, `LoadConfiguredServers`, every publish),
so an upgrade start logged the "predate the config-load admission gate"
advisory 2–5 times. It is now reported once per server per process. Gate
decisions are unchanged.
- **Benign startup race logged as ERROR.** Both the supervisor reconcile
and `LoadConfiguredServers` → `AddServer` asked a not-yet-ready client
to connect. The second call was correctly refused with "connection
already in progress or established (state: Connecting)" but logged at
ERROR, and server identity registration was skipped. A new
`managed.ErrConnectAlreadyActive` sentinel (same message text) lets
`AddServer` treat it as success at debug level.
- **`set_profile` under-reported a switchable client's reach.** After a
successful switch, `resolveEffectiveProfileForJustSetSlug` treated the
client binding as authoritative and reported the binding's servers
instead of the selected profile's.
## Verification
- Cross-model review: codex gpt-6.1-sol, chunked. Three low findings:
two doc-wording findings are applied, and the third (the per-process
advisory set is never cleared) is a deliberate trade-off.
- Live re-verification on isolated instances: each symptom was
reproduced on a main build and is gone on this branch. The upgrade case
was run over a v0.52.1 data dir.
-**web:** token savings are labelled as an estimate on Home and in the macOS app, Activity's
207
+
"Clear filters" on a server/tool conflict reloads the list, "Needs review" health badges are
208
+
orange, and a brand-new install shows a getting-started card instead of "All clear". ([#1467](https://github.com/smart-mcp-proxy/mcpproxy-go/pull/1467))
209
+
-**logging:** an upgrade start no longer repeats the "predate the config-load admission gate"
210
+
advisory on every config pass (once per server per process), and the benign startup race
211
+
"connection already in progress or established" is logged at debug instead of error.
212
+
-**profiles:**`set_profile` from a switchable client credential reports the servers of the
213
+
profile it just selected instead of the binding's narrower set.
214
+
170
215
-**web/settings:** toggles for nullable settings (`quarantine_enabled`, `telemetry.enabled` and the
171
216
`audit_log.*` booleans) show the value the core actually applies instead of OFF when the key is
172
217
absent, and the page header now says to press Save changes instead of "Changes save instantly".
Copy file name to clipboardExpand all lines: docs/configuration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -415,7 +415,7 @@ it and none can double-report it.
415
415
|`oauth`| object | No | OAuth configuration (see [OAuth Configuration](#oauth-configuration)) |
416
416
|`isolation`| object | No | Per-server Docker isolation settings (see [Docker Isolation](#docker-isolation)) |
417
417
|`enabled`| boolean | No | Enable/disable server (default: `true`) |
418
-
|`quarantined`| boolean | No | Security quarantine status (default: `false`for manually added servers, `true`for LLM-added servers)|
418
+
|`quarantined`| boolean | No | Security quarantine status. The default depends on how the server arrives. A server added through the UI, CLI, REST API or an AI agent follows its [trust mode](features/security-quarantine.md#trust-modes-auto--scan--manual) at add time (quarantined under the default`manual` mode). A server you add by editing this file, with no `quarantined` key and no prior `config.db` record, is **held for review** on first load when quarantine is enabled and its trust mode is not `auto` (no `trust_mode` means `manual`, unless a legacy `auto_approve_tool_changes: true`or `skip_quarantine: true` resolves it to `auto`). An explicit `"quarantined": false` admits it, and an explicit `true` holds it. A server that is already recorded in `config.db` keeps its recorded state. See [Servers added by hand-editing `mcp_config.json`](features/security-quarantine.md#servers-added-by-hand-editing-mcp_configjson) for the full admission rules.|
419
419
|`reconnect_on_use`| boolean | No | When `true`, tool calls to a disconnected server trigger an immediate reconnect attempt (15s timeout) before failing (default: `false`) |
420
420
|`expose_prompts`| boolean | No | Per-server override for whether this server's MCP prompts are aggregated into mcpproxy's `prompts/list`. Only takes effect when the global `aggregate_upstream_prompts` master switch is on. Omit to expose prompts whenever the server advertises `Capabilities.Prompts`; `false` opts this server out even if it does. |
421
421
|`toon_output`| string | No | Per-server override for the global [`toon_output`](#toon-output-adaptive-result-encoding): `off`, `adaptive`, or `always`. Non-empty value wins over the global for this server's tools; omit to inherit. See [TOON Output](features/toon-output.md). |
Copy file name to clipboardExpand all lines: docs/features/profiles.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,6 +6,10 @@ description: "Named views over your upstream servers with a tool policy: tier ca
6
6
7
7
# Profiles
8
8
9
+
:::note Profiles are optional
10
+
You do not need a profile to use MCPProxy. Without an effective profile (no profiles configured, or a caller that none of them applies to), no profile-level restriction applies to that caller: it can reach every configured server, unless its own credential is scoped (for example an agent token with an allowed-servers list). Use profiles when you need to scope access, for example to give one client or token read-only access to a few servers.
11
+
:::
12
+
9
13
A **profile** is a named view over your upstream servers plus a **tool policy**. It decides which servers a caller reaches, which of their tools the caller can discover and call, and whether the caller gets code execution and the management tools. The same profile is used by every surface that lets you work with MCPProxy: the config file, the Web UI and macOS app (**Profiles** in the sidebar), the CLI (`mcpproxy profile ...`), the MCP `profiles` tool and the REST API.
10
14
11
15
A profile is enforced by the core, on every path a tool can be discovered or called through. "Work Read-only" really is read-only: a session under it cannot find, describe or call a write, destructive, denied or unclassified tool, whichever way it connected.
@@ -18,6 +22,8 @@ Three ideas fit together:
18
22
19
23
## Quick start
20
24
25
+
This quick start is for users who need scoped access. If you do not, you can skip profiles entirely.
:::note First-time config-file servers are held for review
237
+
A server you add by editing this file for the first time is **held for review** (quarantined) until you approve it in the **Review queue**. The examples above omit the `quarantined` key on purpose. Writing `"quarantined": false` admits a server right away, so use it only for servers you have already vetted. A server that MCPProxy already knows keeps its recorded state. See [Servers added by hand-editing `mcp_config.json`](/features/security-quarantine#servers-added-by-hand-editing-mcp_configjson).
238
+
:::
239
+
236
240
## 5. Approve It Out of Quarantine
237
241
238
242
However you added it, the server is now **quarantined** - its tools are withheld
// The gate runs several times per process (gateInitialConfig, then
228
+
// LoadConfiguredServers, then the pre-publish hook on every publish); name
229
+
// each affected server once per process.
230
+
r.preFixMu.Lock()
231
+
ifr.preFixReported==nil {
232
+
r.preFixReported=make(map[string]struct{})
233
+
}
234
+
fresh:=names[:0:0]
235
+
for_, n:=rangenames {
236
+
if_, seen:=r.preFixReported[n]; !seen {
237
+
r.preFixReported[n] =struct{}{}
238
+
fresh=append(fresh, n)
239
+
}
240
+
}
241
+
r.preFixMu.Unlock()
242
+
iflen(fresh) ==0 {
243
+
return
244
+
}
245
+
names=fresh
227
246
r.logger.Warn("Configured servers predate the config-load admission gate and have never been explicitly reviewed",
228
247
zap.Strings("servers", names),
229
248
zap.String("action", "review them in the quarantine UI, or record the decision with an explicit \"quarantined\" value in mcp_config.json (issue #937)"))
0 commit comments