@@ -91,6 +91,10 @@ MCP Go handles all the complex protocol details and server management, so you ca
9191 - [ Tools] ( #tools )
9292 - [ Prompts] ( #prompts )
9393- [ Examples] ( #examples )
94+ - [ Extras] ( #extras )
95+ - [ Session Management] ( #session-management )
96+ - [ Request Hooks] ( #request-hooks )
97+ - [ Tool Handler Middleware] ( #tool-handler-middleware )
9498- [ Contributing] ( #contributing )
9599 - [ Prerequisites] ( #prerequisites )
96100 - [ Installation] ( #installation-1 )
@@ -516,6 +520,198 @@ For examples, see the `examples/` directory.
516520
517521## Extras
518522
523+ ### Session Management
524+
525+ MCP-Go provides a robust session management system that allows you to:
526+ - Maintain separate state for each connected client
527+ - Register and track client sessions
528+ - Send notifications to specific clients
529+ - Provide per-session tool customization
530+
531+ <details >
532+ <summary >Show Session Management Examples</summary >
533+
534+ #### Basic Session Handling
535+
536+ ``` go
537+ // Create a server with session capabilities
538+ s := server.NewMCPServer (
539+ " Session Demo" ,
540+ " 1.0.0" ,
541+ server.WithToolCapabilities (true ),
542+ )
543+
544+ // Implement your own ClientSession
545+ type MySession struct {
546+ id string
547+ notifChannel chan mcp.JSONRPCNotification
548+ isInitialized bool
549+ // Add custom fields for your application
550+ }
551+
552+ // Implement the ClientSession interface
553+ func (s *MySession ) SessionID () string {
554+ return s.id
555+ }
556+
557+ func (s *MySession ) NotificationChannel () chan <- mcp .JSONRPCNotification {
558+ return s.notifChannel
559+ }
560+
561+ func (s *MySession ) Initialize () {
562+ s.isInitialized = true
563+ }
564+
565+ func (s *MySession ) Initialized () bool {
566+ return s.isInitialized
567+ }
568+
569+ // Register a session
570+ session := &MySession{
571+ id: " user-123" ,
572+ notifChannel: make (chan mcp.JSONRPCNotification , 10 ),
573+ }
574+ if err := s.RegisterSession (context.Background (), session); err != nil {
575+ log.Printf (" Failed to register session: %v " , err)
576+ }
577+
578+ // Send notification to a specific client
579+ err := s.SendNotificationToSpecificClient (
580+ session.SessionID (),
581+ " notification/update" ,
582+ map [string ]any{" message" : " New data available!" },
583+ )
584+ if err != nil {
585+ log.Printf (" Failed to send notification: %v " , err)
586+ }
587+
588+ // Unregister session when done
589+ s.UnregisterSession (context.Background (), session.SessionID ())
590+ ```
591+
592+ #### Per-Session Tools
593+
594+ For more advanced use cases, you can implement the ` SessionWithTools ` interface to support per-session tool customization:
595+
596+ ``` go
597+ // Implement SessionWithTools interface for per-session tools
598+ type MyAdvancedSession struct {
599+ MySession // Embed the basic session
600+ sessionTools map [string ]server.ServerTool
601+ }
602+
603+ // Implement additional methods for SessionWithTools
604+ func (s *MyAdvancedSession ) GetSessionTools () map [string ]server .ServerTool {
605+ return s.sessionTools
606+ }
607+
608+ func (s *MyAdvancedSession ) SetSessionTools (tools map [string ]server .ServerTool ) {
609+ s.sessionTools = tools
610+ }
611+
612+ // Create and register a session with tools support
613+ advSession := &MyAdvancedSession{
614+ MySession : MySession {
615+ id: " user-456" ,
616+ notifChannel: make (chan mcp.JSONRPCNotification , 10 ),
617+ },
618+ sessionTools: make (map [string ]server.ServerTool ),
619+ }
620+ if err := s.RegisterSession (context.Background (), advSession); err != nil {
621+ log.Printf (" Failed to register session: %v " , err)
622+ }
623+
624+ // Add session-specific tools
625+ userSpecificTool := mcp.NewTool (
626+ " user_data" ,
627+ mcp.WithDescription (" Access user-specific data" ),
628+ )
629+ err := s.AddSessionTools (
630+ advSession.SessionID (),
631+ server.ServerTool {
632+ Tool : userSpecificTool,
633+ Handler : func (ctx context.Context , req mcp.CallToolRequest ) (*mcp.CallToolResult , error ) {
634+ // This handler is only available to this specific session
635+ return mcp.NewToolResultText (" User-specific data for " + advSession.SessionID ()), nil
636+ },
637+ },
638+ )
639+ if err != nil {
640+ log.Printf (" Failed to add session tool: %v " , err)
641+ }
642+
643+ // Delete session-specific tools when no longer needed
644+ err = s.DeleteSessionTools (advSession.SessionID (), " user_data" )
645+ if err != nil {
646+ log.Printf (" Failed to delete session tool: %v " , err)
647+ }
648+ ```
649+
650+ #### Tool Filtering
651+
652+ You can also apply filters to control which tools are available to certain sessions:
653+
654+ ``` go
655+ // Add a tool filter that only shows tools with certain prefixes
656+ s := server.NewMCPServer (
657+ " Tool Filtering Demo" ,
658+ " 1.0.0" ,
659+ server.WithToolCapabilities (true ),
660+ server.WithToolFilter (func (ctx context.Context , tools []mcp.Tool ) []mcp.Tool {
661+ // Get session from context
662+ session := server.ClientSessionFromContext (ctx)
663+ if session == nil {
664+ return tools // Return all tools if no session
665+ }
666+
667+ // Example: filter tools based on session ID prefix
668+ if strings.HasPrefix (session.SessionID (), " admin-" ) {
669+ // Admin users get all tools
670+ return tools
671+ } else {
672+ // Regular users only get tools with "public-" prefix
673+ var filteredTools []mcp.Tool
674+ for _ , tool := range tools {
675+ if strings.HasPrefix (tool.Name , " public-" ) {
676+ filteredTools = append (filteredTools, tool)
677+ }
678+ }
679+ return filteredTools
680+ }
681+ }),
682+ )
683+ ```
684+
685+ #### Working with Context
686+
687+ The session context is automatically passed to tool and resource handlers:
688+
689+ ``` go
690+ s.AddTool (mcp.NewTool (" session_aware" ), func (ctx context.Context , req mcp.CallToolRequest ) (*mcp.CallToolResult , error ) {
691+ // Get the current session from context
692+ session := server.ClientSessionFromContext (ctx)
693+ if session == nil {
694+ return mcp.NewToolResultError (" No active session" ), nil
695+ }
696+
697+ return mcp.NewToolResultText (" Hello, session " + session.SessionID ()), nil
698+ })
699+
700+ // When using handlers in HTTP/SSE servers, you need to pass the context with the session
701+ httpHandler := func (w http.ResponseWriter , r *http.Request ) {
702+ // Get session from somewhere (like a cookie or header)
703+ session := getSessionFromRequest (r)
704+
705+ // Add session to context
706+ ctx := s.WithContext (r.Context (), session)
707+
708+ // Use this context when handling requests
709+ // ...
710+ }
711+ ```
712+
713+ </details >
714+
519715### Request Hooks
520716
521717Hook into the request lifecycle by creating a ` Hooks ` object with your
0 commit comments