Skip to content

Commit b795bcd

Browse files
committed
Fix STDIO MCP server deadlock caused by list_changed notification handlers blocking the reader thread
1 parent b909df6 commit b795bcd

3 files changed

Lines changed: 41 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- Fix STDIO MCP server deadlock caused by list_changed notification handlers blocking the reader thread.
56
- Consider Anthropic internal server error as a retriable error.
67
- Improve MCP error logging to show error code, message, and data instead of null.
78
- Improve error handling when MCP promtps fail on server side.

deps-lock.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,16 @@
982982
"mvn-repo": "https://repo.clojars.org/",
983983
"hash": "sha256-Xe66kz8gwkNNCBozUpigMJuTl2+p1ZQc+QwEgldebZA="
984984
},
985+
{
986+
"mvn-path": "dev/ericdallo/rewrite-json/0.1.1/rewrite-json-0.1.1.jar",
987+
"mvn-repo": "https://repo.clojars.org/",
988+
"hash": "sha256-1XnFTWANPTA8jRfrz/gP7V3MMQ0ht4tJIBDCI5vuOb8="
989+
},
990+
{
991+
"mvn-path": "dev/ericdallo/rewrite-json/0.1.1/rewrite-json-0.1.1.pom",
992+
"mvn-repo": "https://repo.clojars.org/",
993+
"hash": "sha256-smGEfZ7nI45VkdHtuZVDmdoXvEXU3xcgK1Q5kGfJfYQ="
994+
},
985995
{
986996
"mvn-path": "expound/expound/0.9.0/expound-0.9.0.jar",
987997
"mvn-repo": "https://repo.clojars.org/",

src/eca/features/tools/mcp.clj

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,28 +137,50 @@
137137
(logger/info logger-tag (format "[%s] %s" server-name msg)))})
138138
:needs-reinit?* nil})))
139139

140+
(defn ^:private non-blocking-handler
141+
"Wraps a notification handler so it runs on a separate thread.
142+
Prevents STDIO transport deadlock where the reader thread blocks on a
143+
synchronous fetch request inside a notification handler, making it
144+
unable to read incoming responses."
145+
[f]
146+
(pcs/wrap-initialized-check
147+
(fn [jsonrpc-notification]
148+
(future (f jsonrpc-notification)))))
149+
140150
(defn ^:private ->client [name transport init-timeout workspaces
141151
{:keys [on-tools-change]}]
142152
(let [tools-consumer (fn [tools]
143153
(logger/info logger-tag
144154
(format "[%s] Tools list changed, received %d tools"
145155
name (count tools)))
146156
(on-tools-change tools))
147-
tools-nhandler (pcs/wrap-initialized-check
148-
(fn [jsonrpc-notification]
149-
(pcs/fetch-tools jsonrpc-notification
150-
{:on-tools tools-consumer})))
151157
client (pmc/make-mcp-client
152158
{:info (pes/make-info name "current")
153159
:client-transport transport
154160
:primitives {:roots (mapv #(pcap/make-root-item (:uri %)
155161
{:name (:name %)})
156162
workspaces)}
157163
:notification-handlers
158-
{psd/method-notifications-tools-list_changed tools-nhandler
159-
psd/method-notifications-message (fn [params]
160-
(logger/info logger-tag
161-
(format "[MCP-%s] %s" name (:data params))))}
164+
{psd/method-notifications-tools-list_changed
165+
(non-blocking-handler
166+
(fn [notification]
167+
(pcs/fetch-tools notification
168+
{:on-tools tools-consumer})))
169+
170+
psd/method-notifications-resources-list_changed
171+
(non-blocking-handler
172+
(fn [notification]
173+
(pcs/fetch-resources notification)))
174+
175+
psd/method-notifications-prompts-list_changed
176+
(non-blocking-handler
177+
(fn [notification]
178+
(pcs/fetch-prompts notification)))
179+
180+
psd/method-notifications-message
181+
(fn [params]
182+
(logger/info logger-tag
183+
(format "[MCP-%s] %s" name (:data params))))}
162184
:print-banner? false})]
163185
(pmc/initialize-and-notify! client
164186
{:timeout-millis (* 1000 init-timeout)})

0 commit comments

Comments
 (0)