|
201 | 201 | (async/into [])
|
202 | 202 | (async/<!!))]
|
203 | 203 | (merge
|
204 |
| - {:resourceTemplates resource-templates} |
205 |
| - (when (= 100 (count resource-templates)) |
206 |
| - {:nextCursor nextCursor})))) |
| 204 | + {:resourceTemplates resource-templates} |
| 205 | + (when (= 100 (count resource-templates)) |
| 206 | + {:nextCursor nextCursor})))) |
207 | 207 |
|
208 | 208 | (defmethod lsp.server/receive-request "resources/subscribe" [_ _ params]
|
209 | 209 | (logger/info "resources/subscribe" params)
|
|
261 | 261 | (mapcat (comp :content :result))
|
262 | 262 | (into []))))
|
263 | 263 |
|
| 264 | +(defn get-functions [db*] |
| 265 | + (->> @db* :mcp.prompts/registry vals (mapcat :functions))) |
| 266 | + |
| 267 | +(defn poci? [{:keys [db*] :as components} params] |
| 268 | + (not |
| 269 | + (= :mcp |
| 270 | + (-> (filter #(= (-> params :name) (-> % :function :name)) (get-functions db*)) |
| 271 | + first |
| 272 | + :function |
| 273 | + :container |
| 274 | + :type)))) |
| 275 | + |
| 276 | +(defn make-tool-calls [{:keys [db* server-id] :as components} params {:keys [thread-id] :as opts}] |
| 277 | + ;; TODO non-mcp tool calls are maps of content, role tool_call_id |
| 278 | + ;; we turn them into one text message and respond to the jsonrpc request here |
| 279 | + ;; for mcp tool calls the response will already be valid content |
| 280 | + ;; so we can concat it and just return the result (or error) |
| 281 | + ;; tool-outputs are :content, :role, :tool_call_id |
| 282 | + ;; (MCP doesn't care about :role or :tool_call_id - these are client concerns) |
| 283 | + (let [tool-outputs (->> |
| 284 | + (tools/make-tool-calls |
| 285 | + 0 |
| 286 | + (partial |
| 287 | + tools/function-handler |
| 288 | + (merge |
| 289 | + {:functions (get-functions db*) |
| 290 | + :host-dir (-> @db* :host-dir) |
| 291 | + :server-id server-id} |
| 292 | + (when thread-id {:thread-id thread-id}))) |
| 293 | + ;; tool calls are functions, which are arguments,name maps, and ids |
| 294 | + ;; mcp tool call params are also maps of name, and arguments |
| 295 | + [{:function (update |
| 296 | + params :arguments |
| 297 | + (fn [arguments] |
| 298 | + (logger/trace |
| 299 | + (-> arguments |
| 300 | + (merge |
| 301 | + (db/parameter-values (:name params)) |
| 302 | + (select-keys (-> @db* :servers (get server-id)) [:roots])) |
| 303 | + (json/generate-string))))) |
| 304 | + ;; TODO there's no id here like in regular agent tool calling loops |
| 305 | + ;; MCP clients do this on their side (using just the response id) |
| 306 | + :id "1"}]) |
| 307 | + (async/reduce conj []) |
| 308 | + (async/<!!))] |
| 309 | + ;; TODO with mcp, tool-calls with errors are still jsonrpc results |
| 310 | + ;; protocol errors are jsonrpc errors, with a code and a message |
| 311 | + ;; TODO if result is ::method-not-found, we'll get a protocol error |
| 312 | + ;; responding with a map containing an :error key will also generate a protocol error |
| 313 | + {:content (create-tool-outputs tool-outputs) |
| 314 | + :is-error false})) |
| 315 | + |
264 | 316 | (defn mcp-tool-calls
|
265 | 317 | " params
|
266 | 318 | db* - uses mcp.prompts/registry and host-dir
|
267 | 319 | params - tools/call mcp params"
|
268 | 320 | [{:keys [db* server-id] :as components} params]
|
269 |
| - (volumes/with-volume |
270 |
| - (fn [thread-id] |
271 |
| - ;; TODO non-mcp tool calls are maps of content, role tool_call_id |
272 |
| - ;; we turn them into one text message and respond to the jsonrpc request here |
273 |
| - ;; for mcp tool calls the response will already be valid content |
274 |
| - ;; so we can concat it and just return the result (or error) |
275 |
| - ;; tool-outputs are :content, :role, :tool_call_id |
276 |
| - ;; (MCP doesn't care about :role or :tool_call_id - these are client concerns) |
277 |
| - (let [tool-outputs (->> |
278 |
| - (tools/make-tool-calls |
279 |
| - 0 |
280 |
| - (partial |
281 |
| - tools/function-handler |
282 |
| - {:functions (->> @db* :mcp.prompts/registry vals (mapcat :functions)) |
283 |
| - :host-dir (-> @db* :host-dir) |
284 |
| - :server-id server-id |
285 |
| - :thread-id thread-id}) |
286 |
| - ;; tool calls are functions, which are arguments,name maps, and ids |
287 |
| - ;; mcp tool call params are also maps of name, and arguments |
288 |
| - [{:function (update |
289 |
| - params :arguments |
290 |
| - (fn [arguments] |
291 |
| - (logger/trace |
292 |
| - (-> arguments |
293 |
| - (merge |
294 |
| - (db/parameter-values (:name params)) |
295 |
| - (select-keys (-> @db* :servers (get server-id)) [:roots])) |
296 |
| - (json/generate-string))))) |
297 |
| - :id "1"}]) |
298 |
| - (async/reduce conj []) |
299 |
| - (async/<!!))] |
300 |
| - ;; TODO with mcp, tool-calls with errors are still jsonrpc results |
301 |
| - ;; protocol errors are jsonrpc errors, with a code and a message |
302 |
| - ;; TODO if result is ::method-not-found, we'll get a protocol error |
303 |
| - ;; responding with a map containing an :error key will also generate a protocol error |
304 |
| - {:content |
305 |
| - (concat |
306 |
| - (create-tool-outputs tool-outputs) |
307 |
| - (volumes/pick-up-mcp-resources thread-id (partial update-resources components))) |
308 |
| - :is-error false})))) |
| 321 | + (if (poci? components params) |
| 322 | + (volumes/with-volume |
| 323 | + (fn [thread-id] |
| 324 | + (let [response (make-tool-calls components params {:thread-id thread-id})] |
| 325 | + (update response :content concat (volumes/pick-up-mcp-resources thread-id (partial update-resources components)))))) |
| 326 | + (make-tool-calls components params {}))) |
309 | 327 |
|
310 | 328 | (defmethod lsp.server/receive-request "tools/call" [_ components params]
|
311 | 329 | (logger/info "tools/call")
|
|
0 commit comments