|
534 | 534 | (swap! db* update :mcp-clients dissoc server-name) |
535 | 535 | (initialize-server! server-name db* config metrics (constantly nil))) |
536 | 536 |
|
537 | | -(def ^:private reinit-poll-interval-ms 100) |
538 | 537 | (def ^:private tool-call-timeout-ms 120000) |
539 | 538 |
|
540 | 539 | (defn ^:private tool-call-error [msg] |
541 | 540 | {:error true |
542 | 541 | :contents [{:type :text :text msg}]}) |
543 | 542 |
|
544 | 543 | (defn ^:private do-call-tool |
545 | | - "Execute a tool call. When needs-reinit?* is provided (HTTP transport), runs |
546 | | - pmc/call-tool in a future and polls for transport errors (404/5xx) so we can |
547 | | - short-circuit instead of blocking until plumcp's internal timeout — the error |
548 | | - is set in a virtual thread that pmc/call-tool never joins." |
549 | | - [mcp-client name arguments needs-reinit?*] |
| 544 | + "Execute a tool call. Delegates timeout handling to plumcp via :timeout-millis. |
| 545 | + HTTP 400/404/500 errors are returned as JSON-RPC error responses by plumcp, |
| 546 | + so no polling loop is needed." |
| 547 | + [mcp-client name arguments] |
550 | 548 | (locking mcp-client |
551 | | - (when needs-reinit?* |
552 | | - (reset! needs-reinit?* false)) |
553 | 549 | (let [error-msg* (atom nil) |
554 | | - call-opts {:on-error (fn [_id jsonrpc-error] |
| 550 | + call-opts {:timeout-millis tool-call-timeout-ms |
| 551 | + :on-error (fn [_id jsonrpc-error] |
555 | 552 | (let [msg (or (:message jsonrpc-error) "Unknown JSON-RPC error")] |
556 | 553 | (logger/warn logger-tag "Error calling tool:" msg) |
557 | 554 | (reset! error-msg* msg)) |
558 | 555 | nil)} |
559 | | - call-future (future (pmc/call-tool mcp-client name arguments call-opts)) |
560 | 556 | result (try |
561 | | - (if needs-reinit?* |
562 | | - (loop [elapsed (long 0)] |
563 | | - (cond |
564 | | - (realized? call-future) |
565 | | - (deref call-future) |
566 | | - |
567 | | - @needs-reinit?* |
568 | | - (do (future-cancel call-future) ::connection-lost) |
569 | | - |
570 | | - (>= elapsed (long tool-call-timeout-ms)) |
571 | | - (do (future-cancel call-future) ::timeout) |
572 | | - |
573 | | - :else |
574 | | - (do (Thread/sleep (long reinit-poll-interval-ms)) |
575 | | - (recur (+ elapsed (long reinit-poll-interval-ms)))))) |
576 | | - (deref call-future)) |
| 557 | + (pmc/call-tool mcp-client name arguments call-opts) |
577 | 558 | (catch Exception e |
578 | | - (future-cancel call-future) |
579 | 559 | (if (transient-transport-error? e) |
580 | 560 | (do (logger/warn logger-tag (format "Transient transport error, retrying tool call: %s" (.getMessage e))) |
581 | 561 | ::retry) |
|
585 | 565 | (= ::retry result) |
586 | 566 | nil |
587 | 567 |
|
588 | | - (= ::timeout result) |
589 | | - (tool-call-error (format "MCP tool call timed out after %ds" (/ tool-call-timeout-ms 1000))) |
590 | | - |
591 | | - (= ::connection-lost result) |
592 | | - (tool-call-error "MCP server connection lost during tool call") |
593 | | - |
594 | 568 | (::error-msg result) |
595 | 569 | (tool-call-error (format "MCP server error: %s" (::error-msg result))) |
596 | 570 |
|
|
604 | 578 | (defn ^:private reinit-and-call-tool! [server-name mcp-client db* config metrics name arguments] |
605 | 579 | (reinitialize-server! server-name mcp-client db* config metrics) |
606 | 580 | (if-let [new-client (get-in @db* [:mcp-clients server-name :client])] |
607 | | - (let [new-needs-reinit?* (get-in @db* [:mcp-clients server-name :needs-reinit?*])] |
608 | | - (do-call-tool new-client name arguments new-needs-reinit?*)) |
| 581 | + (do-call-tool new-client name arguments) |
609 | 582 | (tool-call-error (format "Failed to re-initialize MCP server '%s'" server-name)))) |
610 | 583 |
|
611 | 584 | (defn call-tool! [name arguments {:keys [db db* config metrics]}] |
|
618 | 591 | (if (and needs-reinit?* @needs-reinit?* db* config metrics) |
619 | 592 | ;; Already flagged (e.g. GET stream 5xx) — reinit before attempting the call |
620 | 593 | (reinit-and-call-tool! server-name mcp-client db* config metrics name arguments) |
621 | | - (let [result (do-call-tool mcp-client name arguments needs-reinit?*)] |
| 594 | + (let [result (do-call-tool mcp-client name arguments)] |
622 | 595 | (cond |
623 | 596 | ;; nil = transient transport error, retry once |
624 | 597 | (nil? result) |
625 | | - (do-call-tool mcp-client name arguments needs-reinit?*) |
| 598 | + (do-call-tool mcp-client name arguments) |
626 | 599 |
|
627 | | - ;; Flagged during the call (e.g. POST 404) — reinit and retry |
| 600 | + ;; Flagged during the call (e.g. GET stream 404/5xx) — reinit and retry |
628 | 601 | (and (:error result) needs-reinit?* @needs-reinit?* db* config metrics) |
629 | 602 | (reinit-and-call-tool! server-name mcp-client db* config metrics name arguments) |
630 | 603 |
|
|
0 commit comments