mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-04 13:37:40 +00:00
fix(settings): make MCP edits create-first to avoid data loss
The previous edit flow deleted the existing MCP server before attempting to add the replacement entry. If add failed (CLI error, validation, transport, duplicate handling), the original entry was already gone, causing destructive data loss from an edit action. This change makes both save flows non-destructive: - saveMcpServer now posts /api/mcp/cli/add first. - saveCodexMcpServer now posts /api/codex/mcp/cli/add first. - Old entry deletion only happens after successful create. - Old-entry deletion runs only when identity actually changed (name and for Claude scope). - Cleanup delete failures are caught and logged (console.warn) instead of failing the save. Result: editing is atomic from caller perspective with respect to create failures, and resilient to cleanup failures.
This commit is contained in:
@@ -364,17 +364,14 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }:
|
|||||||
|
|
||||||
const saveMcpServer = useCallback(
|
const saveMcpServer = useCallback(
|
||||||
async (serverData: ClaudeMcpFormState, editingServer: McpServer | null) => {
|
async (serverData: ClaudeMcpFormState, editingServer: McpServer | null) => {
|
||||||
if (editingServer?.id) {
|
const newServerScope = serverData.scope || 'user';
|
||||||
// Editing still follows the existing behavior: remove current entry and re-create it.
|
|
||||||
await deleteMcpServer(editingServer.id, editingServer.scope || 'user');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await authenticatedFetch('/api/mcp/cli/add', {
|
const response = await authenticatedFetch('/api/mcp/cli/add', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: serverData.name,
|
name: serverData.name,
|
||||||
type: serverData.type,
|
type: serverData.type,
|
||||||
scope: serverData.scope,
|
scope: newServerScope,
|
||||||
projectPath: serverData.projectPath,
|
projectPath: serverData.projectPath,
|
||||||
command: serverData.config.command,
|
command: serverData.config.command,
|
||||||
args: serverData.config.args || [],
|
args: serverData.config.args || [],
|
||||||
@@ -393,6 +390,28 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }:
|
|||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error || 'Failed to save server via Claude CLI');
|
throw new Error(result.error || 'Failed to save server via Claude CLI');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!editingServer?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousServerScope = editingServer.scope || 'user';
|
||||||
|
const didServerIdentityChange =
|
||||||
|
editingServer.id !== serverData.name || previousServerScope !== newServerScope;
|
||||||
|
|
||||||
|
if (!didServerIdentityChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deleteMcpServer(editingServer.id, previousServerScope);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Saved MCP server update but failed to remove the previous server entry.', {
|
||||||
|
previousServerId: editingServer.id,
|
||||||
|
previousServerScope,
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[deleteMcpServer],
|
[deleteMcpServer],
|
||||||
);
|
);
|
||||||
@@ -537,10 +556,6 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }:
|
|||||||
|
|
||||||
const saveCodexMcpServer = useCallback(
|
const saveCodexMcpServer = useCallback(
|
||||||
async (serverData: CodexMcpFormState, editingServer: McpServer | null) => {
|
async (serverData: CodexMcpFormState, editingServer: McpServer | null) => {
|
||||||
if (editingServer?.name) {
|
|
||||||
await deleteCodexMcpServer(editingServer.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await authenticatedFetch('/api/codex/mcp/cli/add', {
|
const response = await authenticatedFetch('/api/codex/mcp/cli/add', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -560,6 +575,19 @@ export function useSettingsController({ isOpen, initialTab, projects, onClose }:
|
|||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error || 'Failed to save Codex MCP server');
|
throw new Error(result.error || 'Failed to save Codex MCP server');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!editingServer?.name || editingServer.name === serverData.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deleteCodexMcpServer(editingServer.name);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Saved Codex MCP server update but failed to remove the previous server entry.', {
|
||||||
|
previousServerName: editingServer.name,
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[deleteCodexMcpServer],
|
[deleteCodexMcpServer],
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user