fix(web): carry a landed stdio env/cwd onto the config it connects with

The Server Settings modal edits a stdio server's `env` and `cwd` as
settings, while the transport reads them off the *config* — so #2091's
tracker, which resolves settings through the last write known to have
reached disk, left those two behind: `server.config` still came straight
off a `servers` entry that stops advancing once a list read fails. A save
that landed during such a window kept spawning the child process with the
pre-save environment, while the modal (re-seeded from the tracker) showed
the new value. Credentials live in `env`, so the symptom is the inspected
server failing to authorize rather than a visibly lost edit.

Adds the settings→config mapping to `core/mcp/serverList.ts` — the one
place both sides of the wire can share — and routes the `/api/servers` PUT
write-through and the web client's connect path through it, so the value
persisted and the value spawned cannot be derived differently.

Closes #2096

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-25 00:36:09 -04:00
commit d9b5f4f8a7

View file

@ -51,7 +51,6 @@ import type {
} from "../../types.js";
import {
DEFAULT_SEED_CONFIG,
envPairsToRecord,
expectedSecretFields,
extractSecretsFromStored,
INSPECTOR_FIELD_KEYS,
@ -59,6 +58,7 @@ import {
isProtocolEra,
mergeSecretsIntoStored,
normalizeServerType,
stdioConfigFieldsFromSettings,
storedFieldsToInspectorSettings,
stripInspectorFields,
} from "../../serverList.js";
@ -1653,16 +1653,18 @@ export function createRemoteApp(
): void => {
if (!(entry.type === "stdio" || entry.type === undefined)) return;
const stdio = entry as StdioServerConfig & StoredMCPServer;
// Shared with the web client's connect-time application of the same
// mapping (#2096), so the environment a save persists and the one the
// child process is spawned with cannot be derived differently.
const { env, cwd } = stdioConfigFieldsFromSettings(settings);
if (provided.env) {
const env = envPairsToRecord(settings.env);
if (Object.keys(env).length > 0) {
if (env) {
stdio.env = env;
} else {
delete stdio.env;
}
}
if (provided.cwd) {
const cwd = settings.cwd?.trim();
if (cwd) {
stdio.cwd = cwd;
} else {