diff --git a/cookies/cookies.go b/cookies/cookies.go index aa52324..fde7f04 100644 --- a/cookies/cookies.go +++ b/cookies/cookies.go @@ -10,6 +10,7 @@ import ( type Cookier interface { LoadCookies() ([]byte, error) SaveCookies(data []byte) error + DeleteCookies() error } type localCookie struct { @@ -42,6 +43,15 @@ func (c *localCookie) SaveCookies(data []byte) error { return os.WriteFile(c.path, data, 0644) } +// DeleteCookies 删除 cookies 文件。 +func (c *localCookie) DeleteCookies() error { + if _, err := os.Stat(c.path); os.IsNotExist(err) { + // 文件不存在,返回 nil(认为已经删除) + return nil + } + return os.Remove(c.path) +} + // GetCookiesFilePath 获取 cookies 文件路径。 // 为了向后兼容,如果旧路径 /tmp/cookies.json 存在,则继续使用; // 否则使用当前目录下的 cookies.json diff --git a/handlers_api.go b/handlers_api.go index 0dffaca..77b434f 100644 --- a/handlers_api.go +++ b/handlers_api.go @@ -3,6 +3,7 @@ package main import ( "net/http" + "github.com/xpzouying/xiaohongshu-mcp/cookies" "github.com/xpzouying/xiaohongshu-mcp/xiaohongshu" "github.com/gin-gonic/gin" @@ -63,6 +64,22 @@ func (s *AppServer) getLoginQrcodeHandler(c *gin.Context) { respondSuccess(c, result, "获取登录二维码成功") } +// deleteCookiesHandler 删除 cookies,重置登录状态 +func (s *AppServer) deleteCookiesHandler(c *gin.Context) { + err := s.xiaohongshuService.DeleteCookies(c.Request.Context()) + if err != nil { + respondError(c, http.StatusInternalServerError, "DELETE_COOKIES_FAILED", + "删除 cookies 失败", err.Error()) + return + } + + cookiePath := cookies.GetCookiesFilePath() + respondSuccess(c, map[string]interface{}{ + "cookie_path": cookiePath, + "message": "Cookies 已成功删除,登录状态已重置。下次操作时需要重新登录。", + }, "删除 cookies 成功") +} + // publishHandler 发布内容 func (s *AppServer) publishHandler(c *gin.Context) { var req PublishRequest diff --git a/mcp_handlers.go b/mcp_handlers.go index 8e2c032..88c25dc 100644 --- a/mcp_handlers.go +++ b/mcp_handlers.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/sirupsen/logrus" + "github.com/xpzouying/xiaohongshu-mcp/cookies" "github.com/xpzouying/xiaohongshu-mcp/xiaohongshu" "strings" "time" @@ -27,7 +28,14 @@ func (s *AppServer) handleCheckLoginStatus(ctx context.Context) *MCPToolResult { } } - resultText := fmt.Sprintf("登录状态检查成功: %+v", status) + // 根据 IsLoggedIn 判断并返回友好的提示 + var resultText string + if status.IsLoggedIn { + resultText = fmt.Sprintf("✅ 已登录\n用户名: %s\n\n你可以使用其他功能了。", status.Username) + } else { + resultText = fmt.Sprintf("❌ 未登录\n\n请使用 get_login_qrcode 工具获取二维码进行登录。") + } + return &MCPToolResult{ Content: []MCPContent{{ Type: "text", @@ -76,6 +84,28 @@ func (s *AppServer) handleGetLoginQrcode(ctx context.Context) *MCPToolResult { return &MCPToolResult{Content: contents} } +// handleDeleteCookies 处理删除 cookies 请求,用于登录重置 +func (s *AppServer) handleDeleteCookies(ctx context.Context) *MCPToolResult { + logrus.Info("MCP: 删除 cookies,重置登录状态") + + err := s.xiaohongshuService.DeleteCookies(ctx) + if err != nil { + return &MCPToolResult{ + Content: []MCPContent{{Type: "text", Text: "删除 cookies 失败: " + err.Error()}}, + IsError: true, + } + } + + cookiePath := cookies.GetCookiesFilePath() + resultText := fmt.Sprintf("Cookies 已成功删除,登录状态已重置。\n\n删除的文件路径: %s\n\n下次操作时,需要重新登录。", cookiePath) + return &MCPToolResult{ + Content: []MCPContent{{ + Type: "text", + Text: resultText, + }}, + } +} + // handlePublishContent 处理发布内容 func (s *AppServer) handlePublishContent(ctx context.Context, args map[string]interface{}) *MCPToolResult { logrus.Info("MCP: 发布内容") diff --git a/mcp_server.go b/mcp_server.go index 9237059..d72ffb0 100644 --- a/mcp_server.go +++ b/mcp_server.go @@ -153,7 +153,19 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 3: 发布内容 + // 工具 3: 删除 cookies(登录重置) + mcp.AddTool(server, + &mcp.Tool{ + Name: "delete_cookies", + Description: "删除 cookies 文件,重置登录状态。删除后需要重新登录。", + }, + withPanicRecovery("delete_cookies", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) { + result := appServer.handleDeleteCookies(ctx) + return convertToMCPResult(result), nil, nil + }), + ) + + // 工具 4: 发布内容 mcp.AddTool(server, &mcp.Tool{ Name: "publish_content", @@ -172,7 +184,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 4: 获取Feed列表 + // 工具 5: 获取Feed列表 mcp.AddTool(server, &mcp.Tool{ Name: "list_feeds", @@ -184,7 +196,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 5: 搜索内容 + // 工具 6: 搜索内容 mcp.AddTool(server, &mcp.Tool{ Name: "search_feeds", @@ -196,7 +208,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 6: 获取Feed详情 + // 工具 7: 获取Feed详情 mcp.AddTool(server, &mcp.Tool{ Name: "get_feed_detail", @@ -212,7 +224,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 7: 获取用户主页 + // 工具 8: 获取用户主页 mcp.AddTool(server, &mcp.Tool{ Name: "user_profile", @@ -228,7 +240,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 8: 发表评论 + // 工具 9: 发表评论 mcp.AddTool(server, &mcp.Tool{ Name: "post_comment_to_feed", @@ -245,7 +257,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 9: 发布视频(仅本地文件) + // 工具 10: 发布视频(仅本地文件) mcp.AddTool(server, &mcp.Tool{ Name: "publish_with_video", @@ -263,7 +275,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 10: 点赞笔记 + // 工具 11: 点赞笔记 mcp.AddTool(server, &mcp.Tool{ Name: "like_feed", @@ -280,7 +292,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - // 工具 11: 收藏笔记 + // 工具 12: 收藏笔记 mcp.AddTool(server, &mcp.Tool{ Name: "favorite_feed", @@ -297,7 +309,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) { }), ) - logrus.Infof("Registered %d MCP tools", 11) + logrus.Infof("Registered %d MCP tools", 12) } // convertToMCPResult 将自定义的 MCPToolResult 转换为官方 SDK 的格式 diff --git a/routes.go b/routes.go index 58ff566..f8b31ed 100644 --- a/routes.go +++ b/routes.go @@ -40,6 +40,7 @@ func setupRoutes(appServer *AppServer) *gin.Engine { { api.GET("/login/status", appServer.checkLoginStatusHandler) api.GET("/login/qrcode", appServer.getLoginQrcodeHandler) + api.DELETE("/login/cookies", appServer.deleteCookiesHandler) api.POST("/publish", appServer.publishHandler) api.POST("/publish_video", appServer.publishVideoHandler) api.GET("/feeds/list", appServer.listFeedsHandler) diff --git a/service.go b/service.go index 16dc938..cd502fd 100644 --- a/service.go +++ b/service.go @@ -86,6 +86,13 @@ type UserProfileResponse struct { Feeds []xiaohongshu.Feed `json:"feeds"` } +// DeleteCookies 删除 cookies 文件,用于登录重置 +func (s *XiaohongshuService) DeleteCookies(ctx context.Context) error { + cookiePath := cookies.GetCookiesFilePath() + cookieLoader := cookies.NewLoadCookie(cookiePath) + return cookieLoader.DeleteCookies() +} + // CheckLoginStatus 检查登录状态 func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatusResponse, error) { b := newBrowser()