mirror of
https://github.com/penpot/penpot.git
synced 2026-03-30 16:20:34 +02:00
✨ Allow for reconnections to MCP server
This commit is contained in:
committed by
Alonso Torres
parent
dd6a3c291a
commit
937032c790
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user