@@ -141,7 +141,14 @@ type NotificationHandlerFunc func(ctx context.Context, notification mcp.JSONRPCN
141
141
// MCPServer implements a Model Control Protocol server that can handle various types of requests
142
142
// including resources, prompts, and tools.
143
143
type MCPServer struct {
144
- mu sync.RWMutex // Add mutex for protecting shared resources
144
+ // Separate mutexes for different resource types
145
+ resourcesMu sync.RWMutex
146
+ promptsMu sync.RWMutex
147
+ toolsMu sync.RWMutex
148
+ middlewareMu sync.RWMutex
149
+ notificationHandlersMu sync.RWMutex
150
+ capabilitiesMu sync.RWMutex
151
+
145
152
name string
146
153
version string
147
154
instructions string
@@ -301,7 +308,9 @@ func WithToolHandlerMiddleware(
301
308
toolHandlerMiddleware ToolHandlerMiddleware ,
302
309
) ServerOption {
303
310
return func (s * MCPServer ) {
311
+ s .middlewareMu .Lock ()
304
312
s .toolHandlerMiddlewares = append (s .toolHandlerMiddlewares , toolHandlerMiddleware )
313
+ s .middlewareMu .Unlock ()
305
314
}
306
315
}
307
316
@@ -396,11 +405,14 @@ func (s *MCPServer) AddResource(
396
405
resource mcp.Resource ,
397
406
handler ResourceHandlerFunc ,
398
407
) {
408
+ s .capabilitiesMu .Lock ()
399
409
if s .capabilities .resources == nil {
400
410
s .capabilities .resources = & resourceCapabilities {}
401
411
}
402
- s .mu .Lock ()
403
- defer s .mu .Unlock ()
412
+ s .capabilitiesMu .Unlock ()
413
+
414
+ s .resourcesMu .Lock ()
415
+ defer s .resourcesMu .Unlock ()
404
416
s .resources [resource .URI ] = resourceEntry {
405
417
resource : resource ,
406
418
handler : handler ,
@@ -412,11 +424,14 @@ func (s *MCPServer) AddResourceTemplate(
412
424
template mcp.ResourceTemplate ,
413
425
handler ResourceTemplateHandlerFunc ,
414
426
) {
427
+ s .capabilitiesMu .Lock ()
415
428
if s .capabilities .resources == nil {
416
429
s .capabilities .resources = & resourceCapabilities {}
417
430
}
418
- s .mu .Lock ()
419
- defer s .mu .Unlock ()
431
+ s .capabilitiesMu .Unlock ()
432
+
433
+ s .resourcesMu .Lock ()
434
+ defer s .resourcesMu .Unlock ()
420
435
s .resourceTemplates [template .URITemplate .Raw ()] = resourceTemplateEntry {
421
436
template : template ,
422
437
handler : handler ,
@@ -425,11 +440,14 @@ func (s *MCPServer) AddResourceTemplate(
425
440
426
441
// AddPrompt registers a new prompt handler with the given name
427
442
func (s * MCPServer ) AddPrompt (prompt mcp.Prompt , handler PromptHandlerFunc ) {
443
+ s .capabilitiesMu .Lock ()
428
444
if s .capabilities .prompts == nil {
429
445
s .capabilities .prompts = & promptCapabilities {}
430
446
}
431
- s .mu .Lock ()
432
- defer s .mu .Unlock ()
447
+ s .capabilitiesMu .Unlock ()
448
+
449
+ s .promptsMu .Lock ()
450
+ defer s .promptsMu .Unlock ()
433
451
s .prompts [prompt .Name ] = prompt
434
452
s .promptHandlers [prompt .Name ] = handler
435
453
}
@@ -441,34 +459,37 @@ func (s *MCPServer) AddTool(tool mcp.Tool, handler ToolHandlerFunc) {
441
459
442
460
// AddTools registers multiple tools at once
443
461
func (s * MCPServer ) AddTools (tools ... ServerTool ) {
462
+ s .capabilitiesMu .Lock ()
444
463
if s .capabilities .tools == nil {
445
464
s .capabilities .tools = & toolCapabilities {}
446
465
}
447
- s .mu .Lock ()
466
+ s .capabilitiesMu .Unlock ()
467
+
468
+ s .toolsMu .Lock ()
448
469
for _ , entry := range tools {
449
470
s .tools [entry .Tool .Name ] = entry
450
471
}
451
- s .mu .Unlock ()
472
+ s .toolsMu .Unlock ()
452
473
453
474
// Send notification to all initialized sessions
454
475
s .sendNotificationToAllClients ("notifications/tools/list_changed" , nil )
455
476
}
456
477
457
478
// SetTools replaces all existing tools with the provided list
458
479
func (s * MCPServer ) SetTools (tools ... ServerTool ) {
459
- s .mu .Lock ()
480
+ s .toolsMu .Lock ()
460
481
s .tools = make (map [string ]ServerTool )
461
- s .mu .Unlock ()
482
+ s .toolsMu .Unlock ()
462
483
s .AddTools (tools ... )
463
484
}
464
485
465
486
// DeleteTools removes a tool from the server
466
487
func (s * MCPServer ) DeleteTools (names ... string ) {
467
- s .mu .Lock ()
488
+ s .toolsMu .Lock ()
468
489
for _ , name := range names {
469
490
delete (s .tools , name )
470
491
}
471
- s .mu .Unlock ()
492
+ s .toolsMu .Unlock ()
472
493
473
494
// Send notification to all initialized sessions
474
495
s .sendNotificationToAllClients ("notifications/tools/list_changed" , nil )
@@ -479,8 +500,8 @@ func (s *MCPServer) AddNotificationHandler(
479
500
method string ,
480
501
handler NotificationHandlerFunc ,
481
502
) {
482
- s .mu .Lock ()
483
- defer s .mu .Unlock ()
503
+ s .notificationHandlersMu .Lock ()
504
+ defer s .notificationHandlersMu .Unlock ()
484
505
s .notificationHandlers [method ] = handler
485
506
}
486
507
@@ -589,12 +610,12 @@ func (s *MCPServer) handleListResources(
589
610
id interface {},
590
611
request mcp.ListResourcesRequest ,
591
612
) (* mcp.ListResourcesResult , * requestError ) {
592
- s .mu .RLock ()
613
+ s .resourcesMu .RLock ()
593
614
resources := make ([]mcp.Resource , 0 , len (s .resources ))
594
615
for _ , entry := range s .resources {
595
616
resources = append (resources , entry .resource )
596
617
}
597
- s .mu .RUnlock ()
618
+ s .resourcesMu .RUnlock ()
598
619
599
620
// Sort the resources by name
600
621
sort .Slice (resources , func (i , j int ) bool {
@@ -622,12 +643,12 @@ func (s *MCPServer) handleListResourceTemplates(
622
643
id interface {},
623
644
request mcp.ListResourceTemplatesRequest ,
624
645
) (* mcp.ListResourceTemplatesResult , * requestError ) {
625
- s .mu .RLock ()
646
+ s .resourcesMu .RLock ()
626
647
templates := make ([]mcp.ResourceTemplate , 0 , len (s .resourceTemplates ))
627
648
for _ , entry := range s .resourceTemplates {
628
649
templates = append (templates , entry .template )
629
650
}
630
- s .mu .RUnlock ()
651
+ s .resourcesMu .RUnlock ()
631
652
sort .Slice (templates , func (i , j int ) bool {
632
653
return templates [i ].Name < templates [j ].Name
633
654
})
@@ -653,11 +674,11 @@ func (s *MCPServer) handleReadResource(
653
674
id interface {},
654
675
request mcp.ReadResourceRequest ,
655
676
) (* mcp.ReadResourceResult , * requestError ) {
656
- s .mu .RLock ()
677
+ s .resourcesMu .RLock ()
657
678
// First try direct resource handlers
658
679
if entry , ok := s .resources [request .Params .URI ]; ok {
659
680
handler := entry .handler
660
- s .mu .RUnlock ()
681
+ s .resourcesMu .RUnlock ()
661
682
contents , err := handler (ctx , request )
662
683
if err != nil {
663
684
return nil , & requestError {
@@ -686,7 +707,7 @@ func (s *MCPServer) handleReadResource(
686
707
break
687
708
}
688
709
}
689
- s .mu .RUnlock ()
710
+ s .resourcesMu .RUnlock ()
690
711
691
712
if matched {
692
713
contents , err := matchedHandler (ctx , request )
@@ -717,12 +738,12 @@ func (s *MCPServer) handleListPrompts(
717
738
id interface {},
718
739
request mcp.ListPromptsRequest ,
719
740
) (* mcp.ListPromptsResult , * requestError ) {
720
- s .mu .RLock ()
741
+ s .promptsMu .RLock ()
721
742
prompts := make ([]mcp.Prompt , 0 , len (s .prompts ))
722
743
for _ , prompt := range s .prompts {
723
744
prompts = append (prompts , prompt )
724
745
}
725
- s .mu .RUnlock ()
746
+ s .promptsMu .RUnlock ()
726
747
727
748
// sort prompts by name
728
749
sort .Slice (prompts , func (i , j int ) bool {
@@ -750,9 +771,9 @@ func (s *MCPServer) handleGetPrompt(
750
771
id interface {},
751
772
request mcp.GetPromptRequest ,
752
773
) (* mcp.GetPromptResult , * requestError ) {
753
- s .mu .RLock ()
774
+ s .promptsMu .RLock ()
754
775
handler , ok := s .promptHandlers [request .Params .Name ]
755
- s .mu .RUnlock ()
776
+ s .promptsMu .RUnlock ()
756
777
757
778
if ! ok {
758
779
return nil , & requestError {
@@ -779,7 +800,7 @@ func (s *MCPServer) handleListTools(
779
800
id interface {},
780
801
request mcp.ListToolsRequest ,
781
802
) (* mcp.ListToolsResult , * requestError ) {
782
- s .mu .RLock ()
803
+ s .toolsMu .RLock ()
783
804
tools := make ([]mcp.Tool , 0 , len (s .tools ))
784
805
785
806
// Get all tool names for consistent ordering
@@ -795,6 +816,8 @@ func (s *MCPServer) handleListTools(
795
816
for _ , name := range toolNames {
796
817
tools = append (tools , s .tools [name ].Tool )
797
818
}
819
+ s .toolsMu .RUnlock ()
820
+
798
821
toolsToReturn , nextCursor , err := listByPagination [mcp.Tool ](ctx , s , request .Params .Cursor , tools )
799
822
if err != nil {
800
823
return nil , & requestError {
@@ -817,9 +840,9 @@ func (s *MCPServer) handleToolCall(
817
840
id interface {},
818
841
request mcp.CallToolRequest ,
819
842
) (* mcp.CallToolResult , * requestError ) {
820
- s .mu .RLock ()
843
+ s .toolsMu .RLock ()
821
844
tool , ok := s .tools [request .Params .Name ]
822
- s .mu .RUnlock ()
845
+ s .toolsMu .RUnlock ()
823
846
824
847
if ! ok {
825
848
return nil , & requestError {
@@ -830,9 +853,16 @@ func (s *MCPServer) handleToolCall(
830
853
}
831
854
832
855
finalHandler := tool .Handler
833
- for i := len (s .toolHandlerMiddlewares ) - 1 ; i >= 0 ; i -- {
834
- finalHandler = s.toolHandlerMiddlewares [i ](finalHandler )
856
+
857
+ s .middlewareMu .RLock ()
858
+ mw := s .toolHandlerMiddlewares
859
+ s .middlewareMu .RUnlock ()
860
+
861
+ // Apply middlewares in reverse order
862
+ for i := len (mw ) - 1 ; i >= 0 ; i -- {
863
+ finalHandler = mw [i ](finalHandler )
835
864
}
865
+
836
866
result , err := finalHandler (ctx , request )
837
867
if err != nil {
838
868
return nil , & requestError {
@@ -849,9 +879,9 @@ func (s *MCPServer) handleNotification(
849
879
ctx context.Context ,
850
880
notification mcp.JSONRPCNotification ,
851
881
) mcp.JSONRPCMessage {
852
- s .mu .RLock ()
882
+ s .notificationHandlersMu .RLock ()
853
883
handler , ok := s .notificationHandlers [notification .Method ]
854
- s .mu .RUnlock ()
884
+ s .notificationHandlersMu .RUnlock ()
855
885
856
886
if ok {
857
887
handler (ctx , notification )
0 commit comments