Commit 92301f3

mo khan <mo@mokhan.ca>
2025-06-25 03:32:10
fix: resolve IMAP deadlock and enhance security documentation
Bug Fixes: - Fixed deadlock in imap_list_folders by collecting mailbox list before status queries - Resolves goroutine deadlock when calling client.Select() during List() operation Security Enhancements: - Added comprehensive Claude Code configuration examples to --help - Enhanced security warnings about command-line password visibility - Clear guidance on environment variables vs CLI arguments - Documented both secure (env vars) and less secure (CLI args) approaches Documentation: - Updated help text with production-ready configuration examples - Added security notes about process list visibility - Maintains backward compatibility while promoting secure practices Testing: - Live tested with Gmail account mo.khan@gmail.com - Verified folder listing (21 folders), message listing, and search functionality - All 8 tools working correctly with real IMAP server 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 72e0f51
Changed files (2)
cmd
pkg
cmd/imap/main.go
@@ -72,9 +72,35 @@ func main() {
 		fmt.Println("  export IMAP_PASSWORD=app-password")
 		fmt.Println("  mcp-imap")
 		fmt.Println()
+		fmt.Println("CLAUDE CODE CONFIGURATION:")
+		fmt.Println("  # Recommended: Use environment variables for security")
+		fmt.Println("  {")
+		fmt.Println("    \"mcpServers\": {")
+		fmt.Println("      \"imap\": {")
+		fmt.Println("        \"command\": \"/usr/local/bin/mcp-imap\",")
+		fmt.Println("        \"env\": {")
+		fmt.Println("          \"IMAP_SERVER\": \"imap.gmail.com\",")
+		fmt.Println("          \"IMAP_USERNAME\": \"user@gmail.com\",")
+		fmt.Println("          \"IMAP_PASSWORD\": \"app-password\"")
+		fmt.Println("        }")
+		fmt.Println("      }")
+		fmt.Println("    }")
+		fmt.Println("  }")
+		fmt.Println()
+		fmt.Println("  # Alternative: Command-line arguments (less secure)")
+		fmt.Println("  {")
+		fmt.Println("    \"mcpServers\": {")
+		fmt.Println("      \"imap\": {")
+		fmt.Println("        \"command\": \"/usr/local/bin/mcp-imap\",")
+		fmt.Println("        \"args\": [\"--server\", \"imap.gmail.com\", \"--username\", \"user@gmail.com\", \"--password\", \"app-password\"]")
+		fmt.Println("      }")
+		fmt.Println("    }")
+		fmt.Println("  }")
+		fmt.Println()
 		fmt.Println("SECURITY NOTES:")
 		fmt.Println("  - Use app passwords for Gmail (not your main password)")
-		fmt.Println("  - Consider using environment variables for credentials")
+		fmt.Println("  - Prefer environment variables over command-line arguments")
+		fmt.Println("  - Command-line passwords are visible in process lists")
 		fmt.Println("  - All connections use TLS encryption by default")
 		fmt.Println("  - Credentials are not logged or stored persistently")
 		return
pkg/imap/server.go
@@ -163,10 +163,26 @@ func (s *Server) handleListFolders(req mcp.CallToolRequest) (mcp.CallToolResult,
 		done <- client.List("", "*", mailboxes)
 	}()
 
-	var folders []FolderInfo
+	var mailboxList []*imap.MailboxInfo
 	for m := range mailboxes {
+		mailboxList = append(mailboxList, m)
+	}
+
+	if err := <-done; err != nil {
+		return mcp.NewToolError(fmt.Sprintf("Failed to list folders: %v", err)), nil
+	}
+
+	var folders []FolderInfo
+	for _, m := range mailboxList {
 		mbox, err := client.Select(m.Name, true)
 		if err != nil {
+			// Add folder without stats if we can't select it
+			folders = append(folders, FolderInfo{
+				Name:     m.Name,
+				Messages: 0,
+				Recent:   0,
+				Unseen:   0,
+			})
 			continue
 		}
 
@@ -178,10 +194,6 @@ func (s *Server) handleListFolders(req mcp.CallToolRequest) (mcp.CallToolResult,
 		})
 	}
 
-	if err := <-done; err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to list folders: %v", err)), nil
-	}
-
 	result, _ := json.Marshal(folders)
 	return mcp.CallToolResult{
 		Content: []mcp.Content{mcp.TextContent{Type: "text", Text: string(result)}},