Commit dfce622

mo khan <mo@mokhan.ca>
2025-08-16 20:16:29
refactor: more tools
1 parent b9c1e47
Changed files (3)
cmd
pkg
cmd/imap/main.go
@@ -159,7 +159,7 @@ func main() {
 	}
 
 	// Create and start server
-	imapServer := imap.NewServer(*server, *username, *password, *port, *useTLS)
+	imapServer := imap.New(*server, *username, *password, *port, *useTLS)
 	
 	ctx := context.Background()
 	if err := imapServer.Run(ctx); err != nil {
pkg/imap/server.go
@@ -10,13 +10,13 @@ import (
 	"sync"
 	"time"
 
-	"github.com/emersion/go-imap"
+	goimap "github.com/emersion/go-imap"
 	"github.com/emersion/go-imap/client"
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-type Server struct {
-	*mcp.Server
+// ImapOperations provides IMAP email operations
+type ImapOperations struct {
 	mu       sync.RWMutex
 	client   *client.Client
 	server   string
@@ -65,350 +65,295 @@ type ConnectionInfo struct {
 	ServerInfo map[string]interface{} `json:"server_info"`
 }
 
-func NewServer(server, username, password string, port int, useTLS bool) *Server {
-	s := &Server{
-		Server:   mcp.NewServer("imap", "IMAP email server for reading and managing emails", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{}),
+// NewImapOperations creates a new ImapOperations helper
+func NewImapOperations(server, username, password string, port int, useTLS bool) *ImapOperations {
+	return &ImapOperations{
 		server:   server,
 		username: username,
 		password: password,
 		port:     port,
 		useTLS:   useTLS,
 	}
-
-	s.registerTools()
-
-	// Register prompts
-	analysisPrompt := mcp.Prompt{
-		Name:        "email-analysis",
-		Description: "Analyze email content with AI insights including sentiment, summary, and key points",
-	}
-	searchPrompt := mcp.Prompt{
-		Name:        "email-search",
-		Description: "Contextual email search with AI-powered insights and filtering",
-	}
-	s.RegisterPrompt(analysisPrompt, s.handleAnalysisPrompt)
-	s.RegisterPrompt(searchPrompt, s.handleSearchPrompt)
-
-	return s
 }
 
-// ListTools returns all available IMAP email management tools
-func (s *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "imap_list_folders",
-			Description: "List all folders in the email account (INBOX, Sent, Drafts, etc.)",
-			InputSchema: map[string]interface{}{
-				"type":       "object",
-				"properties": map[string]interface{}{},
+// New creates a new IMAP MCP server
+func New(server, username, password string, port int, useTLS bool) *mcp.Server {
+	imap := NewImapOperations(server, username, password, port, useTLS)
+	builder := mcp.NewServerBuilder("imap-server", "1.0.0")
+
+	// Add imap_list_folders tool
+	builder.AddTool(mcp.NewTool("imap_list_folders", "List all folders in the email account (INBOX, Sent, Drafts, etc.)", map[string]interface{}{
+		"type":       "object",
+		"properties": map[string]interface{}{},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleListFolders(req)
+	}))
+
+	// Add imap_list_messages tool  
+	builder.AddTool(mcp.NewTool("imap_list_messages", "List messages in a folder with optional pagination and filtering", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
 			},
-		},
-		{
-			Name:        "imap_list_messages",
-			Description: "List messages in a folder with optional pagination and filtering",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-					"limit": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of messages to return (default: 20)",
-						"minimum":     1,
-						"maximum":     100,
-					},
-					"offset": map[string]interface{}{
-						"type":        "integer",
-						"description": "Number of messages to skip (for pagination) (default: 0)",
-						"minimum":     0,
-					},
-					"unread_only": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Show only unread messages (default: false)",
-					},
-				},
+			"limit": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of messages to return (default: 20)",
+				"minimum":     1,
+				"maximum":     100,
 			},
-		},
-		{
-			Name:        "imap_read_message",
-			Description: "Read the full content of a specific email message",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uid": map[string]interface{}{
-						"type":        "integer",
-						"description": "Message UID",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-					"mark_as_read": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Mark message as read when reading (default: false)",
-					},
-				},
-				"required": []string{"uid"},
+			"offset": map[string]interface{}{
+				"type":        "integer",
+				"description": "Number of messages to skip (for pagination) (default: 0)",
+				"minimum":     0,
+			},
+			"unread_only": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Show only unread messages (default: false)",
 			},
 		},
-		{
-			Name:        "imap_search_messages",
-			Description: "Search for messages by content, sender, subject, or other criteria",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"query": map[string]interface{}{
-						"type":        "string",
-						"description": "Search query text",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder to search in (default: INBOX)",
-					},
-					"search_type": map[string]interface{}{
-						"type":        "string",
-						"description": "Type of search (subject, from, body, all) (default: all)",
-						"enum":        []string{"subject", "from", "to", "body", "all"},
-					},
-					"since_date": map[string]interface{}{
-						"type":        "string",
-						"description": "Search messages since this date (YYYY-MM-DD format)",
-					},
-					"before_date": map[string]interface{}{
-						"type":        "string",
-						"description": "Search messages before this date (YYYY-MM-DD format)",
-					},
-					"limit": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of results (default: 50)",
-						"minimum":     1,
-						"maximum":     200,
-					},
-				},
-				"required": []string{"query"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleListMessages(req)
+	}))
+
+	// Add imap_read_message tool
+	builder.AddTool(mcp.NewTool("imap_read_message", "Read the full content of a specific email message", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uid": map[string]interface{}{
+				"type":        "integer",
+				"description": "Message UID",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
+			},
+			"mark_as_read": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Mark message as read when reading (default: false)",
 			},
 		},
-		{
-			Name:        "imap_get_folder_stats",
-			Description: "Get statistics for a folder (total messages, unread count, etc.)",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-				},
+		"required": []string{"uid"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleReadMessage(req)
+	}))
+
+	// Add imap_search_messages tool
+	builder.AddTool(mcp.NewTool("imap_search_messages", "Search for messages by content, sender, subject, or other criteria", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"query": map[string]interface{}{
+				"type":        "string",
+				"description": "Search query text",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder to search in (default: INBOX)",
+			},
+			"search_type": map[string]interface{}{
+				"type":        "string",
+				"description": "Type of search (subject, from, body, all) (default: all)",
+				"enum":        []string{"subject", "from", "to", "body", "all"},
+			},
+			"since_date": map[string]interface{}{
+				"type":        "string",
+				"description": "Search messages since this date (YYYY-MM-DD format)",
+			},
+			"before_date": map[string]interface{}{
+				"type":        "string",
+				"description": "Search messages before this date (YYYY-MM-DD format)",
+			},
+			"limit": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of results (default: 50)",
+				"minimum":     1,
+				"maximum":     200,
 			},
 		},
-		{
-			Name:        "imap_mark_as_read",
-			Description: "Mark one or more messages as read or unread",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uid": map[string]interface{}{
-						"type":        "integer",
-						"description": "Message UID to mark",
-					},
-					"uids": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "integer",
-						},
-						"description": "Array of message UIDs to mark (alternative to single uid)",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-					"read": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Mark as read (true) or unread (false) (default: true)",
-					},
-				},
+		"required": []string{"query"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleSearchMessages(req)
+	}))
+
+	// Add imap_get_folder_stats tool
+	builder.AddTool(mcp.NewTool("imap_get_folder_stats", "Get statistics for a specific folder (message counts, sizes, etc.)", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
 			},
 		},
-		{
-			Name:        "imap_get_attachments",
-			Description: "List attachments for a message",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uid": map[string]interface{}{
-						"type":        "integer",
-						"description": "Message UID",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-				},
-				"required": []string{"uid"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleGetFolderStats(req)
+	}))
+
+	// Add imap_mark_as_read tool
+	builder.AddTool(mcp.NewTool("imap_mark_as_read", "Mark messages as read or unread", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uids": map[string]interface{}{
+				"type":        "array",
+				"items":       map[string]interface{}{"type": "integer"},
+				"description": "Array of message UIDs to mark",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
+			},
+			"mark_as_read": map[string]interface{}{
+				"type":        "boolean",
+				"description": "True to mark as read, false to mark as unread (default: true)",
 			},
 		},
-		{
-			Name:        "imap_get_connection_info",
-			Description: "Get information about the IMAP server connection and capabilities",
-			InputSchema: map[string]interface{}{
-				"type":       "object",
-				"properties": map[string]interface{}{},
+		"required": []string{"uids"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleMarkAsRead(req)
+	}))
+
+	// Add imap_get_attachments tool
+	builder.AddTool(mcp.NewTool("imap_get_attachments", "List attachments for a specific message (placeholder)", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uid": map[string]interface{}{
+				"type":        "integer",
+				"description": "Message UID",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
 			},
 		},
-		{
-			Name:        "imap_delete_message",
-			Description: "Delete a single message (requires confirmation for safety)",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uid": map[string]interface{}{
-						"type":        "integer",
-						"description": "Message UID to delete",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-					"confirmed": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Confirmation that you want to permanently delete this message",
-					},
-				},
-				"required": []string{"uid", "confirmed"},
+		"required": []string{"uid"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleGetAttachments(req)
+	}))
+
+	// Add imap_get_connection_info tool
+	builder.AddTool(mcp.NewTool("imap_get_connection_info", "Get IMAP server connection information and capabilities", map[string]interface{}{
+		"type": "object",
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleGetConnectionInfo(req)
+	}))
+
+	// Add imap_delete_message tool
+	builder.AddTool(mcp.NewTool("imap_delete_message", "Delete a single message (requires confirmation for safety)", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uid": map[string]interface{}{
+				"type":        "integer",
+				"description": "Message UID to delete",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
+			},
+			"confirmed": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Must be true to confirm permanent deletion",
 			},
 		},
-		{
-			Name:        "imap_delete_messages",
-			Description: "Delete multiple messages in bulk (requires confirmation for safety)",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uids": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "integer",
-						},
-						"description": "Array of message UIDs to delete",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name (default: INBOX)",
-					},
-					"confirmed": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Confirmation that you want to permanently delete these messages",
-					},
-				},
-				"required": []string{"uids", "confirmed"},
+		"required": []string{"uid", "confirmed"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleDeleteMessage(req)
+	}))
+
+	// Add imap_delete_messages tool
+	builder.AddTool(mcp.NewTool("imap_delete_messages", "Delete multiple messages at once (requires confirmation for safety)", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uids": map[string]interface{}{
+				"type":        "array",
+				"items":       map[string]interface{}{"type": "integer"},
+				"description": "Array of message UIDs to delete",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
+			},
+			"confirmed": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Must be true to confirm permanent deletion",
 			},
 		},
-		{
-			Name:        "imap_move_to_trash",
-			Description: "Move messages to trash folder (safer alternative to permanent deletion)",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"uid": map[string]interface{}{
-						"type":        "integer",
-						"description": "Message UID to move to trash",
-					},
-					"uids": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "integer",
-						},
-						"description": "Array of message UIDs to move to trash (alternative to single uid)",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Source folder name (default: INBOX)",
-					},
-					"trash_folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Trash folder name (default: Trash or [Gmail]/Trash)",
-					},
-				},
+		"required": []string{"uids", "confirmed"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleDeleteMessages(req)
+	}))
+
+	// Add imap_move_to_trash tool
+	builder.AddTool(mcp.NewTool("imap_move_to_trash", "Move messages to trash folder (safe, reversible deletion)", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"uids": map[string]interface{}{
+				"type":        "array",
+				"items":       map[string]interface{}{"type": "integer"},
+				"description": "Array of message UIDs to move to trash",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Source folder name (default: INBOX)",
+			},
+			"trash_folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Trash folder name (default: Trash)",
 			},
 		},
-		{
-			Name:        "imap_expunge_folder",
-			Description: "Permanently remove messages marked for deletion from a folder",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Folder name to expunge (default: INBOX)",
-					},
-					"confirmed": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Confirmation that you want to permanently expunge deleted messages",
-					},
-				},
-				"required": []string{"confirmed"},
+		"required": []string{"uids"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleMoveToTrash(req)
+	}))
+
+	// Add imap_expunge_folder tool
+	builder.AddTool(mcp.NewTool("imap_expunge_folder", "Permanently remove all messages marked for deletion from a folder", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Folder name (default: INBOX)",
+			},
+			"confirmed": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Must be true to confirm permanent expunge",
 			},
 		},
-	}
-}
+		"required": []string{"confirmed"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return imap.handleExpungeFolder(req)
+	}))
 
-// registerTools registers all IMAP tools with the server
-func (s *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := s.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "imap_list_folders":
-			handler = s.handleListFolders
-		case "imap_list_messages":
-			handler = s.handleListMessages
-		case "imap_read_message":
-			handler = s.handleReadMessage
-		case "imap_search_messages":
-			handler = s.handleSearchMessages
-		case "imap_get_folder_stats":
-			handler = s.handleGetFolderStats
-		case "imap_mark_as_read":
-			handler = s.handleMarkAsRead
-		case "imap_get_attachments":
-			handler = s.handleGetAttachments
-		case "imap_get_connection_info":
-			handler = s.handleGetConnectionInfo
-		case "imap_delete_message":
-			handler = s.handleDeleteMessage
-		case "imap_delete_messages":
-			handler = s.handleDeleteMessages
-		case "imap_move_to_trash":
-			handler = s.handleMoveToTrash
-		case "imap_expunge_folder":
-			handler = s.handleExpungeFolder
-		default:
-			continue
-		}
-		s.RegisterToolWithDefinition(tool, handler)
-	}
+	// Add prompts
+	builder.AddPrompt(mcp.NewPrompt("email-analysis", "Analyze email content with AI insights including sentiment, summary, and key points", []mcp.PromptArgument{}, func(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+		return imap.handleAnalysisPrompt(req)
+	}))
+
+	builder.AddPrompt(mcp.NewPrompt("email-search", "Contextual email search with AI-powered insights and filtering", []mcp.PromptArgument{}, func(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+		return imap.handleSearchPrompt(req)
+	}))
+
+	return builder.Build()
 }
 
-func (s *Server) connect() error {
-	if s.connected && s.client != nil {
+
+// Helper methods for ImapOperations
+
+func (imap *ImapOperations) connect() error {
+	if imap.connected && imap.client != nil {
 		return nil
 	}
 
-	address := fmt.Sprintf("%s:%d", s.server, s.port)
+	address := fmt.Sprintf("%s:%d", imap.server, imap.port)
 	
 	var c *client.Client
 	var err error
 
-	if s.useTLS {
-		c, err = client.DialTLS(address, &tls.Config{ServerName: s.server})
+	if imap.useTLS {
+		c, err = client.DialTLS(address, &tls.Config{ServerName: imap.server})
 	} else {
 		c, err = client.Dial(address)
 		if err == nil {
-			if err = c.StartTLS(&tls.Config{ServerName: s.server}); err != nil {
+			if err = c.StartTLS(&tls.Config{ServerName: imap.server}); err != nil {
 				log.Printf("STARTTLS failed: %v", err)
 			}
 		}
@@ -418,46 +363,46 @@ func (s *Server) connect() error {
 		return fmt.Errorf("failed to connect to IMAP server: %v", err)
 	}
 
-	if err = c.Login(s.username, s.password); err != nil {
+	if err = c.Login(imap.username, imap.password); err != nil {
 		c.Close()
 		return fmt.Errorf("authentication failed: %v", err)
 	}
 
-	s.mu.Lock()
-	s.client = c
-	s.connected = true
-	s.mu.Unlock()
+	imap.mu.Lock()
+	imap.client = c
+	imap.connected = true
+	imap.mu.Unlock()
 
 	return nil
 }
 
-func (s *Server) ensureConnection() error {
-	s.mu.RLock()
-	connected := s.connected
-	s.mu.RUnlock()
+func (imap *ImapOperations) ensureConnection() error {
+	imap.mu.RLock()
+	connected := imap.connected
+	imap.mu.RUnlock()
 
 	if !connected {
-		return s.connect()
+		return imap.connect()
 	}
 	return nil
 }
 
-func (s *Server) handleListFolders(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleListFolders(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
-	mailboxes := make(chan *imap.MailboxInfo, 10)
+	mailboxes := make(chan *goimap.MailboxInfo, 10)
 	done := make(chan error, 1)
 	go func() {
 		done <- client.List("", "*", mailboxes)
 	}()
 
-	var mailboxList []*imap.MailboxInfo
+	var mailboxList []*goimap.MailboxInfo
 	for m := range mailboxes {
 		mailboxList = append(mailboxList, m)
 	}
@@ -494,8 +439,8 @@ func (s *Server) handleListFolders(req mcp.CallToolRequest) (mcp.CallToolResult,
 	}, nil
 }
 
-func (s *Server) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -509,9 +454,9 @@ func (s *Server) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult
 		limit = int(l)
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	mbox, err := client.Select(folder, true)
 	if err != nil {
@@ -530,13 +475,13 @@ func (s *Server) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult
 		from = mbox.Messages - uint32(limit) + 1
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddRange(from, to)
 
-	messages := make(chan *imap.Message, 10)
+	messages := make(chan *goimap.Message, 10)
 	done := make(chan error, 1)
 	go func() {
-		done <- client.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchRFC822Size}, messages)
+		done <- client.Fetch(seqset, []goimap.FetchItem{goimap.FetchEnvelope, goimap.FetchFlags, goimap.FetchRFC822Size}, messages)
 	}()
 
 	var messageList []MessageInfo
@@ -590,8 +535,8 @@ func (s *Server) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult
 	}, nil
 }
 
-func (s *Server) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -613,24 +558,24 @@ func (s *Server) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult,
 		return mcp.NewToolError("uid parameter is required"), nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, true); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uid)
 
-	messages := make(chan *imap.Message, 1)
+	messages := make(chan *goimap.Message, 1)
 	done := make(chan error, 1)
 	go func() {
-		done <- client.UidFetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchRFC822Size, imap.FetchRFC822}, messages)
+		done <- client.UidFetch(seqset, []goimap.FetchItem{goimap.FetchEnvelope, goimap.FetchFlags, goimap.FetchRFC822Size, goimap.FetchRFC822}, messages)
 	}()
 
-	var message *imap.Message
+	var message *goimap.Message
 	for msg := range messages {
 		message = msg
 		break
@@ -645,7 +590,7 @@ func (s *Server) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult,
 	}
 
 	var body string
-	if r := message.GetBody(&imap.BodySectionName{}); r != nil {
+	if r := message.GetBody(&goimap.BodySectionName{}); r != nil {
 		if bodyBytes, err := io.ReadAll(r); err == nil {
 			body = string(bodyBytes)
 		}
@@ -692,8 +637,8 @@ func (s *Server) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult,
 	}, nil
 }
 
-func (s *Server) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -707,15 +652,15 @@ func (s *Server) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResu
 		return mcp.NewToolError("query parameter is required"), nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	criteria := &imap.SearchCriteria{
+	criteria := &goimap.SearchCriteria{
 		Text: []string{query},
 	}
 
@@ -742,13 +687,13 @@ func (s *Server) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResu
 		}, nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uids...)
 
-	messages := make(chan *imap.Message, 10)
+	messages := make(chan *goimap.Message, 10)
 	done := make(chan error, 1)
 	go func() {
-		done <- client.UidFetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchRFC822Size}, messages)
+		done <- client.UidFetch(seqset, []goimap.FetchItem{goimap.FetchEnvelope, goimap.FetchFlags, goimap.FetchRFC822Size}, messages)
 	}()
 
 	var messageList []MessageInfo
@@ -802,8 +747,8 @@ func (s *Server) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResu
 	}, nil
 }
 
-func (s *Server) handleGetFolderStats(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleGetFolderStats(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -812,9 +757,9 @@ func (s *Server) handleGetFolderStats(req mcp.CallToolRequest) (mcp.CallToolResu
 		folder = f
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	mbox, err := client.Select(folder, true)
 	if err != nil {
@@ -834,8 +779,8 @@ func (s *Server) handleGetFolderStats(req mcp.CallToolRequest) (mcp.CallToolResu
 	}, nil
 }
 
-func (s *Server) handleMarkAsRead(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleMarkAsRead(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -862,27 +807,27 @@ func (s *Server) handleMarkAsRead(req mcp.CallToolRequest) (mcp.CallToolResult,
 		markAsRead = mar
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uid)
 
-	var operation imap.StoreItem
-	flags := []interface{}{imap.SeenFlag}
+	var operation goimap.StoreItem
+	flags := []interface{}{goimap.SeenFlag}
 	
 	if markAsRead {
-		operation = imap.FormatFlagsOp(imap.AddFlags, true)
+		operation = goimap.FormatFlagsOp(goimap.AddFlags, true)
 	} else {
-		operation = imap.FormatFlagsOp(imap.RemoveFlags, true)
+		operation = goimap.FormatFlagsOp(goimap.RemoveFlags, true)
 	}
 
-	ch := make(chan *imap.Message, 1)
+	ch := make(chan *goimap.Message, 1)
 	if err := client.UidStore(seqset, operation, flags, ch); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to update message flags: %v", err)), nil
 	}
@@ -900,23 +845,23 @@ func (s *Server) handleMarkAsRead(req mcp.CallToolRequest) (mcp.CallToolResult,
 	}, nil
 }
 
-func (s *Server) handleGetAttachments(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (imap *ImapOperations) handleGetAttachments(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	return mcp.CallToolResult{
 		Content: []mcp.Content{mcp.TextContent{Type: "text", Text: "Attachment handling not yet implemented"}},
 	}, nil
 }
 
-func (s *Server) handleGetConnectionInfo(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	s.mu.RLock()
-	connected := s.connected
-	client := s.client
-	s.mu.RUnlock()
+func (imap *ImapOperations) handleGetConnectionInfo(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	imap.mu.RLock()
+	connected := imap.connected
+	client := imap.client
+	imap.mu.RUnlock()
 
 	info := ConnectionInfo{
-		Server:    s.server,
-		Username:  s.username,
-		Port:      s.port,
-		UseTLS:    s.useTLS,
+		Server:    imap.server,
+		Username:  imap.username,
+		Port:      imap.port,
+		UseTLS:    imap.useTLS,
 		Connected: connected,
 		Capabilities: []string{},
 		ServerInfo: make(map[string]interface{}),
@@ -941,15 +886,15 @@ func (s *Server) handleGetConnectionInfo(req mcp.CallToolRequest) (mcp.CallToolR
 	}, nil
 }
 
-func (s *Server) handleAnalysisPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
-	return s.getEmailAnalysisPrompt(req.Arguments)
+func (imap *ImapOperations) handleAnalysisPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+	return imap.getEmailAnalysisPrompt(req.Arguments)
 }
 
-func (s *Server) handleSearchPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
-	return s.getEmailSearchPrompt(req.Arguments)
+func (imap *ImapOperations) handleSearchPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+	return imap.getEmailSearchPrompt(req.Arguments)
 }
 
-func (s *Server) getEmailAnalysisPrompt(args map[string]interface{}) (mcp.GetPromptResult, error) {
+func (imap *ImapOperations) getEmailAnalysisPrompt(args map[string]interface{}) (mcp.GetPromptResult, error) {
 	prompt := `Analyze the provided email content and provide insights including:
 
 1. **Sentiment Analysis**: Overall tone (positive, negative, neutral)
@@ -978,7 +923,7 @@ Please provide your analysis in a structured format with clear sections.`
 	}, nil
 }
 
-func (s *Server) getEmailSearchPrompt(args map[string]interface{}) (mcp.GetPromptResult, error) {
+func (imap *ImapOperations) getEmailSearchPrompt(args map[string]interface{}) (mcp.GetPromptResult, error) {
 	query, ok := args["query"].(string)
 	if !ok {
 		return mcp.GetPromptResult{}, fmt.Errorf("query parameter is required")
@@ -1020,8 +965,8 @@ Use IMAP search capabilities effectively to find the most relevant emails.`
 	}, nil
 }
 
-func (s *Server) handleDeleteMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleDeleteMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -1055,22 +1000,22 @@ func (s *Server) handleDeleteMessage(req mcp.CallToolRequest) (mcp.CallToolResul
 		}, nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uid)
 
 	// Mark as deleted
-	operation := imap.FormatFlagsOp(imap.AddFlags, true)
-	flags := []interface{}{imap.DeletedFlag}
+	operation := goimap.FormatFlagsOp(goimap.AddFlags, true)
+	flags := []interface{}{goimap.DeletedFlag}
 
-	ch := make(chan *imap.Message, 1)
+	ch := make(chan *goimap.Message, 1)
 	if err := client.UidStore(seqset, operation, flags, ch); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to mark message as deleted: %v", err)), nil
 	}
@@ -1088,8 +1033,8 @@ func (s *Server) handleDeleteMessage(req mcp.CallToolRequest) (mcp.CallToolResul
 	}, nil
 }
 
-func (s *Server) handleDeleteMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleDeleteMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -1129,22 +1074,22 @@ func (s *Server) handleDeleteMessages(req mcp.CallToolRequest) (mcp.CallToolResu
 		}, nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uids...)
 
 	// Mark as deleted
-	operation := imap.FormatFlagsOp(imap.AddFlags, true)
-	flags := []interface{}{imap.DeletedFlag}
+	operation := goimap.FormatFlagsOp(goimap.AddFlags, true)
+	flags := []interface{}{goimap.DeletedFlag}
 
-	ch := make(chan *imap.Message, 10)
+	ch := make(chan *goimap.Message, 10)
 	if err := client.UidStore(seqset, operation, flags, ch); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to mark messages as deleted: %v", err)), nil
 	}
@@ -1162,8 +1107,8 @@ func (s *Server) handleDeleteMessages(req mcp.CallToolRequest) (mcp.CallToolResu
 	}, nil
 }
 
-func (s *Server) handleMoveToTrash(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleMoveToTrash(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -1202,15 +1147,15 @@ func (s *Server) handleMoveToTrash(req mcp.CallToolRequest) (mcp.CallToolResult,
 		return mcp.NewToolError("uid or uids parameter is required"), nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
 	}
 
-	seqset := new(imap.SeqSet)
+	seqset := new(goimap.SeqSet)
 	seqset.AddNum(uids...)
 
 	// Try to use MOVE command (Gmail supports this)
@@ -1221,10 +1166,10 @@ func (s *Server) handleMoveToTrash(req mcp.CallToolRequest) (mcp.CallToolResult,
 		}
 
 		// Mark original messages as deleted
-		operation := imap.FormatFlagsOp(imap.AddFlags, true)
-		flags := []interface{}{imap.DeletedFlag}
+		operation := goimap.FormatFlagsOp(goimap.AddFlags, true)
+		flags := []interface{}{goimap.DeletedFlag}
 
-		ch := make(chan *imap.Message, 10)
+		ch := make(chan *goimap.Message, 10)
 		if err := client.UidStore(seqset, operation, flags, ch); err != nil {
 			return mcp.NewToolError(fmt.Sprintf("Failed to mark messages as deleted: %v", err)), nil
 		}
@@ -1242,8 +1187,8 @@ func (s *Server) handleMoveToTrash(req mcp.CallToolRequest) (mcp.CallToolResult,
 	}, nil
 }
 
-func (s *Server) handleExpungeFolder(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	if err := s.ensureConnection(); err != nil {
+func (imap *ImapOperations) handleExpungeFolder(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	if err := imap.ensureConnection(); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Connection failed: %v", err)), nil
 	}
 
@@ -1264,9 +1209,9 @@ func (s *Server) handleExpungeFolder(req mcp.CallToolRequest) (mcp.CallToolResul
 		}, nil
 	}
 
-	s.mu.RLock()
-	client := s.client
-	s.mu.RUnlock()
+	imap.mu.RLock()
+	client := imap.client
+	imap.mu.RUnlock()
 
 	if _, err := client.Select(folder, false); err != nil {
 		return mcp.NewToolError(fmt.Sprintf("Failed to select folder %s: %v", folder, err)), nil
@@ -1281,14 +1226,14 @@ func (s *Server) handleExpungeFolder(req mcp.CallToolRequest) (mcp.CallToolResul
 	}, nil
 }
 
-func (s *Server) Close() error {
-	s.mu.Lock()
-	defer s.mu.Unlock()
+func (imap *ImapOperations) Close() error {
+	imap.mu.Lock()
+	defer imap.mu.Unlock()
 
-	if s.client != nil {
-		s.client.Close()
-		s.client = nil
+	if imap.client != nil {
+		imap.client.Close()
+		imap.client = nil
 	}
-	s.connected = false
+	imap.connected = false
 	return nil
 }
pkg/maildir/server.go
@@ -17,9 +17,8 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Maildir MCP server
-type Server struct {
-	*mcp.Server
+// MaildirOperations provides maildir email analysis operations
+type MaildirOperations struct {
 	allowedPaths []string
 }
 
@@ -65,10 +64,8 @@ type ContactInfo struct {
 	IsOutgoing bool      `json:"is_outgoing"`
 }
 
-// New creates a new Maildir MCP server
-func New(allowedPaths []string) *Server {
-	server := mcp.NewServer("maildir-server", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
-
+// NewMaildirOperations creates a new MaildirOperations helper
+func NewMaildirOperations(allowedPaths []string) *MaildirOperations {
 	// Normalize and validate allowed paths
 	normalizedPaths := make([]string, len(allowedPaths))
 	for i, path := range allowedPaths {
@@ -79,228 +76,151 @@ func New(allowedPaths []string) *Server {
 		normalizedPaths[i] = filepath.Clean(absPath)
 	}
 
-	maildirServer := &Server{
-		Server:       server,
+	return &MaildirOperations{
 		allowedPaths: normalizedPaths,
 	}
-
-	// Register all maildir tools, prompts, resources, and roots
-	maildirServer.registerTools()
-	maildirServer.registerPrompts()
-	maildirServer.registerResources()
-	maildirServer.registerRoots()
-
-	return maildirServer
 }
 
-
-// ListTools returns all available Maildir tools
-func (ms *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "maildir_scan_folders",
-			Description: "Scan and list all folders in the Maildir structure",
-			InputSchema: map[string]interface{}{
-				"type": "object",
+// New creates a new Maildir MCP server
+func New(allowedPaths []string) *mcp.Server {
+	maildir := NewMaildirOperations(allowedPaths)
+	builder := mcp.NewServerBuilder("maildir-server", "1.0.0")
+
+	// Add maildir_scan_folders tool
+	builder.AddTool(mcp.NewTool("maildir_scan_folders", "Scan and list all folders in the Maildir structure", map[string]interface{}{
+		"type": "object",
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleScanFolders(req)
+	}))
+
+	// Add maildir_list_messages tool
+	builder.AddTool(mcp.NewTool("maildir_list_messages", "List messages in a specific folder with optional pagination and filtering", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "The folder name to list messages from",
 			},
-		},
-		{
-			Name:        "maildir_list_messages",
-			Description: "List messages in a specific folder with optional pagination and filtering",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "The folder name to list messages from",
-					},
-					"limit": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of messages to return",
-						"minimum":     1,
-						"default":     50,
-					},
-					"offset": map[string]interface{}{
-						"type":        "integer",
-						"description": "Number of messages to skip",
-						"minimum":     0,
-						"default":     0,
-					},
-					"unread_only": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Only return unread messages",
-						"default":     false,
-					},
-				},
-				"required": []string{"folder"},
+			"limit": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of messages to return",
+				"minimum":     1,
+				"default":     50,
 			},
-		},
-		{
-			Name:        "maildir_read_message",
-			Description: "Read the full content of a specific message",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"message_id": map[string]interface{}{
-						"type":        "string",
-						"description": "The unique message ID",
-					},
-				},
-				"required": []string{"message_id"},
+			"offset": map[string]interface{}{
+				"type":        "integer",
+				"description": "Number of messages to skip",
+				"minimum":     0,
+				"default":     0,
+			},
+			"unread_only": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Only return unread messages",
+				"default":     false,
 			},
 		},
-		{
-			Name:        "maildir_search_messages",
-			Description: "Search for messages across all folders using various criteria",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"query": map[string]interface{}{
-						"type":        "string",
-						"description": "Search query string",
-					},
-					"sender": map[string]interface{}{
-						"type":        "string",
-						"description": "Filter by sender email or name",
-					},
-					"subject": map[string]interface{}{
-						"type":        "string",
-						"description": "Filter by subject line",
-					},
-					"folder": map[string]interface{}{
-						"type":        "string",
-						"description": "Limit search to specific folder",
-					},
-					"limit": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of results",
-						"minimum":     1,
-						"default":     50,
-					},
-				},
+		"required": []string{"folder"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleListMessages(req)
+	}))
+
+	// Add maildir_read_message tool
+	builder.AddTool(mcp.NewTool("maildir_read_message", "Read the full content of a specific message", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"message_id": map[string]interface{}{
+				"type":        "string",
+				"description": "The unique message ID",
 			},
 		},
-		{
-			Name:        "maildir_get_thread",
-			Description: "Get all messages in a conversation thread",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"message_id": map[string]interface{}{
-						"type":        "string",
-						"description": "Message ID to find thread for",
-					},
-				},
-				"required": []string{"message_id"},
+		"required": []string{"message_id"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleReadMessage(req)
+	}))
+
+	// Add maildir_search_messages tool
+	builder.AddTool(mcp.NewTool("maildir_search_messages", "Search for messages across all folders using various criteria", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"query": map[string]interface{}{
+				"type":        "string",
+				"description": "Search query string",
+			},
+			"sender": map[string]interface{}{
+				"type":        "string",
+				"description": "Filter by sender email or name",
+			},
+			"subject": map[string]interface{}{
+				"type":        "string",
+				"description": "Filter by subject line",
+			},
+			"folder": map[string]interface{}{
+				"type":        "string",
+				"description": "Limit search to specific folder",
+			},
+			"limit": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of results",
+				"minimum":     1,
+				"default":     50,
 			},
 		},
-		{
-			Name:        "maildir_analyze_contacts",
-			Description: "Analyze contact frequency and relationship data from email history",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"limit": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of contacts to analyze",
-						"minimum":     1,
-						"default":     100,
-					},
-				},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleSearchMessages(req)
+	}))
+
+	// Add maildir_get_thread tool
+	builder.AddTool(mcp.NewTool("maildir_get_thread", "Get all messages in a conversation thread", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"message_id": map[string]interface{}{
+				"type":        "string",
+				"description": "Message ID to find thread for",
 			},
 		},
-		{
-			Name:        "maildir_get_statistics",
-			Description: "Get comprehensive statistics about the maildir including message counts, storage usage, and activity patterns",
-			InputSchema: map[string]interface{}{
-				"type": "object",
+		"required": []string{"message_id"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleGetThread(req)
+	}))
+
+	// Add maildir_analyze_contacts tool
+	builder.AddTool(mcp.NewTool("maildir_analyze_contacts", "Analyze contact frequency and relationship data from email history", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"limit": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of contacts to analyze",
+				"minimum":     1,
+				"default":     100,
 			},
 		},
-	}
-}
-
-// registerTools registers all Maildir tools with the server
-func (ms *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := ms.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "maildir_scan_folders":
-			handler = ms.HandleScanFolders
-		case "maildir_list_messages":
-			handler = ms.HandleListMessages
-		case "maildir_read_message":
-			handler = ms.HandleReadMessage
-		case "maildir_search_messages":
-			handler = ms.HandleSearchMessages
-		case "maildir_get_thread":
-			handler = ms.HandleGetThread
-		case "maildir_analyze_contacts":
-			handler = ms.HandleAnalyzeContacts
-		case "maildir_get_statistics":
-			handler = ms.HandleGetStatistics
-		default:
-			continue
-		}
-		ms.RegisterToolWithDefinition(tool, handler)
-	}
-}
-
-// registerPrompts registers all Maildir prompts with the server
-func (ms *Server) registerPrompts() {
-	// No specific prompts for maildir at the moment
-}
-
-// registerResources sets up resource handling (lazy loading)
-func (ms *Server) registerResources() {
-	// Register placeholder resources for each allowed path to make them discoverable
-	for _, path := range ms.allowedPaths {
-		maildirURI := "maildir://" + path
-		pathName := filepath.Base(path)
-		if pathName == "." || pathName == "/" {
-			pathName = path
-		}
-		
-		resource := mcp.Resource{
-			URI:         maildirURI,
-			Name:        fmt.Sprintf("Maildir: %s", pathName),
-			Description: fmt.Sprintf("Maildir folders in %s", path),
-			MimeType:    "application/x-maildir",
-		}
-		
-		ms.Server.RegisterResourceWithDefinition(resource, ms.HandleReadResource)
-	}
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleAnalyzeContacts(req)
+	}))
+
+	// Add maildir_get_statistics tool
+	builder.AddTool(mcp.NewTool("maildir_get_statistics", "Get comprehensive statistics about the maildir including message counts, storage usage, and activity patterns", map[string]interface{}{
+		"type": "object",
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return maildir.handleGetStatistics(req)
+	}))
+
+	return builder.Build()
 }
 
-// registerRoots registers maildir paths as roots
-func (ms *Server) registerRoots() {
-	for _, path := range ms.allowedPaths {
-		// Create maildir:// URI for the path
-		maildirURI := "maildir://" + path
 
-		// Create a user-friendly name from the path
-		pathName := filepath.Base(path)
-		if pathName == "." || pathName == "/" {
-			pathName = path
-		}
+// Helper methods for MaildirOperations
 
-		root := mcp.NewRoot(maildirURI, fmt.Sprintf("Maildir: %s", pathName))
-		ms.RegisterRoot(root)
-	}
-}
 
 
 // HandleScanFolders implements the maildir_scan_folders tool
-func (ms *Server) HandleScanFolders(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleScanFolders(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
@@ -309,7 +229,7 @@ func (ms *Server) HandleScanFolders(req mcp.CallToolRequest) (mcp.CallToolResult
 		includeCounts = ic
 	}
 
-	folders, err := ms.scanFolders(maildirPath, includeCounts)
+	folders, err := maildir.scanFolders(maildirPath, includeCounts)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to scan folders: %v", err)), nil
 	}
@@ -325,13 +245,13 @@ func (ms *Server) HandleScanFolders(req mcp.CallToolRequest) (mcp.CallToolResult
 }
 
 // HandleListMessages implements the maildir_list_messages tool
-func (ms *Server) HandleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleListMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
@@ -353,7 +273,7 @@ func (ms *Server) HandleListMessages(req mcp.CallToolRequest) (mcp.CallToolResul
 		offset = int(o)
 	}
 
-	messages, total, err := ms.listMessages(maildirPath, folder, limit, offset, req.Arguments)
+	messages, total, err := maildir.listMessages(maildirPath, folder, limit, offset, req.Arguments)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to list messages: %v", err)), nil
 	}
@@ -372,13 +292,13 @@ func (ms *Server) HandleListMessages(req mcp.CallToolRequest) (mcp.CallToolResul
 }
 
 // HandleReadMessage implements the maildir_read_message tool
-func (ms *Server) HandleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
@@ -402,7 +322,7 @@ func (ms *Server) HandleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult
 		sanitizeContent = sc
 	}
 
-	message, err := ms.readMessage(maildirPath, messageID, includeHTML, includeHeaders, sanitizeContent)
+	message, err := maildir.readMessage(maildirPath, messageID, includeHTML, includeHeaders, sanitizeContent)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to read message: %v", err)), nil
 	}
@@ -416,13 +336,13 @@ func (ms *Server) HandleReadMessage(req mcp.CallToolRequest) (mcp.CallToolResult
 }
 
 // HandleSearchMessages implements the maildir_search_messages tool
-func (ms *Server) HandleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
@@ -439,7 +359,7 @@ func (ms *Server) HandleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolRes
 		}
 	}
 
-	results, err := ms.searchMessages(maildirPath, query, limit, req.Arguments)
+	results, err := maildir.searchMessages(maildirPath, query, limit, req.Arguments)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to search messages: %v", err)), nil
 	}
@@ -456,13 +376,13 @@ func (ms *Server) HandleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolRes
 }
 
 // HandleGetThread implements the maildir_get_thread tool
-func (ms *Server) HandleGetThread(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleGetThread(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
@@ -476,7 +396,7 @@ func (ms *Server) HandleGetThread(req mcp.CallToolRequest) (mcp.CallToolResult,
 		maxDepth = int(md)
 	}
 
-	thread, err := ms.getThread(maildirPath, messageID, maxDepth)
+	thread, err := maildir.getThread(maildirPath, messageID, maxDepth)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to get thread: %v", err)), nil
 	}
@@ -492,17 +412,17 @@ func (ms *Server) HandleGetThread(req mcp.CallToolRequest) (mcp.CallToolResult,
 }
 
 // HandleAnalyzeContacts implements the maildir_analyze_contacts tool
-func (ms *Server) HandleAnalyzeContacts(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleAnalyzeContacts(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
-	contacts, err := ms.analyzeContacts(maildirPath, req.Arguments)
+	contacts, err := maildir.analyzeContacts(maildirPath, req.Arguments)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to analyze contacts: %v", err)), nil
 	}
@@ -518,17 +438,17 @@ func (ms *Server) HandleAnalyzeContacts(req mcp.CallToolRequest) (mcp.CallToolRe
 }
 
 // HandleGetStatistics implements the maildir_get_statistics tool
-func (ms *Server) HandleGetStatistics(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (maildir *MaildirOperations) handleGetStatistics(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	maildirPath, ok := req.Arguments["maildir_path"].(string)
 	if !ok {
 		return mcp.NewToolError("maildir_path is required"), nil
 	}
 
-	if !ms.isPathAllowed(maildirPath) {
+	if !maildir.isPathAllowed(maildirPath) {
 		return mcp.NewToolError("access denied: path not in allowed directories"), nil
 	}
 
-	stats, err := ms.getStatistics(maildirPath, req.Arguments)
+	stats, err := maildir.getStatistics(maildirPath, req.Arguments)
 	if err != nil {
 		return mcp.NewToolError(fmt.Sprintf("failed to get statistics: %v", err)), nil
 	}
@@ -541,48 +461,18 @@ func (ms *Server) HandleGetStatistics(req mcp.CallToolRequest) (mcp.CallToolResu
 	return mcp.NewToolResult(mcp.NewTextContent(string(result))), nil
 }
 
-// HandleReadResource implements resource reading for maildir URIs
-func (ms *Server) HandleReadResource(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
-	// Parse the maildir URI to extract path and folder
-	uri := req.URI
-	if !strings.HasPrefix(uri, "maildir://") {
-		return mcp.ReadResourceResult{}, fmt.Errorf("invalid maildir URI: %s", uri)
-	}
-
-	path := strings.TrimPrefix(uri, "maildir://")
-	
-	// For now, return folder information as JSON
-	folders, err := ms.scanFolders(path, true)
-	if err != nil {
-		return mcp.ReadResourceResult{}, fmt.Errorf("failed to scan maildir: %v", err)
-	}
-
-	result, err := json.Marshal(map[string]interface{}{
-		"folders": folders,
-		"uri":     uri,
-	})
-	if err != nil {
-		return mcp.ReadResourceResult{}, fmt.Errorf("failed to marshal result: %v", err)
-	}
-
-	return mcp.ReadResourceResult{
-		Contents: []mcp.Content{
-			mcp.NewTextContent(string(result)),
-		},
-	}, nil
-}
 
 // Helper functions
 
 // isPathAllowed checks if the given path is within allowed directories
-func (ms *Server) isPathAllowed(path string) bool {
+func (maildir *MaildirOperations) isPathAllowed(path string) bool {
 	absPath, err := filepath.Abs(expandHome(path))
 	if err != nil {
 		return false
 	}
 	absPath = filepath.Clean(absPath)
 
-	for _, allowedPath := range ms.allowedPaths {
+	for _, allowedPath := range maildir.allowedPaths {
 		if strings.HasPrefix(absPath, allowedPath) {
 			return true
 		}
@@ -603,7 +493,7 @@ func expandHome(path string) string {
 }
 
 // scanFolders scans maildir folders and returns folder information
-func (ms *Server) scanFolders(maildirPath string, includeCounts bool) ([]FolderInfo, error) {
+func (maildir *MaildirOperations) scanFolders(maildirPath string, includeCounts bool) ([]FolderInfo, error) {
 	var folders []FolderInfo
 
 	// Walk the maildir directory to find folders
@@ -637,8 +527,8 @@ func (ms *Server) scanFolders(maildirPath string, includeCounts bool) ([]FolderI
 
 					if includeCounts {
 						// Count messages in cur and new directories
-						curCount := ms.countMessagesInDir(curDir)
-						newCount := ms.countMessagesInDir(newDir)
+						curCount := maildir.countMessagesInDir(curDir)
+						newCount := maildir.countMessagesInDir(newDir)
 						folder.MessageCount = curCount + newCount
 						folder.UnreadCount = newCount
 					}
@@ -664,7 +554,7 @@ func (ms *Server) scanFolders(maildirPath string, includeCounts bool) ([]FolderI
 }
 
 // countMessagesInDir counts the number of message files in a directory
-func (ms *Server) countMessagesInDir(dirPath string) int {
+func (maildir *MaildirOperations) countMessagesInDir(dirPath string) int {
 	entries, err := os.ReadDir(dirPath)
 	if err != nil {
 		return 0
@@ -672,7 +562,7 @@ func (ms *Server) countMessagesInDir(dirPath string) int {
 
 	count := 0
 	for _, entry := range entries {
-		if !entry.IsDir() && ms.isMaildirMessage(entry.Name()) {
+		if !entry.IsDir() && maildir.isMaildirMessage(entry.Name()) {
 			count++
 		}
 	}
@@ -680,13 +570,13 @@ func (ms *Server) countMessagesInDir(dirPath string) int {
 }
 
 // isMaildirMessage checks if a filename looks like a maildir message
-func (ms *Server) isMaildirMessage(filename string) bool {
+func (maildir *MaildirOperations) isMaildirMessage(filename string) bool {
 	// Basic check for maildir message format
 	return strings.Contains(filename, ".") && !strings.HasPrefix(filename, ".")
 }
 
 // listMessages lists messages in a specific folder with filtering and pagination
-func (ms *Server) listMessages(maildirPath, folder string, limit, offset int, filters map[string]interface{}) ([]MessageInfo, int, error) {
+func (maildir *MaildirOperations) listMessages(maildirPath, folder string, limit, offset int, filters map[string]interface{}) ([]MessageInfo, int, error) {
 	folderPath := filepath.Join(maildirPath, folder)
 	if folder == "INBOX" && maildirPath == folderPath {
 		// Handle case where INBOX might be the root maildir
@@ -698,7 +588,7 @@ func (ms *Server) listMessages(maildirPath, folder string, limit, offset int, fi
 	// Scan cur and new directories
 	for _, subdir := range []string{"cur", "new"} {
 		dirPath := filepath.Join(folderPath, subdir)
-		messages, err := ms.scanMessagesInDir(dirPath, folder, subdir == "new")
+		messages, err := maildir.scanMessagesInDir(dirPath, folder, subdir == "new")
 		if err != nil {
 			continue // Skip if directory doesn't exist or can't be read
 		}
@@ -706,7 +596,7 @@ func (ms *Server) listMessages(maildirPath, folder string, limit, offset int, fi
 	}
 
 	// Apply filters
-	filteredMessages := ms.applyMessageFilters(allMessages, filters)
+	filteredMessages := maildir.applyMessageFilters(allMessages, filters)
 
 	// Sort by date (newest first)
 	sort.Slice(filteredMessages, func(i, j int) bool {
@@ -730,7 +620,7 @@ func (ms *Server) listMessages(maildirPath, folder string, limit, offset int, fi
 }
 
 // scanMessagesInDir scans messages in a specific directory
-func (ms *Server) scanMessagesInDir(dirPath, folder string, isNew bool) ([]MessageInfo, error) {
+func (maildir *MaildirOperations) scanMessagesInDir(dirPath, folder string, isNew bool) ([]MessageInfo, error) {
 	entries, err := os.ReadDir(dirPath)
 	if err != nil {
 		return nil, err
@@ -738,12 +628,12 @@ func (ms *Server) scanMessagesInDir(dirPath, folder string, isNew bool) ([]Messa
 
 	var messages []MessageInfo
 	for _, entry := range entries {
-		if entry.IsDir() || !ms.isMaildirMessage(entry.Name()) {
+		if entry.IsDir() || !maildir.isMaildirMessage(entry.Name()) {
 			continue
 		}
 
 		messagePath := filepath.Join(dirPath, entry.Name())
-		message, err := ms.parseMessageInfo(messagePath, folder, entry.Name(), isNew)
+		message, err := maildir.parseMessageInfo(messagePath, folder, entry.Name(), isNew)
 		if err != nil {
 			continue // Skip malformed messages
 		}
@@ -755,7 +645,7 @@ func (ms *Server) scanMessagesInDir(dirPath, folder string, isNew bool) ([]Messa
 }
 
 // parseMessageInfo parses basic message information from a maildir message file
-func (ms *Server) parseMessageInfo(messagePath, folder, filename string, isNew bool) (MessageInfo, error) {
+func (maildir *MaildirOperations) parseMessageInfo(messagePath, folder, filename string, isNew bool) (MessageInfo, error) {
 	file, err := os.Open(messagePath)
 	if err != nil {
 		return MessageInfo{}, err
@@ -775,7 +665,7 @@ func (ms *Server) parseMessageInfo(messagePath, folder, filename string, isNew b
 	}
 
 	// Extract flags from filename
-	flags := ms.parseMaildirFlags(filename, isNew)
+	flags := maildir.parseMaildirFlags(filename, isNew)
 
 	// Parse date
 	dateStr := msg.Header.Get("Date")
@@ -785,10 +675,10 @@ func (ms *Server) parseMessageInfo(messagePath, folder, filename string, isNew b
 	}
 
 	// Extract references for threading
-	references := ms.parseReferences(msg.Header.Get("References"))
+	references := maildir.parseReferences(msg.Header.Get("References"))
 
 	messageInfo := MessageInfo{
-		ID:        ms.generateMessageID(messagePath),
+		ID:        maildir.generateMessageID(messagePath),
 		Filename:  filename,
 		Subject:   msg.Header.Get("Subject"),
 		From:      msg.Header.Get("From"),
@@ -813,7 +703,7 @@ func (ms *Server) parseMessageInfo(messagePath, folder, filename string, isNew b
 }
 
 // parseMaildirFlags parses maildir flags from filename
-func (ms *Server) parseMaildirFlags(filename string, isNew bool) []string {
+func (maildir *MaildirOperations) parseMaildirFlags(filename string, isNew bool) []string {
 	var flags []string
 
 	if isNew {
@@ -850,7 +740,7 @@ func (ms *Server) parseMaildirFlags(filename string, isNew bool) []string {
 }
 
 // parseReferences parses References header for email threading
-func (ms *Server) parseReferences(referencesStr string) []string {
+func (maildir *MaildirOperations) parseReferences(referencesStr string) []string {
 	if referencesStr == "" {
 		return nil
 	}
@@ -868,17 +758,17 @@ func (ms *Server) parseReferences(referencesStr string) []string {
 }
 
 // generateMessageID generates a unique ID for a message based on its path
-func (ms *Server) generateMessageID(messagePath string) string {
+func (maildir *MaildirOperations) generateMessageID(messagePath string) string {
 	// Use the filename without path as the ID
 	return filepath.Base(messagePath)
 }
 
 // applyMessageFilters applies various filters to messages
-func (ms *Server) applyMessageFilters(messages []MessageInfo, filters map[string]interface{}) []MessageInfo {
+func (maildir *MaildirOperations) applyMessageFilters(messages []MessageInfo, filters map[string]interface{}) []MessageInfo {
 	var filtered []MessageInfo
 
 	for _, msg := range messages {
-		if ms.messageMatchesFilters(msg, filters) {
+		if maildir.messageMatchesFilters(msg, filters) {
 			filtered = append(filtered, msg)
 		}
 	}
@@ -887,7 +777,7 @@ func (ms *Server) applyMessageFilters(messages []MessageInfo, filters map[string
 }
 
 // messageMatchesFilters checks if a message matches the given filters
-func (ms *Server) messageMatchesFilters(msg MessageInfo, filters map[string]interface{}) bool {
+func (maildir *MaildirOperations) messageMatchesFilters(msg MessageInfo, filters map[string]interface{}) bool {
 	// Date range filter
 	if dateFromStr, ok := filters["date_from"].(string); ok {
 		if dateFrom, err := time.Parse("2006-01-02", dateFromStr); err == nil {
@@ -937,9 +827,9 @@ func (ms *Server) messageMatchesFilters(msg MessageInfo, filters map[string]inte
 }
 
 // readMessage reads a full message with content
-func (ms *Server) readMessage(maildirPath, messageID string, includeHTML, includeHeaders, sanitizeContent bool) (*Message, error) {
+func (maildir *MaildirOperations) readMessage(maildirPath, messageID string, includeHTML, includeHeaders, sanitizeContent bool) (*Message, error) {
 	// Find the message file
-	messagePath, err := ms.findMessagePath(maildirPath, messageID)
+	messagePath, err := maildir.findMessagePath(maildirPath, messageID)
 	if err != nil {
 		return nil, err
 	}
@@ -963,23 +853,23 @@ func (ms *Server) readMessage(maildirPath, messageID string, includeHTML, includ
 	}
 
 	// Parse basic message info
-	folder := ms.extractFolderFromPath(messagePath)
+	folder := maildir.extractFolderFromPath(messagePath)
 	isNew := strings.Contains(messagePath, "/new/")
-	messageInfo, err := ms.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
+	messageInfo, err := maildir.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
 	if err != nil {
 		return nil, err
 	}
 
 	// Extract message body
-	body, htmlBody, err := ms.extractMessageBody(msg, includeHTML)
+	body, htmlBody, err := maildir.extractMessageBody(msg, includeHTML)
 	if err != nil {
 		return nil, err
 	}
 
 	if sanitizeContent {
-		body = ms.sanitizeContent(body)
+		body = maildir.sanitizeContent(body)
 		if htmlBody != "" {
-			htmlBody = ms.sanitizeContent(htmlBody)
+			htmlBody = maildir.sanitizeContent(htmlBody)
 		}
 	}
 
@@ -993,7 +883,7 @@ func (ms *Server) readMessage(maildirPath, messageID string, includeHTML, includ
 }
 
 // findMessagePath finds the full path to a message file by ID
-func (ms *Server) findMessagePath(maildirPath, messageID string) (string, error) {
+func (maildir *MaildirOperations) findMessagePath(maildirPath, messageID string) (string, error) {
 	var foundPath string
 
 	err := filepath.Walk(maildirPath, func(path string, info os.FileInfo, err error) error {
@@ -1021,7 +911,7 @@ func (ms *Server) findMessagePath(maildirPath, messageID string) (string, error)
 }
 
 // extractFolderFromPath extracts folder name from message path
-func (ms *Server) extractFolderFromPath(messagePath string) string {
+func (maildir *MaildirOperations) extractFolderFromPath(messagePath string) string {
 	// Navigate up from the message file to find the folder
 	dir := filepath.Dir(messagePath) // cur or new directory
 	dir = filepath.Dir(dir)          // folder directory
@@ -1029,7 +919,7 @@ func (ms *Server) extractFolderFromPath(messagePath string) string {
 }
 
 // extractMessageBody extracts plain text and HTML body from message
-func (ms *Server) extractMessageBody(msg *mail.Message, includeHTML bool) (string, string, error) {
+func (maildir *MaildirOperations) extractMessageBody(msg *mail.Message, includeHTML bool) (string, string, error) {
 	contentType := msg.Header.Get("Content-Type")
 	
 	if contentType == "" {
@@ -1065,7 +955,7 @@ func (ms *Server) extractMessageBody(msg *mail.Message, includeHTML bool) (strin
 			return "", "", err
 		}
 		htmlBody := string(body)
-		plainBody := ms.htmlToPlainText(htmlBody)
+		plainBody := maildir.htmlToPlainText(htmlBody)
 		if includeHTML {
 			return plainBody, htmlBody, nil
 		}
@@ -1073,7 +963,7 @@ func (ms *Server) extractMessageBody(msg *mail.Message, includeHTML bool) (strin
 	}
 
 	if strings.HasPrefix(mediaType, "multipart/") {
-		return ms.extractMultipartBody(msg.Body, params["boundary"], includeHTML)
+		return maildir.extractMultipartBody(msg.Body, params["boundary"], includeHTML)
 	}
 
 	// Fallback to reading as plain text
@@ -1085,7 +975,7 @@ func (ms *Server) extractMessageBody(msg *mail.Message, includeHTML bool) (strin
 }
 
 // extractMultipartBody extracts body from multipart message
-func (ms *Server) extractMultipartBody(body io.Reader, boundary string, includeHTML bool) (string, string, error) {
+func (maildir *MaildirOperations) extractMultipartBody(body io.Reader, boundary string, includeHTML bool) (string, string, error) {
 	mr := multipart.NewReader(body, boundary)
 	
 	var plainBody, htmlBody string
@@ -1117,7 +1007,7 @@ func (ms *Server) extractMultipartBody(body io.Reader, boundary string, includeH
 
 	// If we only have HTML, convert it to plain text
 	if plainBody == "" && htmlBody != "" {
-		plainBody = ms.htmlToPlainText(htmlBody)
+		plainBody = maildir.htmlToPlainText(htmlBody)
 	}
 
 	if includeHTML {
@@ -1127,7 +1017,7 @@ func (ms *Server) extractMultipartBody(body io.Reader, boundary string, includeH
 }
 
 // htmlToPlainText converts HTML to plain text (simple implementation)
-func (ms *Server) htmlToPlainText(html string) string {
+func (maildir *MaildirOperations) htmlToPlainText(html string) string {
 	// Simple HTML to text conversion - remove tags
 	re := regexp.MustCompile(`<[^>]*>`)
 	text := re.ReplaceAllString(html, "")
@@ -1144,7 +1034,7 @@ func (ms *Server) htmlToPlainText(html string) string {
 }
 
 // sanitizeContent sanitizes message content (basic implementation)
-func (ms *Server) sanitizeContent(content string) string {
+func (maildir *MaildirOperations) sanitizeContent(content string) string {
 	// Basic PII masking - this is a simple implementation
 	// In production, you'd want more sophisticated PII detection
 	
@@ -1160,12 +1050,12 @@ func (ms *Server) sanitizeContent(content string) string {
 }
 
 // searchMessages performs full-text search across messages
-func (ms *Server) searchMessages(maildirPath, query string, limit int, filters map[string]interface{}) ([]MessageInfo, error) {
+func (maildir *MaildirOperations) searchMessages(maildirPath, query string, limit int, filters map[string]interface{}) ([]MessageInfo, error) {
 	var results []MessageInfo
 	
 	// Simple implementation - scan all messages and search in subject/from/body
 	err := filepath.Walk(maildirPath, func(path string, info os.FileInfo, err error) error {
-		if err != nil || info.IsDir() || !ms.isMaildirMessage(info.Name()) {
+		if err != nil || info.IsDir() || !maildir.isMaildirMessage(info.Name()) {
 			return nil
 		}
 
@@ -1174,7 +1064,7 @@ func (ms *Server) searchMessages(maildirPath, query string, limit int, filters m
 			return nil
 		}
 
-		matches, messageInfo := ms.searchInMessage(path, query)
+		matches, messageInfo := maildir.searchInMessage(path, query)
 		if matches {
 			results = append(results, messageInfo)
 		}
@@ -1200,16 +1090,16 @@ func (ms *Server) searchMessages(maildirPath, query string, limit int, filters m
 }
 
 // searchInMessage searches for query in a specific message
-func (ms *Server) searchInMessage(messagePath, query string) (bool, MessageInfo) {
+func (maildir *MaildirOperations) searchInMessage(messagePath, query string) (bool, MessageInfo) {
 	file, err := os.Open(messagePath)
 	if err != nil {
 		return false, MessageInfo{}
 	}
 	defer file.Close()
 
-	folder := ms.extractFolderFromPath(messagePath)
+	folder := maildir.extractFolderFromPath(messagePath)
 	isNew := strings.Contains(messagePath, "/new/")
-	messageInfo, err := ms.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
+	messageInfo, err := maildir.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
 	if err != nil {
 		return false, MessageInfo{}
 	}
@@ -1230,7 +1120,7 @@ func (ms *Server) searchInMessage(messagePath, query string) (bool, MessageInfo)
 		return false, messageInfo
 	}
 
-	body, _, err := ms.extractMessageBody(msg, false)
+	body, _, err := maildir.extractMessageBody(msg, false)
 	if err != nil {
 		return false, messageInfo
 	}
@@ -1243,16 +1133,16 @@ func (ms *Server) searchInMessage(messagePath, query string) (bool, MessageInfo)
 }
 
 // getThread retrieves email thread for a message
-func (ms *Server) getThread(maildirPath, messageID string, maxDepth int) ([]MessageInfo, error) {
+func (maildir *MaildirOperations) getThread(maildirPath, messageID string, maxDepth int) ([]MessageInfo, error) {
 	// Find the starting message
-	messagePath, err := ms.findMessagePath(maildirPath, messageID)
+	messagePath, err := maildir.findMessagePath(maildirPath, messageID)
 	if err != nil {
 		return nil, err
 	}
 
-	folder := ms.extractFolderFromPath(messagePath)
+	folder := maildir.extractFolderFromPath(messagePath)
 	isNew := strings.Contains(messagePath, "/new/")
-	startMessage, err := ms.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
+	startMessage, err := maildir.parseMessageInfo(messagePath, folder, filepath.Base(messagePath), isNew)
 	if err != nil {
 		return nil, err
 	}
@@ -1267,11 +1157,11 @@ func (ms *Server) getThread(maildirPath, messageID string, maxDepth int) ([]Mess
 }
 
 // analyzeContacts analyzes contact information from messages
-func (ms *Server) analyzeContacts(maildirPath string, filters map[string]interface{}) ([]ContactInfo, error) {
+func (maildir *MaildirOperations) analyzeContacts(maildirPath string, filters map[string]interface{}) ([]ContactInfo, error) {
 	contactMap := make(map[string]*ContactInfo)
 
 	err := filepath.Walk(maildirPath, func(path string, info os.FileInfo, err error) error {
-		if err != nil || info.IsDir() || !ms.isMaildirMessage(info.Name()) {
+		if err != nil || info.IsDir() || !maildir.isMaildirMessage(info.Name()) {
 			return nil
 		}
 
@@ -1280,23 +1170,23 @@ func (ms *Server) analyzeContacts(maildirPath string, filters map[string]interfa
 			return nil
 		}
 
-		folder := ms.extractFolderFromPath(path)
+		folder := maildir.extractFolderFromPath(path)
 		isNew := strings.Contains(path, "/new/")
-		messageInfo, err := ms.parseMessageInfo(path, folder, filepath.Base(path), isNew)
+		messageInfo, err := maildir.parseMessageInfo(path, folder, filepath.Base(path), isNew)
 		if err != nil {
 			return nil
 		}
 
 		// Process From address
 		if messageInfo.From != "" {
-			ms.processContact(contactMap, messageInfo.From, messageInfo.Date, false)
+			maildir.processContact(contactMap, messageInfo.From, messageInfo.Date, false)
 		}
 
 		// Process To addresses
 		if messageInfo.To != "" {
 			toAddresses := strings.Split(messageInfo.To, ",")
 			for _, addr := range toAddresses {
-				ms.processContact(contactMap, strings.TrimSpace(addr), messageInfo.Date, true)
+				maildir.processContact(contactMap, strings.TrimSpace(addr), messageInfo.Date, true)
 			}
 		}
 
@@ -1321,7 +1211,7 @@ func (ms *Server) analyzeContacts(maildirPath string, filters map[string]interfa
 }
 
 // processContact processes a contact address for analysis
-func (ms *Server) processContact(contactMap map[string]*ContactInfo, address string, date time.Time, isOutgoing bool) {
+func (maildir *MaildirOperations) processContact(contactMap map[string]*ContactInfo, address string, date time.Time, isOutgoing bool) {
 	// Extract email address from "Name <email>" format
 	addr, err := mail.ParseAddress(address)
 	if err != nil {
@@ -1362,7 +1252,7 @@ func (ms *Server) processContact(contactMap map[string]*ContactInfo, address str
 }
 
 // getStatistics generates maildir usage statistics
-func (ms *Server) getStatistics(maildirPath string, filters map[string]interface{}) (map[string]interface{}, error) {
+func (maildir *MaildirOperations) getStatistics(maildirPath string, filters map[string]interface{}) (map[string]interface{}, error) {
 	stats := make(map[string]interface{})
 	
 	// Basic statistics implementation
@@ -1371,7 +1261,7 @@ func (ms *Server) getStatistics(maildirPath string, filters map[string]interface
 	folderCounts := make(map[string]int)
 
 	err := filepath.Walk(maildirPath, func(path string, info os.FileInfo, err error) error {
-		if err != nil || info.IsDir() || !ms.isMaildirMessage(info.Name()) {
+		if err != nil || info.IsDir() || !maildir.isMaildirMessage(info.Name()) {
 			return nil
 		}
 
@@ -1383,7 +1273,7 @@ func (ms *Server) getStatistics(maildirPath string, filters map[string]interface
 		totalMessages++
 		totalSize += info.Size()
 
-		folder := ms.extractFolderFromPath(path)
+		folder := maildir.extractFolderFromPath(path)
 		folderCounts[folder]++
 
 		return nil