From fc0d576f6d3ede9b94c9cd366f04d92254796d75 Mon Sep 17 00:00:00 2001 From: Hand Sonic <8078023+HandSonic@users.noreply.github.com> Date: Sat, 26 Sep 2026 00:29:23 +0800 Subject: [PATCH] feat(web): manage MCP HTTP access from settings --- .../editor/EditorSettingsDialog.vue | 96 +++- apps/desktop/src/i18n/locales/az.ts | 9 +- apps/desktop/src/i18n/locales/en.ts | 9 +- apps/desktop/src/i18n/locales/es.ts | 9 +- apps/desktop/src/i18n/locales/it.ts | 9 +- apps/desktop/src/i18n/locales/ja.ts | 9 +- apps/desktop/src/i18n/locales/ko.ts | 9 +- apps/desktop/src/i18n/locales/pt-BR.ts | 9 +- apps/desktop/src/i18n/locales/ru.ts | 9 +- apps/desktop/src/i18n/locales/tr.ts | 9 +- apps/desktop/src/i18n/locales/zh-CN.ts | 9 +- apps/desktop/src/i18n/locales/zh-TW.ts | 9 +- apps/desktop/src/lib/backend/api.ts | 3 + apps/desktop/src/lib/backend/http.ts | 16 + apps/desktop/src/lib/backend/tauri.ts | 21 +- crates/dbx-core/src/persistence/storage.rs | 42 ++ crates/dbx-mcp/src/http.rs | 23 +- crates/dbx-mcp/src/http_auth.rs | 285 ++++++++++-- crates/dbx-web/src/auth.rs | 5 + crates/dbx-web/src/demo.rs | 3 + crates/dbx-web/src/main.rs | 90 ++-- crates/dbx-web/src/routes/app_settings.rs | 78 ++-- crates/dbx-web/src/routes/migration.rs | 6 + crates/dbx-web/src/routes/mq.rs | 1 + crates/dbx-web/src/state.rs | 2 + crates/dbx-web/src/web_mcp.rs | 417 ++++++++++++++++++ docs/content/docs/mcp.cn.mdx | 4 +- docs/content/docs/mcp.mdx | 4 +- packages/mcp-server/README.md | 4 +- 29 files changed, 1040 insertions(+), 159 deletions(-) create mode 100644 crates/dbx-web/src/web_mcp.rs diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 0a8da29f6..411f9a81f 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -140,6 +140,8 @@ import { mcpHttpServerStatus, rotateMcpHttpServerToken, loadWebMcpHttpStatus, + saveWebMcpHttpSettings, + rotateWebMcpToken, forgetSnippetSavedToken, forgetWebdavSyncSecretsPassphrase, forgetWebdavSavedPassword, @@ -173,6 +175,7 @@ import { type McpHttpServerSettings, type McpHttpServerStatus, type WebMcpHttpStatus, + type WebMcpHttpSettings, type McpServerStatus, type SnippetProvider, type SnippetSyncConfig, @@ -3303,6 +3306,11 @@ const mcpHttpSettings = ref({ }); const mcpHttpStatus = ref(null); const webMcpHttpStatus = ref(null); +const webMcpEnabledDraft = ref(false); +const webMcpAllowedHostsText = ref(""); +const webMcpAllowedOriginsText = ref(""); +const webMcpSaving = ref(false); +const webMcpError = ref(""); const mcpHttpLoading = ref(false); const mcpHttpSaving = ref(false); const mcpHttpError = ref(""); @@ -3808,7 +3816,12 @@ async function loadMcpHttpSettings() { mcpHttpError.value = ""; try { if (isWeb) { - webMcpHttpStatus.value = await loadWebMcpHttpStatus(); + const status = await loadWebMcpHttpStatus(); + webMcpHttpStatus.value = status; + webMcpEnabledDraft.value = status.enabled; + webMcpAllowedHostsText.value = status.allowedHosts.join("\n"); + webMcpAllowedOriginsText.value = status.allowedOrigins.join("\n"); + webMcpError.value = ""; return; } const [settings, status] = await Promise.all([loadMcpHttpServerSettings(), mcpHttpServerStatus()]); @@ -3824,6 +3837,41 @@ async function loadMcpHttpSettings() { } } +async function saveWebMcpSettings() { + if (webMcpSaving.value || webMcpHttpStatus.value?.deploymentManaged) return; + webMcpSaving.value = true; + webMcpError.value = ""; + const settings: WebMcpHttpSettings = { + enabled: webMcpEnabledDraft.value, + allowedHosts: mcpHttpList(webMcpAllowedHostsText.value), + allowedOrigins: mcpHttpList(webMcpAllowedOriginsText.value), + }; + try { + const status = await saveWebMcpHttpSettings(settings); + webMcpHttpStatus.value = status; + webMcpEnabledDraft.value = status.enabled; + webMcpAllowedHostsText.value = status.allowedHosts.join("\n"); + webMcpAllowedOriginsText.value = status.allowedOrigins.join("\n"); + } catch (error: unknown) { + webMcpError.value = formatMcpHttpError(error); + } finally { + webMcpSaving.value = false; + } +} + +async function rotateWebMcpAccessToken() { + if (webMcpSaving.value || webMcpHttpStatus.value?.deploymentManaged) return; + webMcpSaving.value = true; + webMcpError.value = ""; + try { + webMcpHttpStatus.value = await rotateWebMcpToken(); + } catch (error: unknown) { + webMcpError.value = formatMcpHttpError(error); + } finally { + webMcpSaving.value = false; + } +} + async function saveMcpHttpSettings() { if (mcpHttpSaving.value) return; mcpHttpSaving.value = true; @@ -9737,25 +9785,63 @@ LIMIT 100;
-
+
{{ webMcpHttpStatus?.enabled ? t("settings.mcpHttpStatusLabelEnabled") : t("settings.mcpHttpStatusLabelDisabled") }}

{{ t("settings.mcpHttpWebServiceDescription") }}

+

{{ mcpHttpError }}