feat: Add tool annotations for improved LLM tool understanding (#347)

Add readOnlyHint and destructiveHint annotations to all 13 tools
to help LLMs better understand tool behavior and make safer decisions.

Changes:
- Added readOnlyHint: true to read-only tools (6 tools):
  check_login_status, get_login_qrcode, list_feeds, search_feeds,
  get_feed_detail, user_profile
- Added destructiveHint: true to destructive tools (7 tools):
  delete_cookies, publish_content, publish_with_video, like_feed,
  favorite_feed, post_comment_to_feed, reply_comment_in_feed
- Added title annotations for human-readable display
- Fixed tool count from 12 to 13 in log statement

This improves tool safety metadata for MCP clients.

Co-authored-by: triepod-ai <noreply@github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Bryan Thompson
2025-12-26 09:26:10 -06:00
committed by GitHub
parent ed6d9c60b3
commit 61eccf1cde

View File

@@ -10,6 +10,9 @@ import (
"github.com/sirupsen/logrus"
)
// Helper functions for annotation pointers
func boolPtr(b bool) *bool { return &b }
// MCP 工具参数结构体定义
// PublishContentArgs 发布内容的参数
@@ -148,6 +151,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "check_login_status",
Description: "检查小红书登录状态",
Annotations: &mcp.ToolAnnotations{
Title: "Check Login Status",
ReadOnlyHint: true,
},
},
withPanicRecovery("check_login_status", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
result := appServer.handleCheckLoginStatus(ctx)
@@ -160,6 +167,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "get_login_qrcode",
Description: "获取登录二维码(返回 Base64 图片和超时时间)",
Annotations: &mcp.ToolAnnotations{
Title: "Get Login QR Code",
ReadOnlyHint: true,
},
},
withPanicRecovery("get_login_qrcode", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
result := appServer.handleGetLoginQrcode(ctx)
@@ -172,6 +183,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "delete_cookies",
Description: "删除 cookies 文件,重置登录状态。删除后需要重新登录。",
Annotations: &mcp.ToolAnnotations{
Title: "Delete Cookies",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("delete_cookies", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
result := appServer.handleDeleteCookies(ctx)
@@ -184,6 +199,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "publish_content",
Description: "发布小红书图文内容",
Annotations: &mcp.ToolAnnotations{
Title: "Publish Content",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("publish_content", func(ctx context.Context, req *mcp.CallToolRequest, args PublishContentArgs) (*mcp.CallToolResult, any, error) {
// 转换参数格式到现有的 handler
@@ -203,6 +222,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "list_feeds",
Description: "获取首页 Feeds 列表",
Annotations: &mcp.ToolAnnotations{
Title: "List Feeds",
ReadOnlyHint: true,
},
},
withPanicRecovery("list_feeds", func(ctx context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
result := appServer.handleListFeeds(ctx)
@@ -215,6 +238,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "search_feeds",
Description: "搜索小红书内容(需要已登录)",
Annotations: &mcp.ToolAnnotations{
Title: "Search Feeds",
ReadOnlyHint: true,
},
},
withPanicRecovery("search_feeds", func(ctx context.Context, req *mcp.CallToolRequest, args SearchFeedsArgs) (*mcp.CallToolResult, any, error) {
result := appServer.handleSearchFeeds(ctx, args)
@@ -227,6 +254,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "get_feed_detail",
Description: "获取小红书笔记详情,返回笔记内容、图片、作者信息、互动数据(点赞/收藏/分享数及评论列表。默认返回前10条一级评论如需更多评论请设置load_all_comments=true",
Annotations: &mcp.ToolAnnotations{
Title: "Get Feed Detail",
ReadOnlyHint: true,
},
},
withPanicRecovery("get_feed_detail", func(ctx context.Context, req *mcp.CallToolRequest, args FeedDetailArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -268,6 +299,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "user_profile",
Description: "获取指定的小红书用户主页,返回用户基本信息,关注、粉丝、获赞量及其笔记内容",
Annotations: &mcp.ToolAnnotations{
Title: "User Profile",
ReadOnlyHint: true,
},
},
withPanicRecovery("user_profile", func(ctx context.Context, req *mcp.CallToolRequest, args UserProfileArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -284,6 +319,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "post_comment_to_feed",
Description: "发表评论到小红书笔记",
Annotations: &mcp.ToolAnnotations{
Title: "Post Comment",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("post_comment_to_feed", func(ctx context.Context, req *mcp.CallToolRequest, args PostCommentArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -301,6 +340,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "reply_comment_in_feed",
Description: "回复小红书笔记下的指定评论",
Annotations: &mcp.ToolAnnotations{
Title: "Reply Comment",
DestructiveHint: boolPtr(true),
},
},
func(ctx context.Context, req *mcp.CallToolRequest, args ReplyCommentArgs) (*mcp.CallToolResult, any, error) {
if args.CommentID == "" && args.UserID == "" {
@@ -327,6 +370,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "publish_with_video",
Description: "发布小红书视频内容(仅支持本地单个视频文件)",
Annotations: &mcp.ToolAnnotations{
Title: "Publish Video",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("publish_with_video", func(ctx context.Context, req *mcp.CallToolRequest, args PublishVideoArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -345,6 +392,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "like_feed",
Description: "为指定笔记点赞或取消点赞(如已点赞将跳过点赞,如未点赞将跳过取消点赞)",
Annotations: &mcp.ToolAnnotations{
Title: "Like Feed",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("like_feed", func(ctx context.Context, req *mcp.CallToolRequest, args LikeFeedArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -362,6 +413,10 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
&mcp.Tool{
Name: "favorite_feed",
Description: "收藏指定笔记或取消收藏(如已收藏将跳过收藏,如未收藏将跳过取消收藏)",
Annotations: &mcp.ToolAnnotations{
Title: "Favorite Feed",
DestructiveHint: boolPtr(true),
},
},
withPanicRecovery("favorite_feed", func(ctx context.Context, req *mcp.CallToolRequest, args FavoriteFeedArgs) (*mcp.CallToolResult, any, error) {
argsMap := map[string]interface{}{
@@ -374,7 +429,7 @@ func registerTools(server *mcp.Server, appServer *AppServer) {
}),
)
logrus.Infof("Registered %d MCP tools", 12)
logrus.Infof("Registered %d MCP tools", 13)
}
// convertToMCPResult 将自定义的 MCPToolResult 转换为官方 SDK 的格式