()
| 595 | } |
| 596 | |
| 597 | const saveServer = async () => { |
| 598 | if (!validateServerUrl(serverUrl)) return |
| 599 | const body = { |
| 600 | name: serverName, |
| 601 | serverUrl, |
| 602 | iconSrc: iconSrc || undefined, |
| 603 | color: color || undefined, |
| 604 | authType |
| 605 | } |
| 606 | if (authType === MCP_AUTH_TYPE.CUSTOM_HEADERS) { |
| 607 | const hdrs = {} |
| 608 | for (const { key, value } of headers) { |
| 609 | if (!key) continue |
| 610 | // Partial mask in a value is almost certainly an editing mistake |
| 611 | // (user typed over part of the placeholder). Exact MASK_TOKEN is |
| 612 | // the documented "keep existing" signal — pass it through. |
| 613 | if (value && value !== MASK_TOKEN && value.includes(MASK_TOKEN)) { |
| 614 | showSnackbar(`Header "${key}" value still contains redacted characters. Clear and retype the full value.`, 'error') |
| 615 | return |
| 616 | } |
| 617 | hdrs[key] = value |
| 618 | } |
| 619 | if (Object.keys(hdrs).length > 0) body.authConfig = { headers: hdrs } |
| 620 | } else { |
| 621 | body.authConfig = null // Clear authConfig if switching to no authentication |
| 622 | } |
| 623 | |
| 624 | // Step 1: update |
| 625 | try { |
| 626 | await customMcpServersApi.updateCustomMcpServer(serverId, body) |
| 627 | } catch (error) { |
| 628 | showSnackbar(`Failed to save MCP Server: ${getErrorMsg(error)}`, 'error') |
| 629 | onCancel() |
| 630 | return |
| 631 | } |
| 632 | |
| 633 | // Step 2: authorize with the new config |
| 634 | setAuthorizing(true) |
| 635 | try { |
| 636 | const resp = await customMcpServersApi.authorizeCustomMcpServer(serverId) |
| 637 | let toolsCount = 0 |
| 638 | if (resp?.data?.tools) { |
| 639 | try { |
| 640 | const parsed = JSON.parse(resp.data.tools) || {} |
| 641 | const tools = Array.isArray(parsed?.tools) ? parsed.tools : [] |
| 642 | setDiscoveredTools(tools) |
| 643 | toolsCount = tools.length |
| 644 | } catch { |
| 645 | setDiscoveredTools([]) |
| 646 | } |
| 647 | } |
| 648 | setStatus(resp?.data?.status || MCP_SERVER_STATUS.AUTHORIZED) |
| 649 | setIsEditing(false) |
| 650 | showSnackbar(`Saved and reconnected! Discovered ${toolsCount} tools`) |
| 651 | } catch (error) { |
| 652 | setStatus(MCP_SERVER_STATUS.ERROR) |
| 653 | setIsEditing(false) |
| 654 | showSnackbar(`Saved, but failed to reconnect: ${getErrorMsg(error)}`, 'error') |
no test coverage detected