Skip to content

Commit 08ff414

Browse files
committed
Add session managment docs to README
1 parent 9281b4a commit 08ff414

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

README.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

521717
Hook into the request lifecycle by creating a `Hooks` object with your

0 commit comments

Comments
 (0)