Allow for reconnections to MCP server

This commit is contained in:
alonso.torres
2026-03-23 16:27:37 +01:00
committed by Alonso Torres
parent dd6a3c291a
commit 937032c790
5 changed files with 66 additions and 19 deletions

View File

@@ -377,7 +377,7 @@
(rx/map deref)
(rx/mapcat (fn [value]
(rx/of (mcp/update-mcp-connection value)
(mcp/disconnect-mcp))))))
(mcp/user-disconnect-mcp))))))
(when (contains? cf/flags :mcp)
(->> mbc/stream

View File

@@ -17,9 +17,12 @@
[app.main.store :as st]
[app.plugins.register :refer [mcp-plugin-id]]
[app.util.i18n :refer [tr]]
[app.util.timers :as ts]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
(def retry-interval 10000)
(log/set-level! :info)
(def ^:private default-manifest
@@ -34,13 +37,53 @@
"comment:read" "comment:write"
"content:write" "content:read"}})
(defonce interval-sub (atom nil))
(defn finalize-workspace?
[event]
(= (ptk/type event) :app.main.data.workspace/finalize-workspace))
(defn disconnect-mcp
(defn set-mcp-active
[value]
(ptk/reify ::set-mcp-active
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-local :mcp :active] value))))
(defn start-reconnect-watcher!
[]
(st/emit! (ptk/data-event ::disconnect)))
(st/emit! (set-mcp-active true))
(when (nil? @interval-sub)
(reset!
interval-sub
(ts/interval
retry-interval
(fn []
;; Try to reconnect if active and not connected
(when-not (contains? #{"connecting" "connected"}
(-> @st/state :workspace-local :mcp :connection))
(.log js/console "Reconnecting to MCP...")
(st/emit! (ptk/data-event ::connect))))))))
(defn stop-reconnect-watcher!
[]
(st/emit! (set-mcp-active false))
(when @interval-sub
(rx/dispose! @interval-sub)
(reset! interval-sub nil)))
;; This event will arrive when the user selects disconnect on the menu
;; or there is a broadcast message for disconnection
(defn user-disconnect-mcp
[]
(ptk/reify ::remote-disconnect-mcp
ptk/WatchEvent
(watch [_ _ _]
(rx/of (ptk/data-event ::disconnect)))
ptk/EffectEvent
(effect [_ _ _]
(stop-reconnect-watcher!))))
(defn connect-mcp
[]
@@ -58,12 +101,13 @@
(ptk/reify ::manage-mcp-notification
ptk/WatchEvent
(watch [_ state _]
(let [mcp-connected? (true? (-> state :workspace-local :mcp :connection))
(let [mcp-connected? (= "connected" (-> state :workspace-local :mcp :connection))
mcp-enabled? (true? (-> state :profile :props :mcp-enabled))
num-sessions (-> state :workspace-presence count)
multi-session? (> num-sessions 1)]
multi-session? (> num-sessions 1)
mcp-active? (-> state :workspace-local :mcp :active)]
(if (and mcp-enabled? multi-session?)
(if mcp-connected?
(if (or mcp-connected? mcp-active?)
(rx/of (ntf/hide))
(rx/of (ntf/dialog :content (tr "notifications.mcp.active-in-another-tab")
:cancel {:label (tr "labels.dismiss")
@@ -76,6 +120,7 @@
::ev/origin "workspace-notification"}))})))
(rx/of (ntf/hide)))))))
;; This event will arrive when the mcp is enabled in the main menu
(defn update-mcp-status
[value]
(ptk/reify ::update-mcp-status
@@ -121,13 +166,10 @@
:getServerUrl #(str cf/mcp-ws-uri)
:setMcpStatus
(fn [status]
(let [mcp-connection (case status
"connected" true
"disconnected" false
"error" nil
"")]
(st/emit! (update-mcp-connection mcp-connection))
(log/info :hint "MCP STATUS" :status status)))
(when (= status "connected")
(start-reconnect-watcher!))
(st/emit! (update-mcp-connection status))
(log/info :hint "MCP STATUS" :status status))
:on
(fn [event cb]

View File

@@ -750,7 +750,7 @@
workspace-local (mf/deref refs/workspace-local)
mcp-enabled? (true? (-> profile :props :mcp-enabled))
mcp-connected? (true? (-> workspace-local :mcp :connection))
mcp-connected? (= "connected" (-> workspace-local :mcp :connection))
on-nav-to-integrations
(mf/use-fn
@@ -769,7 +769,7 @@
(mf/use-fn
(fn []
(if mcp-connected?
(st/emit! (mcp/disconnect-mcp)
(st/emit! (mcp/user-disconnect-mcp)
(ptk/event ::ev/event {::ev/name "disconnect-mcp-plugin"
::ev/origin "workspace-menu"}))
(st/emit! (mcp/connect-mcp)
@@ -980,8 +980,8 @@
(when (contains? cf/flags :mcp)
(let [mcp-enabled? (true? (-> profile :props :mcp-enabled))
mcp-connection (-> workspace-local :mcp :connection)
mcp-connected? (true? mcp-connection)
mcp-error? (nil? mcp-connection)]
mcp-connected? (= mcp-connection "connected")
mcp-error? (= mcp-connection "error")]
[:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item)
:on-click on-menu-click
:on-key-down (fn [event]

View File

@@ -105,8 +105,12 @@ function connectToMcpServer(baseUrl?: string, token?: string): void {
updateConnectionStatus("connecting", "Connecting...");
ws.onopen = () => {
console.log("Connected to MCP server");
updateConnectionStatus("connected", "Connected");
setTimeout(() => {
if (ws) {
console.log("Connected to MCP server");
updateConnectionStatus("connected", "Connected");
}
}, 100);
};
ws.onmessage = (event) => {

View File

@@ -68,6 +68,7 @@ export class PluginBridge {
if (this.clientsByToken.has(userToken)) {
this.logger.warn("Duplicate connection for given user token; rejecting new connection");
ws.close(1008, "Duplicate connection for given user token; close previous connection first.");
return;
}
this.clientsByToken.set(userToken, connection);