From 2ea5e8e9b95073c59547ce3e5ae916f1076929ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=A4=A7=E7=86=8A?=
<49681654+xzxlove@users.noreply.github.com>
Date: Sat, 15 Aug 2026 14:44:46 +0800
Subject: [PATCH] feat(settings): add update check and MCP uninstall
---
apps/desktop/src/App.vue | 2 +
.../editor/EditorSettingsDialog.vue | 55 +++++++++++++++--
.../components/settings/ChangelogPanel.vue | 20 ++++++-
apps/desktop/src/i18n/locales/en.ts | 7 ++-
apps/desktop/src/i18n/locales/zh-CN.ts | 7 ++-
.../__tests__/mcp/mcpServerManagement.spec.ts | 18 ++++++
apps/desktop/src/lib/backend/api.ts | 1 +
apps/desktop/src/lib/backend/http.ts | 5 ++
apps/desktop/src/lib/backend/tauri.ts | 5 ++
.../__tests__/settingsAboutUpdate.spec.ts | 18 ++++++
src-tauri/src/commands/mcp.rs | 59 ++++++++++++++++++-
src-tauri/src/lib.rs | 1 +
12 files changed, 189 insertions(+), 9 deletions(-)
create mode 100644 apps/desktop/src/lib/__tests__/mcp/mcpServerManagement.spec.ts
create mode 100644 apps/desktop/src/lib/settings/__tests__/settingsAboutUpdate.spec.ts
diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue
index a4b58c11cc..03e774aa65 100644
--- a/apps/desktop/src/App.vue
+++ b/apps/desktop/src/App.vue
@@ -2652,8 +2652,10 @@ onUnmounted(() => {
:initial-section="settingsInitialSection"
:navigation-request-id="settingsNavigationRequestId"
:app-version="appVersion"
+ :checking-updates="checkingUpdates"
class="flex-1 min-h-0"
@update:open="(open: boolean) => (open ? activateSettingsPage() : closeSettingsPage())"
+ @check-updates="checkUpdates()"
/>
();
const emit = defineEmits<{
"update:open": [value: boolean];
+ "check-updates": [];
}>();
const isSettingsPage = computed(() => props.variant === "page");
@@ -1723,7 +1726,7 @@ async function exportDebugLogs() {
// ---------- MCP Server ----------
type McpConfigTab = "claude" | "cursor" | "trae" | "vscode" | "windsurf" | "codex" | "opencode" | "cherry-studio";
-type McpCopyKind = "install" | `${McpConfigTab}-config`;
+type McpCopyKind = "install" | "uninstall" | `${McpConfigTab}-config`;
const mcpStatus = ref(null);
const mcpStatusLoading = ref(false);
@@ -1736,6 +1739,7 @@ const mcpPolicyLoading = ref(false);
const mcpPolicySaving = ref(false);
const mcpPolicyLoadError = ref("");
const mcpInstalling = ref(false);
+const mcpUninstalling = ref(false);
const mcpInstallMessage = ref("");
const mcpInstallError = ref(false);
const mcpExecutionMode = computed(() => mcpExecutionModeFromPolicy(settingsStore.mcpGlobalPolicy));
@@ -1854,6 +1858,8 @@ const mcpCommand = computed(() => {
return mcpStatus.value.installed ? mcpStatus.value.update_command : mcpStatus.value.install_command;
});
+const mcpUninstallCommand = computed(() => mcpStatus.value?.uninstall_command || "npm uninstall -g @dbx-app/mcp-server");
+
async function refreshMcpStatus() {
if (mcpStatusLoading.value) return;
mcpStatusLoading.value = true;
@@ -1888,7 +1894,7 @@ async function copyMcpText(kind: McpCopyKind, value: string) {
}
async function installMcp() {
- if (mcpInstalling.value) return;
+ if (mcpInstalling.value || mcpUninstalling.value) return;
mcpInstalling.value = true;
mcpInstallMessage.value = "";
mcpInstallError.value = false;
@@ -1911,6 +1917,27 @@ async function installMcp() {
}
}
+async function uninstallMcp() {
+ if (mcpInstalling.value || mcpUninstalling.value || !mcpStatus.value?.installed) return;
+ if (!window.confirm(t("settings.mcpUninstallConfirm"))) return;
+ mcpUninstalling.value = true;
+ mcpInstallMessage.value = "";
+ mcpInstallError.value = false;
+ try {
+ mcpInstallMessage.value = await uninstallMcpServer();
+ await refreshMcpStatus();
+ } catch (e: any) {
+ mcpInstallMessage.value = t("settings.mcpUninstallFailed", { error: e?.message || String(e) });
+ mcpInstallError.value = true;
+ } finally {
+ mcpUninstalling.value = false;
+ window.setTimeout(() => {
+ mcpInstallMessage.value = "";
+ mcpInstallError.value = false;
+ }, 3000);
+ }
+}
+
// ---------- WebDAV Sync ----------
const webdavEndpoint = ref(localStorage.getItem("dbx-webdav-endpoint") || "");
const webdavUsername = ref(localStorage.getItem("dbx-webdav-username") || "");
@@ -2873,7 +2900,7 @@ const aiSupportsAnthropicApiStyle = computed(() => aiEditProvider.value === "cus
const aiCliMcpNeedsInstall = computed(() => aiIsCliProvider.value && (!mcpStatus.value || !mcpStatus.value.installed));
const aiCliMcpCanInstall = computed(() => {
const status = mcpStatus.value;
- return !mcpInstalling.value && !!status?.npm_available && (!status.installed || status.update_available);
+ return !mcpInstalling.value && !mcpUninstalling.value && !!status?.npm_available && (!status.installed || status.update_available);
});
const aiCliMcpActionLabel = computed(() => {
if (!mcpStatus.value?.installed) return t("settings.mcpInstallButton");
@@ -6273,7 +6300,7 @@ onUnmounted(() => {
-
+
+
+
+
+ {{ mcpUninstallCommand }}
+
+
+
+
+
+
+
+
+ {{ mcpUninstalling ? t("settings.mcpUninstalling") : t("settings.mcpUninstallButton") }}
+
+
+
+
{{ t("settings.mcpConfigOptionsHint") }}
@@ -6611,7 +6656,7 @@ onUnmounted(() => {
-
+
diff --git a/apps/desktop/src/components/settings/ChangelogPanel.vue b/apps/desktop/src/components/settings/ChangelogPanel.vue
index fd80678aa6..d52358eb9f 100644
--- a/apps/desktop/src/components/settings/ChangelogPanel.vue
+++ b/apps/desktop/src/components/settings/ChangelogPanel.vue
@@ -1,7 +1,7 @@