From 9a9ef762898d6fb19f0f1752401a4bc0ce32f891 Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Tue, 2 Sep 2025 20:39:52 -0400 Subject: [PATCH] fix: don't share mutex between tools/resources I noticed that #569 was merged (thanks!) and looked at the diff again with fresh eyes and noticed that I reused the existing mutex for tool middlewares within the resource middlewares. This means that, at least while processing middlewares, it's possible a resource call could be blocked waiting on a lock because of a tool call or vice-versa. Since there's a separate mutex for tools, resources, etc, it seems there's a desire to not block each other. This commit renames the existing middleware mutex to better clarify it's specifically for tool middlewares, and adds a new mutex for use specifically with resource middlewares. Signed-off-by: TJ Hoplock --- server/server.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/server/server.go b/server/server.go index 688357280..96a8a6849 100644 --- a/server/server.go +++ b/server/server.go @@ -147,9 +147,10 @@ type NotificationHandlerFunc func(ctx context.Context, notification mcp.JSONRPCN type MCPServer struct { // Separate mutexes for different resource types resourcesMu sync.RWMutex + resourceMiddlewareMu sync.RWMutex promptsMu sync.RWMutex toolsMu sync.RWMutex - middlewareMu sync.RWMutex + toolMiddlewareMu sync.RWMutex notificationHandlersMu sync.RWMutex capabilitiesMu sync.RWMutex toolFiltersMu sync.RWMutex @@ -221,9 +222,9 @@ func WithToolHandlerMiddleware( toolHandlerMiddleware ToolHandlerMiddleware, ) ServerOption { return func(s *MCPServer) { - s.middlewareMu.Lock() + s.toolMiddlewareMu.Lock() s.toolHandlerMiddlewares = append(s.toolHandlerMiddlewares, toolHandlerMiddleware) - s.middlewareMu.Unlock() + s.toolMiddlewareMu.Unlock() } } @@ -233,9 +234,9 @@ func WithResourceHandlerMiddleware( resourceHandlerMiddleware ResourceHandlerMiddleware, ) ServerOption { return func(s *MCPServer) { - s.middlewareMu.Lock() + s.resourceMiddlewareMu.Lock() s.resourceHandlerMiddlewares = append(s.resourceHandlerMiddlewares, resourceHandlerMiddleware) - s.middlewareMu.Unlock() + s.resourceMiddlewareMu.Unlock() } } @@ -876,13 +877,13 @@ func (s *MCPServer) handleReadResource( s.resourcesMu.RUnlock() finalHandler := handler - s.middlewareMu.RLock() + s.resourceMiddlewareMu.RLock() mw := s.resourceHandlerMiddlewares // Apply middlewares in reverse order for i := len(mw) - 1; i >= 0; i-- { finalHandler = mw[i](finalHandler) } - s.middlewareMu.RUnlock() + s.resourceMiddlewareMu.RUnlock() contents, err := finalHandler(ctx, request) if err != nil { @@ -1138,14 +1139,14 @@ func (s *MCPServer) handleToolCall( finalHandler := tool.Handler - s.middlewareMu.RLock() + s.toolMiddlewareMu.RLock() mw := s.toolHandlerMiddlewares // Apply middlewares in reverse order for i := len(mw) - 1; i >= 0; i-- { finalHandler = mw[i](finalHandler) } - s.middlewareMu.RUnlock() + s.toolMiddlewareMu.RUnlock() result, err := finalHandler(ctx, request) if err != nil {