revert(web): drop custom headers from the manual add form (#1915)

Server Settings already has a Custom Headers editor, so adding one to the
manual add form created a second place to edit the same field. The reporter
had also conditionally withdrawn #1915 — "editing that information from the
server settings dialog is sufficient" once #1848 closed, which it has.

Reverts the add-form editor, the shared KeyValueRows element, the optional
`settings` argument on addServer / updateServer, and the App-level merge
helper. What remains are two defects found while working in
ServerSettingsForm, which this PR now closes instead (#2040): the Custom
Headers hint misstating OAuth precedence, and the key/value rows' missing
accessible names.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-16 22:57:34 -04:00
commit 4dd8ed4498

View file

@ -29,28 +29,11 @@ export interface UseServersResult {
loading: boolean;
error: string | undefined;
refresh: () => Promise<void>;
/**
* `settings` is optional: omitted, no settings node is persisted for the new
* entry. Passed, it is written alongside the config in the same POST — the
* add form needs this to carry custom headers, which live on `settings`
* rather than on the transport config (#1915).
*/
addServer: (
id: string,
config: MCPServerConfig,
settings?: InspectorServerSettings,
) => Promise<void>;
/**
* `settings` is optional and asymmetric with `addServer`'s: **omitting** it
* tells the backend to preserve the entry's existing settings node, so a
* config-only save cannot silently wipe persisted headers / metadata / OAuth
* credentials. Pass a full settings object to replace it.
*/
addServer: (id: string, config: MCPServerConfig) => Promise<void>;
updateServer: (
originalId: string,
newId: string,
config: MCPServerConfig,
settings?: InspectorServerSettings,
) => Promise<void>;
/**
* Patch only the `settings` node on an existing server entry, leaving the
@ -219,17 +202,11 @@ export function useServers(opts: UseServersOptions): UseServersResult {
}, [base, authToken, doFetch, refreshInternal]);
const addServer = useCallback(
async (
id: string,
config: MCPServerConfig,
settings?: InspectorServerSettings,
): Promise<void> => {
async (id: string, config: MCPServerConfig): Promise<void> => {
const res = await doFetch(`${base}/api/servers`, {
method: "POST",
headers: buildHeaders(authToken, true),
// `settings` is omitted from the body when undefined (JSON.stringify
// drops undefined values), which the route reads as "no settings node".
body: JSON.stringify({ id, config, settings }),
body: JSON.stringify({ id, config }),
});
if (!res.ok) {
throw new Error(await readErrorMessage(res));
@ -258,21 +235,18 @@ export function useServers(opts: UseServersOptions): UseServersResult {
originalId: string,
newId: string,
config: MCPServerConfig,
settings?: InspectorServerSettings,
): Promise<void> => {
// With `settings` undefined, `JSON.stringify` drops the key entirely and
// the backend route treats that omission as "preserve the existing
// settings node on disk" — so a config-only save cannot silently wipe
// persisted headers / metadata / OAuth credentials. A caller editing a
// field that lives on settings (e.g. ServerConfigModal's custom headers)
// passes the full settings object it wants written, which replaces the
// node wholesale — so it must carry forward the fields it isn't editing.
// `settings` is intentionally omitted from the body. The backend route
// treats omission as "preserve the existing settings node on disk", so
// a config-only save (e.g. ServerConfigModal) cannot silently wipe
// persisted headers / metadata / OAuth credentials. To explicitly
// clear settings, send `settings: null`.
const res = await doFetch(
`${base}/api/servers/${encodeURIComponent(originalId)}`,
{
method: "PUT",
headers: buildHeaders(authToken, true),
body: JSON.stringify({ id: newId, config, settings }),
body: JSON.stringify({ id: newId, config }),
},
);
if (!res.ok) {