From a5f09e18a82c93204916bd3c3a4570895516e4dd Mon Sep 17 00:00:00 2001 From: Luis de Dios Date: Tue, 17 Mar 2026 10:17:02 +0100 Subject: [PATCH] :tada: Make the mcp plugin switching between tabs work correctly (#8597) * :sparkles: Make the MCP plugin switching between tabs work correctly * :tada: Show notification when the plugin is loaded in another tab * :paperclip: PR changes * :sparkles: Add events --- .continue/mcpServers/new-mcp-server.yaml | 10 --- frontend/src/app/main/data/workspace.cljs | 10 ++- frontend/src/app/main/data/workspace/mcp.cljs | 63 ++++++++++++++----- .../app/main/ui/settings/integrations.cljs | 8 +-- frontend/translations/en.po | 6 ++ frontend/translations/es.po | 6 ++ 6 files changed, 74 insertions(+), 29 deletions(-) delete mode 100644 .continue/mcpServers/new-mcp-server.yaml diff --git a/.continue/mcpServers/new-mcp-server.yaml b/.continue/mcpServers/new-mcp-server.yaml deleted file mode 100644 index 0e32aa6d45..0000000000 --- a/.continue/mcpServers/new-mcp-server.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: New MCP server -version: 0.0.1 -schema: v1 -mcpServers: - - name: New MCP server - command: npx - args: - - -y - - - env: {} diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index defc643443..fa2e04fe9d 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -373,7 +373,15 @@ (when (contains? cf/flags :mcp) (->> mbc/stream - (rx/filter (mbc/type? :mcp-enabled-change)) + (rx/filter (mbc/type? :mcp-enabled-change-connection)) + (rx/map deref) + (rx/mapcat (fn [value] + (rx/of (mcp/update-mcp-connection value) + (mcp/disconnect-mcp)))))) + + (when (contains? cf/flags :mcp) + (->> mbc/stream + (rx/filter (mbc/type? :mcp-enabled-change-status)) (rx/map deref) (rx/map mcp/update-mcp-status))) diff --git a/frontend/src/app/main/data/workspace/mcp.cljs b/frontend/src/app/main/data/workspace/mcp.cljs index 72544ad7cc..63e7de7516 100644 --- a/frontend/src/app/main/data/workspace/mcp.cljs +++ b/frontend/src/app/main/data/workspace/mcp.cljs @@ -9,10 +9,14 @@ [app.common.logging :as log] [app.common.uri :as u] [app.config :as cf] + [app.main.broadcast :as mbc] + [app.main.data.event :as ev] + [app.main.data.notifications :as ntf] [app.main.data.plugins :as dp] [app.main.repo :as rp] [app.main.store :as st] [app.plugins.register :refer [mcp-plugin-id]] + [app.util.i18n :refer [tr]] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -34,6 +38,37 @@ [event] (= (ptk/type event) :app.main.data.workspace/finalize-workspace)) +(defn disconnect-mcp + [] + (st/emit! (ptk/data-event ::disconnect))) + +(defn connect-mcp + [] + (ptk/reify ::connect-mcp + ptk/WatchEvent + (watch [_ _ stream] + (mbc/emit! :mcp-enabled-change-connection false) + (->> stream + (rx/filter (ptk/type? ::disconnect)) + (rx/take 1) + (rx/map #(ptk/data-event ::connect)))))) + +(defn manage-notification + [mcp-enabled? mcp-connected?] + (if mcp-enabled? + (if mcp-connected? + (rx/of (ntf/hide)) + (rx/of (ntf/dialog :content (tr "notifications.mcp.active-tab-switching.text") + :cancel {:label (tr "labels.dismiss") + :callback #(st/emit! (ntf/hide) + (ptk/event ::ev/event {::ev/name "confirm-mcp-tab-switch" + ::ev/origin "workspace-notification"}))} + :accept {:label (tr "labels.switch") + :callback #(st/emit! (connect-mcp) + (ptk/event ::ev/event {::ev/name "dismiss-mcp-tab-switch" + ::ev/origin "workspace-notification"}))}))) + (rx/of (ntf/hide)))) + (defn update-mcp-status [value] (ptk/reify ::update-mcp-status @@ -42,18 +77,26 @@ (update-in state [:profile :props] assoc :mcp-enabled value)) ptk/WatchEvent - (watch [_ _ _] - (case value - true (rx/of (ptk/data-event ::connect)) - false (rx/of (ptk/data-event ::disconnect)) - nil)))) + (watch [_ state _] + (rx/merge + (let [mcp-connected? (-> state :workspace-local :mcp :connected)] + (manage-notification value mcp-connected?)) + (case value + true (rx/of (ptk/data-event ::connect)) + false (rx/of (ptk/data-event ::disconnect)) + nil))))) (defn update-mcp-connection [value] (ptk/reify ::update-mcp-plugin-connection ptk/UpdateEvent (update [_ state] - (update-in state [:workspace-local :mcp] assoc :connected value)))) + (update-in state [:workspace-local :mcp] assoc :connected value)) + + ptk/WatchEvent + (watch [_ state _] + (let [mcp-enabled? (-> state :profile :props :mcp-enabled)] + (manage-notification mcp-enabled? value))))) (defn init-mcp! [stream] @@ -94,14 +137,6 @@ (rx/take-until stopper) (rx/subs! #(cb))))))}})))))) -(defn disconnect-mcp - [] - (st/emit! (ptk/data-event ::disconnect))) - -(defn connect-mcp - [] - (st/emit! (ptk/data-event ::connect))) - (defn init-mcp-connection [] (ptk/reify ::init-mcp-connection diff --git a/frontend/src/app/main/ui/settings/integrations.cljs b/frontend/src/app/main/ui/settings/integrations.cljs index d84eef10fc..f4b820e0b3 100644 --- a/frontend/src/app/main/ui/settings/integrations.cljs +++ b/frontend/src/app/main/ui/settings/integrations.cljs @@ -279,7 +279,7 @@ (ev/event {::ev/name "enable-mcp" ::ev/origin "integrations" :source "key-creation"})) - (mbc/emit! :mcp-enabled-change true) + (mbc/emit! :mcp-enabled-change-status true) (reset! created? true)))] [:div {:class (stl/css :modal-overlay)} @@ -320,7 +320,7 @@ (du/update-profile-props {:mcp-enabled true}) (ev/event {::ev/name "regenerate-mcp-key" ::ev/origin "integrations"})) - (mbc/emit! :mcp-enabled-change true) + (mbc/emit! :mcp-enabled-change-status true) (reset! created? true)))] [:div {:class (stl/css :modal-overlay)} @@ -431,7 +431,7 @@ (ev/event {::ev/name (if (true? value) "enable-mcp" "disable-mcp") ::ev/origin "integrations" :source "toggle"})) - (mbc/emit! :mcp-enabled-change value))) + (mbc/emit! :mcp-enabled-change-status value))) handle-generate-mcp-key (mf/use-fn @@ -449,7 +449,7 @@ mdata {:on-success #(st/emit! (du/fetch-access-tokens))}] (st/emit! (du/delete-access-token (with-meta params mdata)) (du/update-profile-props {:mcp-enabled false})) - (mbc/emit! :mcp-enabled-change false)))) + (mbc/emit! :mcp-enabled-change-status false)))) on-copy-to-clipboard (mf/use-fn diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 96c544612c..ebe68d176b 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2514,6 +2514,9 @@ msgstr "Director" msgid "labels.discard" msgstr "Discard" +msgid "labels.dismiss" +msgstr "Dismiss" + #: src/app/main/ui/settings/feedback.cljs:134, src/app/main/ui/static.cljs:409 msgid "labels.download" msgstr "Download %s" @@ -3830,6 +3833,9 @@ msgstr "Invitation sent successfully" msgid "notifications.invitation-link-copied" msgstr "Invitation link copied" +msgid "notifications.mcp.active-tab-switching.text" +msgstr "MCP is active in another tab. Switch here?" + #: src/app/main/ui/settings/delete_account.cljs:24 msgid "notifications.profile-deletion-not-allowed" msgstr "You can't delete your profile. Reassign your teams before proceed." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 105d279647..2721f60649 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2471,6 +2471,9 @@ msgstr "Director" msgid "labels.discard" msgstr "Descartar" +msgid "labels.dismiss" +msgstr "Cancelar" + #: src/app/main/ui/settings/feedback.cljs:134, src/app/main/ui/static.cljs:409 msgid "labels.download" msgstr "Descargar %s" @@ -3787,6 +3790,9 @@ msgstr "Invitación enviada con éxito" msgid "notifications.invitation-link-copied" msgstr "Enlace de invitacion copiado" +msgid "notifications.mcp.active-tab-switching.text" +msgstr "MCP está activo en otra pestaña. ¿Cambiar a esta?" + #: src/app/main/ui/settings/delete_account.cljs:24 msgid "notifications.profile-deletion-not-allowed" msgstr "No puedes borrar tu perfil. Reasigna tus equipos antes de seguir."