|
59 | 59 | (.build))) |
60 | 60 | (.build))) |
61 | 61 |
|
62 | | -(defn ^:private ->full-server [mcp-name server-config db] |
63 | | - (let [tools (->> (vals (:mcp-tools db)) |
64 | | - (filterv #(= mcp-name (:mcp-name %))) |
65 | | - (map (fn [mcp-tool] |
66 | | - {:name (:name mcp-tool) |
67 | | - :description (:description mcp-tool) |
68 | | - :parameters (:parameters mcp-tool)})))] |
69 | | - (cond-> {:name (name mcp-name) |
70 | | - :command (:command server-config) |
71 | | - :args (:args server-config)} |
72 | | - (seq tools) (assoc :tools tools)))) |
| 62 | +(defn ^:private ->server [mcp-name server-config status db] |
| 63 | + {:name (name mcp-name) |
| 64 | + :command (:command server-config) |
| 65 | + :args (:args server-config) |
| 66 | + :tools (get-in db [:mcp-clients mcp-name :tools]) |
| 67 | + :status status}) |
73 | 68 |
|
74 | 69 | (defn initialize-servers-async! [{:keys [on-server-updated]} db* config] |
75 | 70 | (let [workspaces (:workspace-folders @db*) |
76 | | - db @db*] |
| 71 | + db @db* |
| 72 | + obj-mapper (ObjectMapper.)] |
77 | 73 | (doseq [[name server-config] (:mcpServers config)] |
78 | | - (let [full-server (->full-server name server-config db)] |
79 | | - (when-not (get-in db [:mcp-clients name]) |
80 | | - (if (get server-config :disabled false) |
81 | | - (on-server-updated (assoc full-server :status :disabled)) |
82 | | - (future |
83 | | - (try |
84 | | - (let [transport (->transport server-config workspaces) |
85 | | - client (->client transport config)] |
86 | | - (on-server-updated (assoc full-server :status :starting)) |
87 | | - (swap! db* assoc-in [:mcp-clients name] {:client client}) |
88 | | - (doseq [{:keys [name uri]} workspaces] |
89 | | - (.addRoot client (McpSchema$Root. uri name))) |
90 | | - (.initialize client) |
91 | | - (on-server-updated (assoc full-server :status :running))) |
92 | | - (catch Exception e |
93 | | - (logger/warn logger-tag (format "Could not initialize MCP server %s. Error: %s" name (.getMessage e))) |
94 | | - (on-server-updated (assoc full-server :status :failed))))))))))) |
95 | | - |
96 | | -(defn tools-cached? [db] |
97 | | - (boolean (:mcp-tools db))) |
98 | | - |
99 | | -(defn cache-tools! [db*] |
100 | | - (let [obj-mapper (ObjectMapper.)] |
101 | | - (doseq [[name {:keys [^McpSyncClient client]}] (:mcp-clients @db*)] |
102 | | - (when (.isInitialized client) |
103 | | - (doseq [^McpSchema$Tool tool-client (.tools (.listTools client))] |
104 | | - (let [tool {:name (.name tool-client) |
105 | | - :mcp-name name |
106 | | - :mcp-client client |
107 | | - :description (.description tool-client) |
108 | | - ;; We convert to json to then read so we have the clojure map |
109 | | - ;; TODO avoid this converting to clojure map directly |
110 | | - :parameters (json/parse-string (.writeValueAsString obj-mapper (.inputSchema tool-client)) true)}] |
111 | | - (swap! db* assoc-in [:mcp-tools (:name tool)] tool))))))) |
| 74 | + (when-not (get-in db [:mcp-clients name]) |
| 75 | + (if (get server-config :disabled false) |
| 76 | + (on-server-updated (->server name server-config :disabled db)) |
| 77 | + (future |
| 78 | + (try |
| 79 | + (let [transport (->transport server-config workspaces) |
| 80 | + client (->client transport config)] |
| 81 | + (on-server-updated (->server name server-config :starting db)) |
| 82 | + (swap! db* assoc-in [:mcp-clients name] {:client client}) |
| 83 | + (doseq [{:keys [name uri]} workspaces] |
| 84 | + (.addRoot client (McpSchema$Root. uri name))) |
| 85 | + (.initialize client) |
| 86 | + (let [tools (mapv (fn [^McpSchema$Tool tool-client] |
| 87 | + {:name (.name tool-client) |
| 88 | + :description (.description tool-client) |
| 89 | + ;; We convert to json to then read so we have a clojure map |
| 90 | + ;; TODO avoid this converting to clojure map directly |
| 91 | + :parameters (json/parse-string (.writeValueAsString obj-mapper (.inputSchema tool-client)) true)}) |
| 92 | + (.tools (.listTools client)))] |
| 93 | + (swap! db* assoc-in [:mcp-clients name :tools] tools)) |
| 94 | + (on-server-updated (->server name server-config :running @db*))) |
| 95 | + (catch Exception e |
| 96 | + (logger/warn logger-tag (format "Could not initialize MCP server %s. Error: %s" name (.getMessage e))) |
| 97 | + (on-server-updated (->server name server-config :failed db)))))))))) |
112 | 98 |
|
113 | 99 | (defn all-tools [db] |
114 | | - (vals (:mcp-tools db))) |
| 100 | + (into [] |
| 101 | + (mapcat (fn [[_name {:keys [tools]}]] |
| 102 | + tools)) |
| 103 | + (:mcp-clients db))) |
115 | 104 |
|
116 | 105 | (defn call-tool! [^String name ^Map arguments db] |
117 | | - (let [result (.callTool ^McpSyncClient (get-in db [:mcp-tools name :mcp-client]) |
| 106 | + (let [mcp-client (->> (:mcp-clients db) |
| 107 | + (keep (fn [{:keys [client tools]}] |
| 108 | + (when (some #(= name (:name %)) tools) |
| 109 | + client))) |
| 110 | + first) |
| 111 | + result (.callTool ^McpSyncClient mcp-client |
118 | 112 | (McpSchema$CallToolRequest. name arguments))] |
119 | 113 | (logger/debug logger-tag "ToolCall result: " result) |
120 | 114 | {:contents (map (fn [content] |
|
129 | 123 | (doseq [[_name {:keys [_client]}] (:mcp-clients @db*)] |
130 | 124 | ;; TODO NoClassDefFound being thrown for some reason |
131 | 125 | #_(.closeGracefully ^McpSyncClient client)) |
132 | | - (swap! db* assoc |
133 | | - :mcp-clients {} |
134 | | - :mcp-tools {})) |
| 126 | + (swap! db* assoc :mcp-clients {})) |
0 commit comments