Skip to main content
Glama
freestylefly

WeRead MCP Server

by freestylefly

get_book_best_reviews

Retrieve top-rated reviews for any book by specifying its ID and the desired number of reviews. Supports pagination for accessing additional results.

Instructions

Get popular reviews for a specific book

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
book_idYesBook ID
countNoNumber of reviews to return
max_idxNoPagination index
synckeyNoSync key for pagination

Implementation Reference

  • Main handler for get_book_best_reviews tool: validates input, fetches book info and best reviews, processes review data (ratings, filtering), formats and returns JSON response.
    case "get_book_best_reviews": {
      const bookId = String(request.params.arguments?.book_id || "");
      const count = Number(request.params.arguments?.count || 10);
      const maxIdx = Number(request.params.arguments?.max_idx || 0);
      const synckey = Number(request.params.arguments?.synckey || 0);
      
      if (!bookId) {
        throw new Error("书籍ID不能为空");
      }
      
      // 1. 获取书籍信息
      const bookInfo = await wereadApi.getBookinfo(bookId);
      
      // 2. 获取热门书评
      const bestReviewsData = await wereadApi.getBestReviews(bookId, count, maxIdx, synckey);
      
      // 控制台打印原始返回数据,方便调试
      // console.error("热门书评原始数据:", JSON.stringify(bestReviewsData, null, 2));
      
      // 3. 提取基础数据
      const hasMore = bestReviewsData.reviewsHasMore || false;
      const syncKey = bestReviewsData.synckey || 0;
      const totalCount = bestReviewsData.reviewsCnt || 0;
      
      // 4. 处理每条书评 - 根据接口确切的数据结构
      let processedReviews: any[] = [];
      
      if (bestReviewsData.reviews && Array.isArray(bestReviewsData.reviews)) {
        processedReviews = bestReviewsData.reviews
          .filter((item: any) => {
            return item && item.review && item.review.review;
          })
          .map((item: any) => {
            const reviewContainer = item.review; // {reviewId, review}
            const review = reviewContainer.review; // 实际评论内容
            const author = review.author || {};
            
            // 仅处理有内容的评论
            if (!review.content && !review.htmlContent) {
              return null;
            }
            
            // 处理评分 - 实际返回示例中用star表示评分(0-100)
            let rating = 0;
            if (review.star) {
              rating = review.star / 20; // 转换为5分制
            } else if (review.newRatingLevel) {
              // 有些评论用newRatingLevel表示评分级别
              switch(review.newRatingLevel) {
                case 1: rating = 5; break; // "好看"
                case 2: rating = 3; break; // "一般"
                case 3: rating = 1; break; // "不行"
                default: rating = 0;
              }
            }
            
            // 构建评论对象
            return {
              review_id: reviewContainer.reviewId || "",
              content: review.content || review.htmlContent || "",
              rating: rating,
              likes: review.liked || reviewContainer.likesCount || 0,
              comments: review.comments || 0,
              created_time: review.createTime ? new Date(review.createTime * 1000).toISOString() : "",
              //user_id: author.userVid || "",
              author_nickname: author.name || "",
              //avatar_url: author.avatar || ""
              is_spoiler: !!review.notVisibleToFriends,
              is_top: item.idx === 1 || !!item.isTop // 置顶评论判断
            };
          })
          .filter(Boolean); // 过滤掉null值
      }
      
      // 5. 返回结果
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            book_id: bookId,
            book_title: bookInfo.title || "",
            book_author: bookInfo.author || "",
            total_reviews: totalCount,
            has_more: hasMore,
            sync_key: syncKey,
            reviews: processedReviews
          }, null, 2)
        }]
      };
    }
  • Tool schema definition including input parameters for book_id (required), count, max_idx, synckey with descriptions and defaults.
    {
      name: "get_book_best_reviews",
      description: "Get popular reviews for a specific book",
      inputSchema: {
        type: "object",
        properties: {
          book_id: {
            type: "string",
            description: "Book ID"
          },
          count: {
            type: "integer",
            description: "Number of reviews to return",
            default: 10
          },
          max_idx: {
            type: "integer",
            description: "Pagination index",
            default: 0
          },
          synckey: {
            type: "integer",
            description: "Sync key for pagination",
            default: 0
          }
        },
        required: ["book_id"]
      }
    },
  • src/index.ts:52-153 (registration)
    Registration of all tools including get_book_best_reviews in the ListToolsRequestHandler response.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "get_bookshelf",
            description: "Get all books in the user's bookshelf with comprehensive statistics and categorization information",
            inputSchema: {
              type: "object",
              properties: {},
              required: []
            }
          },
          {
            name: "search_books",
            description: "Search for books in the user's bookshelf by keywords and return matching books with details and reading progress",
            inputSchema: {
              type: "object",
              properties: {
                keyword: {
                  type: "string",
                  description: "Search keyword to match book title, author, translator or category"
                },
                exact_match: {
                  type: "boolean",
                  description: "Whether to use exact matching, default is fuzzy matching",
                  default: false
                },
                include_details: {
                  type: "boolean",
                  description: "Whether to include detailed information",
                  default: true
                },
                max_results: {
                  type: "integer",
                  description: "Maximum number of results to return",
                  default: 5
                }
              },
              required: ["keyword"]
            }
          },
          {
            name: "get_book_notes_and_highlights",
            description: "Get all highlights and notes for a specific book, organized by chapter",
            inputSchema: {
              type: "object",
              properties: {
                book_id: {
                  type: "string",
                  description: "Book ID"
                },
                include_chapters: {
                  type: "boolean",
                  description: "Whether to include chapter information",
                  default: true
                },
                organize_by_chapter: {
                  type: "boolean",
                  description: "Whether to organize by chapter",
                  default: true
                },
                highlight_style: {
                  type: ["integer", "null"],
                  description: "Highlight style filter, null means all",
                  default: null
                }
              },
              required: ["book_id"]
            }
          },
          {
            name: "get_book_best_reviews",
            description: "Get popular reviews for a specific book",
            inputSchema: {
              type: "object",
              properties: {
                book_id: {
                  type: "string",
                  description: "Book ID"
                },
                count: {
                  type: "integer",
                  description: "Number of reviews to return",
                  default: 10
                },
                max_idx: {
                  type: "integer",
                  description: "Pagination index",
                  default: 0
                },
                synckey: {
                  type: "integer",
                  description: "Sync key for pagination",
                  default: 0
                }
              },
              required: ["book_id"]
            }
          },
        ]
      };
    });
  • Core API method that fetches best reviews from WeRead API endpoint using retry logic and standard request handling.
    public async getBestReviews(bookId: string, count: number = 10, maxIdx: number = 0, synckey: number = 0): Promise<any> {
      await this.ensureInitialized();
      return this.retry(async () => {
        const data = await this.makeApiRequest<any>(WEREAD_BEST_REVIEW_URL, "get", {
          bookId,
          synckey,
          maxIdx,
          count
        });
        
        return data;
      });
    }
  • API endpoint URL constant for fetching best reviews.
    const WEREAD_BEST_REVIEW_URL = "https://weread.qq.com/web/review/list/best";
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions 'popular reviews' but doesn't explain how popularity is determined (e.g., sorting criteria, algorithm). It also omits key behavioral traits like whether this is a read-only operation, potential rate limits, authentication needs, or what the output format looks like (since no output schema exists). The description adds minimal value beyond the basic purpose.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence with zero waste. It's front-loaded with the core purpose ('Get popular reviews for a specific book'), and every word earns its place. There's no redundant or verbose language.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (a tool with 4 parameters, no annotations, and no output schema), the description is incomplete. It doesn't explain behavioral aspects like how 'popular' is defined, pagination mechanics, or return format. With no output schema, the description should ideally hint at what's returned (e.g., list of reviews with ratings), but it doesn't. This leaves significant gaps for an AI agent to use the tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters (book_id, count, max_idx, synckey) with descriptions. The description adds no additional meaning about parameters beyond implying 'book_id' is needed for a specific book. It doesn't clarify parameter interactions (e.g., how max_idx and synckey work together for pagination) or semantics of 'popular' in relation to parameters. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Get') and resource ('popular reviews for a specific book'), making the purpose understandable. It distinguishes from siblings like 'get_book_notes_and_highlights' (which focuses on notes/highlights) and 'search_books' (which searches books rather than reviews). However, it doesn't specify what makes reviews 'popular' (e.g., by rating, helpfulness, recency), which prevents a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention when to choose this over 'get_book_notes_and_highlights' for review-related data, or whether it's preferable for popular reviews versus other review-fetching tools not listed. There's no context about prerequisites, timing, or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freestylefly/mcp-server-weread'

If you have feedback or need assistance with the MCP directory API, please join our Discord server