From bba64b9048b94116e89693e1eb7d83d930e989ef Mon Sep 17 00:00:00 2001 From: "yanan.zhangyn" Date: Wed, 9 Sep 2026 19:48:20 +0800 Subject: [PATCH 1/2] fix(studio): simplify MCP credential editing --- frontend/src/App.tsx | 34 +- frontend/src/adk/client.ts | 52 ++ frontend/src/create/CustomCreate.css | 61 +-- frontend/src/create/CustomCreate.tsx | 207 ++++---- frontend/src/create/mcpAuth.ts | 187 +++----- frontend/src/create/types.ts | 11 +- frontend/src/i18n/resources/en-US/adk.json | 2 + frontend/src/i18n/resources/en-US/create.json | 12 +- frontend/src/i18n/resources/zh-CN/adk.json | 2 + frontend/src/i18n/resources/zh-CN/create.json | 12 +- frontend/tests/agentWorkspace.test.mjs | 20 +- frontend/tests/deploymentConfigUi.test.mjs | 5 +- frontend/tests/mcpAuth.test.mjs | 161 +++---- frontend/tests/runtimeAgentIdentity.test.mjs | 2 +- tests/cli/test_studio_rbac.py | 50 ++ veadk/cli/cli_frontend.py | 85 ++++ veadk/cli/legacy_runtime_recovery.py | 51 ++ .../{index-y89rQfXU.js => index-2IoWFVZy.js} | 452 +++++++++--------- ...B1zZ3C2s.js => CodeDiffEditor-BDqfIWmM.js} | 2 +- ...Ci.js => MarkdownPromptEditor-D1E1zJ8P.js} | 2 +- .../{arc-BmSNZeim.js => arc-ZuNETUkN.js} | 2 +- ...hannel-CK3FNdKP.js => channel-DaXLiLJ2.js} | 2 +- ...ex.es-BwpKNMlY.js => index.es-DOOh-GGD.js} | 2 +- ...n-DYdURk6H.js => jspdf.es.min-1nwUkr_m.js} | 6 +- ...{linear-FRN7TzCz.js => linear-B24m3Hy0.js} | 2 +- ...{index-BilOAbdo.css => index-WpRMTWy0.css} | 2 +- ...8p.js => abnfDiagram-N423BO3Z-Cfug2B5Z.js} | 2 +- ... architectureDiagram-T3A2C74G-CSeCcUVs.js} | 2 +- ...l.js => blockDiagram-VBNYF7ZC-BpAsW4fe.js} | 2 +- ...RQ1P.js => c4Diagram-5PPSVZJV-GCZ9h_ZE.js} | 2 +- ...w7u93fzV.js => chunk-2GRJ4B5K-ChOAdLxh.js} | 2 +- ...Df19aPp9.js => chunk-2Q5K7J3B-BEW8aaLP.js} | 2 +- ...CziPj31s.js => chunk-5RXB4S5H-65Qg4_pd.js} | 2 +- ...0VUj4cdX.js => chunk-5VM5RSS4-BJQk-vqy.js} | 2 +- ...BuYPTb-v.js => chunk-6Q2QTUOP-0cJyR1We.js} | 2 +- ...CdzaapU0.js => chunk-GF5L2VYU-XdmXa5xL.js} | 2 +- ...s5uAWi9x.js => chunk-JWPE2WC7-BOWacHkF.js} | 2 +- ...BwJsQpfI.js => chunk-KBJHAD2P-ANN-i8qK.js} | 2 +- ...CvZ-mg4G.js => chunk-RYQCIY6F-BZ1k65n3.js} | 2 +- ...DF1LpnDY.js => chunk-XXDRQBXY-Co_XyMXJ.js} | 2 +- .../mermaid/classDiagram-JCYQIIEL-B86LdNwl.js | 1 - .../mermaid/classDiagram-JCYQIIEL-CilCrNI_.js | 1 + .../classDiagram-v2-OCEON4UE-B86LdNwl.js | 1 - .../classDiagram-v2-OCEON4UE-CilCrNI_.js | 1 + ...a.js => cose-bilkent-JH36ORCC-MrsFj5M8.js} | 2 +- ...YIu5D_.js => cynefin-OW5HDTMX-DyqzZGaN.js} | 2 +- ...js => cynefinDiagram-MW4NZA55-Cqwp_191.js} | 2 +- ...Bh80CoKM.js => dagre-VZM6K2ZE-m8bWgWSU.js} | 2 +- ...jc3YK7.js => diagram-7IWD3JNH-1x58Mhkf.js} | 2 +- ...k5VMXY.js => diagram-B4RE2ZJO-D_8kKEYf.js} | 2 +- ...4oG5BD.js => diagram-LBJQPF4R-DkVd3naY.js} | 2 +- ...t3iGyV.js => diagram-Q27KOJAE-DP1aFYZq.js} | 2 +- ...u56O7S.js => diagram-UB23O5K3-w-oaFo7g.js} | 2 +- ...Du.js => ebnfDiagram-BXEA7PRR-D-t2EfIX.js} | 2 +- ...xrdp.js => erDiagram-JOGREHBK-D8OoBkzd.js} | 2 +- ...uo.js => flowDiagram-UKHOOZJN-ykvUzSEk.js} | 2 +- ...6.js => ganttDiagram-PKOTCBZU-Bd3Yc5sD.js} | 2 +- ...s => gitGraphDiagram-DS77QQ5N-BS-C-AY-.js} | 2 +- ...pi.js => infoDiagram-6WML65LV-DGy6FKA_.js} | 2 +- ...s => ishikawaDiagram-WSZJBQD7-CmoeOFGL.js} | 2 +- ...js => journeyDiagram-NVQOT4AX-CQx5Vz58.js} | 2 +- ...=> kanban-definition-27J2QSJJ-D4YfbbFj.js} | 2 +- ...e-Byx96n1y.js => mermaid.core-CWT43X_9.js} | 8 +- ...> mindmap-definition-FAOFIHXS-lEORyQUR.js} | 2 +- ...G_k.js => pegDiagram-VL7TDLO6-BFU5C5kT.js} | 2 +- ...edZ.js => pieDiagram-7S7Q4E2Y-BISe5AFn.js} | 2 +- ...s => quadrantDiagram-CIZ2JOQS-D77kOcg8.js} | 2 +- ...s => railroadDiagram-AXF67PYL-Di8EcQEa.js} | 2 +- ...> requirementDiagram-LRYGKXZP-D2c-c_nr.js} | 2 +- ....js => sankeyDiagram-W5VNT64P-D438Eimi.js} | 2 +- ...s => sequenceDiagram-SI44F4Z6-DPfDIcdT.js} | 2 +- ...yn.js => sizeCapture-X5ZJPWSS-2oaPReZA.js} | 2 +- ...s.js => stateDiagram-OKZ733FA-Btep9HxD.js} | 2 +- .../stateDiagram-v2-UEYNNEHI-BUH5KdnU.js | 1 - .../stateDiagram-v2-UEYNNEHI-BamfDw-a.js | 1 + ...x4nf.js => swimlanes-SLNWSIFB-Crc-mQaj.js} | 4 +- .../swimlanesDiagram-ULZ7WXOC-C2gcgADM.js | 8 + .../swimlanesDiagram-ULZ7WXOC-DpcZasdm.js | 8 - ... timeline-definition-Z64GVDOM-BhCYztY-.js} | 2 +- ...xC.js => vennDiagram-T6HMQDX7-BkUqrtiP.js} | 2 +- ...js => wardleyDiagram-T6FBY63Y-BWWPoS0d.js} | 2 +- ...js => xychartDiagram-ELKLHX3M-CDgbMMdV.js} | 2 +- veadk/webui/index.html | 4 +- veadk/webui/website-integration.js | 8 +- 84 files changed, 843 insertions(+), 721 deletions(-) rename veadk/webui/assets/app/{index-y89rQfXU.js => index-2IoWFVZy.js} (74%) rename veadk/webui/assets/chunks/{CodeDiffEditor-B1zZ3C2s.js => CodeDiffEditor-BDqfIWmM.js} (99%) rename veadk/webui/assets/chunks/{MarkdownPromptEditor-B5lw1jCi.js => MarkdownPromptEditor-D1E1zJ8P.js} (99%) rename veadk/webui/assets/chunks/{arc-BmSNZeim.js => arc-ZuNETUkN.js} (98%) rename veadk/webui/assets/chunks/{channel-CK3FNdKP.js => channel-DaXLiLJ2.js} (53%) rename veadk/webui/assets/chunks/{index.es-BwpKNMlY.js => index.es-DOOh-GGD.js} (99%) rename veadk/webui/assets/chunks/{jspdf.es.min-DYdURk6H.js => jspdf.es.min-1nwUkr_m.js} (99%) rename veadk/webui/assets/chunks/{linear-FRN7TzCz.js => linear-B24m3Hy0.js} (98%) rename veadk/webui/assets/styles/{index-BilOAbdo.css => index-WpRMTWy0.css} (85%) rename veadk/webui/assets/visualizations/mermaid/{abnfDiagram-N423BO3Z-DmJtql8p.js => abnfDiagram-N423BO3Z-Cfug2B5Z.js} (86%) rename veadk/webui/assets/visualizations/mermaid/{architectureDiagram-T3A2C74G-BC0iLzBL.js => architectureDiagram-T3A2C74G-CSeCcUVs.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{blockDiagram-VBNYF7ZC-wh52Ecel.js => blockDiagram-VBNYF7ZC-BpAsW4fe.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{c4Diagram-5PPSVZJV-B9klRQ1P.js => c4Diagram-5PPSVZJV-GCZ9h_ZE.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-2GRJ4B5K-w7u93fzV.js => chunk-2GRJ4B5K-ChOAdLxh.js} (93%) rename veadk/webui/assets/visualizations/mermaid/{chunk-2Q5K7J3B-Df19aPp9.js => chunk-2Q5K7J3B-BEW8aaLP.js} (66%) rename veadk/webui/assets/visualizations/mermaid/{chunk-5RXB4S5H-CziPj31s.js => chunk-5RXB4S5H-65Qg4_pd.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-5VM5RSS4-0VUj4cdX.js => chunk-5VM5RSS4-BJQk-vqy.js} (83%) rename veadk/webui/assets/visualizations/mermaid/{chunk-6Q2QTUOP-BuYPTb-v.js => chunk-6Q2QTUOP-0cJyR1We.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-GF5L2VYU-CdzaapU0.js => chunk-GF5L2VYU-XdmXa5xL.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-JWPE2WC7-s5uAWi9x.js => chunk-JWPE2WC7-BOWacHkF.js} (78%) rename veadk/webui/assets/visualizations/mermaid/{chunk-KBJHAD2P-BwJsQpfI.js => chunk-KBJHAD2P-ANN-i8qK.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{chunk-RYQCIY6F-CvZ-mg4G.js => chunk-RYQCIY6F-BZ1k65n3.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-XXDRQBXY-DF1LpnDY.js => chunk-XXDRQBXY-Co_XyMXJ.js} (53%) delete mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-JCYQIIEL-B86LdNwl.js create mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-JCYQIIEL-CilCrNI_.js delete mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-v2-OCEON4UE-B86LdNwl.js create mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-v2-OCEON4UE-CilCrNI_.js rename veadk/webui/assets/visualizations/mermaid/{cose-bilkent-JH36ORCC-BwttPwJa.js => cose-bilkent-JH36ORCC-MrsFj5M8.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{cynefin-OW5HDTMX-CfYIu5D_.js => cynefin-OW5HDTMX-DyqzZGaN.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{cynefinDiagram-MW4NZA55-h-hlAvXc.js => cynefinDiagram-MW4NZA55-Cqwp_191.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{dagre-VZM6K2ZE-Bh80CoKM.js => dagre-VZM6K2ZE-m8bWgWSU.js} (97%) rename veadk/webui/assets/visualizations/mermaid/{diagram-7IWD3JNH-CHjc3YK7.js => diagram-7IWD3JNH-1x58Mhkf.js} (96%) rename veadk/webui/assets/visualizations/mermaid/{diagram-B4RE2ZJO-Crk5VMXY.js => diagram-B4RE2ZJO-D_8kKEYf.js} (97%) rename veadk/webui/assets/visualizations/mermaid/{diagram-LBJQPF4R-B24oG5BD.js => diagram-LBJQPF4R-DkVd3naY.js} (94%) rename veadk/webui/assets/visualizations/mermaid/{diagram-Q27KOJAE-CHt3iGyV.js => diagram-Q27KOJAE-DP1aFYZq.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{diagram-UB23O5K3-C0u56O7S.js => diagram-UB23O5K3-w-oaFo7g.js} (95%) rename veadk/webui/assets/visualizations/mermaid/{ebnfDiagram-BXEA7PRR-288CQcDu.js => ebnfDiagram-BXEA7PRR-D-t2EfIX.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{erDiagram-JOGREHBK-Ccaixrdp.js => erDiagram-JOGREHBK-D8OoBkzd.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{flowDiagram-UKHOOZJN-DmwC0ruo.js => flowDiagram-UKHOOZJN-ykvUzSEk.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{ganttDiagram-PKOTCBZU-CDLstIj6.js => ganttDiagram-PKOTCBZU-Bd3Yc5sD.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{gitGraphDiagram-DS77QQ5N-B7nKkelP.js => gitGraphDiagram-DS77QQ5N-BS-C-AY-.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{infoDiagram-6WML65LV-B7-q34pi.js => infoDiagram-6WML65LV-DGy6FKA_.js} (69%) rename veadk/webui/assets/visualizations/mermaid/{ishikawaDiagram-WSZJBQD7-DWxeOhyJ.js => ishikawaDiagram-WSZJBQD7-CmoeOFGL.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{journeyDiagram-NVQOT4AX-CEEbz2Rm.js => journeyDiagram-NVQOT4AX-CQx5Vz58.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{kanban-definition-27J2QSJJ-4S3DxCBE.js => kanban-definition-27J2QSJJ-D4YfbbFj.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{mermaid.core-Byx96n1y.js => mermaid.core-CWT43X_9.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{mindmap-definition-FAOFIHXS-N5zHU5MK.js => mindmap-definition-FAOFIHXS-lEORyQUR.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{pegDiagram-VL7TDLO6-BOK0qG_k.js => pegDiagram-VL7TDLO6-BFU5C5kT.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{pieDiagram-7S7Q4E2Y-9it0uedZ.js => pieDiagram-7S7Q4E2Y-BISe5AFn.js} (96%) rename veadk/webui/assets/visualizations/mermaid/{quadrantDiagram-CIZ2JOQS-CTiy7YiT.js => quadrantDiagram-CIZ2JOQS-D77kOcg8.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{railroadDiagram-AXF67PYL-PGVg3Gs4.js => railroadDiagram-AXF67PYL-Di8EcQEa.js} (84%) rename veadk/webui/assets/visualizations/mermaid/{requirementDiagram-LRYGKXZP-BEni_WUb.js => requirementDiagram-LRYGKXZP-D2c-c_nr.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sankeyDiagram-W5VNT64P-CmNhKWbi.js => sankeyDiagram-W5VNT64P-D438Eimi.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sequenceDiagram-SI44F4Z6-ClGkLfJ7.js => sequenceDiagram-SI44F4Z6-DPfDIcdT.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sizeCapture-X5ZJPWSS-C7Roe_yn.js => sizeCapture-X5ZJPWSS-2oaPReZA.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{stateDiagram-OKZ733FA-BrlX_tes.js => stateDiagram-OKZ733FA-Btep9HxD.js} (96%) delete mode 100644 veadk/webui/assets/visualizations/mermaid/stateDiagram-v2-UEYNNEHI-BUH5KdnU.js create mode 100644 veadk/webui/assets/visualizations/mermaid/stateDiagram-v2-UEYNNEHI-BamfDw-a.js rename veadk/webui/assets/visualizations/mermaid/{swimlanes-SLNWSIFB-CR3Yx4nf.js => swimlanes-SLNWSIFB-Crc-mQaj.js} (99%) create mode 100644 veadk/webui/assets/visualizations/mermaid/swimlanesDiagram-ULZ7WXOC-C2gcgADM.js delete mode 100644 veadk/webui/assets/visualizations/mermaid/swimlanesDiagram-ULZ7WXOC-DpcZasdm.js rename veadk/webui/assets/visualizations/mermaid/{timeline-definition-Z64GVDOM-Dq9PHz3C.js => timeline-definition-Z64GVDOM-BhCYztY-.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{vennDiagram-T6HMQDX7-CYHQcSxC.js => vennDiagram-T6HMQDX7-BkUqrtiP.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{wardleyDiagram-T6FBY63Y-Dkoo2yzf.js => wardleyDiagram-T6FBY63Y-BWWPoS0d.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{xychartDiagram-ELKLHX3M-CSukDV3q.js => xychartDiagram-ELKLHX3M-CDgbMMdV.js} (99%) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 69e4fbcb9..4f51c1c65 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -34,6 +34,7 @@ import { getSession, getStudioAccess, getRuntimeStudioToolCapabilities, + getRuntimeMcpCredentials, getRuntimes, listApps, listEnvironments, @@ -150,7 +151,10 @@ import { AgentCreationModePicker } from "./create/AgentCreationModePicker"; import { CodePackageCreate } from "./create/CodePackageCreate"; import { MigrationWorkspace } from "./migrations/MigrationWorkspace"; import type { AgentDraft } from "./create/types"; -import { configuredMcpEnvKeys } from "./create/mcpAuth"; +import { + configuredMcpEnvKeys, + hydrateMcpCredentialValues, +} from "./create/mcpAuth"; import { hydrateRuntimeModelSelection, isRuntimeModelSelectionEnv, @@ -7274,11 +7278,33 @@ export default function App() { hydratedDraft, arkModelIds, ); + let editorDraft = classifiedDraft; + if (configuredMcpEnvKeys(classifiedDraft).length > 0) { + try { + const credentials = await getRuntimeMcpCredentials({ + runtimeId: capability.runtime.runtimeId, + region: capability.runtime.region, + appName: capability.agent.appName, + etag: capability.etag, + }); + editorDraft = hydrateMcpCredentialValues( + classifiedDraft, + credentials, + ); + } catch (credentialError) { + setError( + credentialError instanceof Error + ? credentialError.message + : appText("errors.runtimeDeploymentConfigUnavailable"), + ); + return; + } + } exitAgentDetailContext(); - setImportedDraft(classifiedDraft); + setImportedDraft(editorDraft); setCustomCreateMode("custom"); setCustomCreationSurface( - classifiedDraft.dynamicAgentDelegation === true + editorDraft.dynamicAgentDelegation === true ? "vulcan" : "traditional", ); @@ -7301,7 +7327,7 @@ export default function App() { capability.editMode === "source-preserving" ? "source-preserving" : "regenerate", - configuredMcpEnvKeys: configuredMcpEnvKeys(classifiedDraft), + configuredMcpEnvKeys: configuredMcpEnvKeys(editorDraft), configuredRuntimeEnvKeys: capability.runtime.configuredEnvKeys, }); diff --git a/frontend/src/adk/client.ts b/frontend/src/adk/client.ts index c1a402ba9..da3a485d4 100644 --- a/frontend/src/adk/client.ts +++ b/frontend/src/adk/client.ts @@ -30,6 +30,7 @@ import { import type { AgentProject } from "../create/project"; import type { AgentDraft, + McpCredentialValue, NetworkConfig, SelectedSkill, } from "../create/types"; @@ -4578,6 +4579,57 @@ export interface RuntimeUpdateCapability { } | null; } +/** Fetch the exact MCP credentials for one authorized update snapshot. */ +export async function getRuntimeMcpCredentials({ + runtimeId, + region, + appName, + etag, + signal, +}: { + runtimeId: string; + region: string; + appName: string; + etag: string; + signal?: AbortSignal; +}): Promise { + const res = await apiFetch("/web/runtime-mcp-credentials", { + method: "POST", + cache: "no-store", + signal, + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ runtimeId, region, appName, etag }), + }); + if (!res.ok) { + throw new Error( + await httpErrorMessage(res, adkT("client.loadMcpCredentialsFailed")), + ); + } + const payload = (await res.json().catch(() => null)) as { + credentials?: unknown; + } | null; + if (!Array.isArray(payload?.credentials)) { + throw new Error(adkT("client.invalidMcpCredentials")); + } + return payload.credentials.map((item) => { + if (!item || typeof item !== "object") { + throw new Error(adkT("client.invalidMcpCredentials")); + } + const raw = item as Record; + const credential = { + agentName: raw.agentName, + name: raw.name, + url: raw.url, + authTokenEnv: raw.authTokenEnv, + value: raw.value, + }; + if (Object.values(credential).some((value) => typeof value !== "string")) { + throw new Error(adkT("client.invalidMcpCredentials")); + } + return credential as McpCredentialValue; + }); +} + interface RuntimeUpdateCapabilityRequest { runtimeId: string; region: string; diff --git a/frontend/src/create/CustomCreate.css b/frontend/src/create/CustomCreate.css index a8da4f158..f70d4f472 100644 --- a/frontend/src/create/CustomCreate.css +++ b/frontend/src/create/CustomCreate.css @@ -3752,50 +3752,39 @@ line-height: 1.5; color: hsl(var(--muted-foreground)); } -.cw-mcp-auth-state { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - min-height: 32px; - padding: 7px 10px; - border: 1px solid hsl(var(--border)); - border-radius: 8px; - background: hsl(var(--muted)); - color: hsl(var(--muted-foreground)); - font-size: 12px; - line-height: 1.45; +.cw-mcp-token-field { + position: relative; } -.cw-mcp-auth-state button { - flex: 0 0 auto; - min-height: 28px; - padding: 0 9px; - border: 1px solid hsl(var(--border)); +.cw-mcp-token-field .cw-input { + padding-right: 40px; +} +.cw-mcp-token-toggle { + position: absolute; + top: 50%; + right: 4px; + display: inline-grid; + width: 28px; + height: 28px; + padding: 0; + border: 0; border-radius: 6px; - background: hsl(var(--panel)); - color: hsl(var(--foreground)); + background: transparent; + color: hsl(var(--muted-foreground)); cursor: pointer; - font: inherit; + place-items: center; + transform: translateY(-50%); } -.cw-mcp-auth-state button:hover { - background: hsl(var(--accent)); +.cw-mcp-token-toggle:hover { + background: hsl(var(--muted)); + color: hsl(var(--foreground)); } -.cw-mcp-auth-state button:focus-visible { +.cw-mcp-token-toggle:focus-visible { outline: 2px solid hsl(var(--primary)); outline-offset: 1px; } -.cw-mcp-auth-state.is-warning { - align-items: flex-start; - border-color: hsl(var(--destructive) / 0.35); - background: hsl(var(--destructive) / 0.06); - color: hsl(var(--foreground)); -} -.cw-mcp-auth-actions { - display: flex; - flex: 0 0 auto; - flex-wrap: wrap; - justify-content: flex-end; - gap: 6px; +.cw-mcp-token-toggle svg { + width: 16px; + height: 16px; } .cw-mcp-warning { display: flex; diff --git a/frontend/src/create/CustomCreate.tsx b/frontend/src/create/CustomCreate.tsx index 026351fe3..2540f5100 100644 --- a/frontend/src/create/CustomCreate.tsx +++ b/frontend/src/create/CustomCreate.tsx @@ -93,18 +93,12 @@ import { import { localPickerMatches } from "./localPickerSearch"; import { draftToYaml } from "./configYaml"; import { - confirmMcpCredentialReuse, - clearMcpConfiguredAuth, deploymentMcpSecretValues, type McpConfigurationConflict, mcpAuthTokenInputValue, - mcpCredentialActionRequired, mcpConfigurationConflict, - mcpCredentialReuseValues, mcpUrlNeedsPathWarning, prepareMcpAuth, - removeMcpCredentialForChangedUrl, - replaceMcpCredentialForChangedUrl, removedConfiguredMcpEnvKeys, sourcePreservingMcpSecretValues, updateMcpAuthTokenInput, @@ -1909,6 +1903,34 @@ function VikingMemorySelect({ * (http / stdio) and shows the matching fields. http -> url + optional * bearer token; stdio -> command + space-separated args. Optional name. * ---------------------------------------------------------------- */ +function McpTokenVisibilityIcon({ hidden }: { hidden: boolean }) { + return ( + + ); +} + function McpToolEditor({ tools, conflict, @@ -1922,11 +1944,20 @@ function McpToolEditor({ }) { const { t } = useTranslation("create"); const conflictErrorId = useId(); + const [revealedTokenIndex, setRevealedTokenIndex] = useState( + null, + ); const visibleConflict = showConflict ? conflict : null; const update = (i: number, p: Partial) => onChange(tools.map((tool, idx) => (idx === i ? { ...tool, ...p } : tool))); - const remove = (i: number) => onChange(tools.filter((_, idx) => idx !== i)); + const remove = (i: number) => { + setRevealedTokenIndex((current) => { + if (current == null || current < i) return current; + return current === i ? null : current - 1; + }); + onChange(tools.filter((_, idx) => idx !== i)); + }; const add = () => onChange([...tools, { name: "", transport: "http", url: "" }]); @@ -2024,119 +2055,49 @@ function McpToolEditor({

)} - - onChange( - tools.map((tool, index) => - index === i - ? updateMcpAuthTokenInput(tool, e.target.value) - : tool, - ), - ) - } - /> - {tool.credentialUpdate === "pending" && ( -
+ + onChange( + tools.map((tool, index) => + index === i + ? updateMcpAuthTokenInput(tool, e.target.value) + : tool, + ), + ) + } + /> + - - -
- - )} - {tool.credentialUpdate === "reuse" && ( -
- {t("traditional.mcp.reuseHint")} - -
- )} - {tool.credentialConfigured && - !tool.authToken && - !tool.credentialUpdate && ( -
- {t("traditional.mcp.credentialConfigured")} - -
- )} +