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";

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv1.0.0

TDQS

B3.2/5.0
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 only says 'Get popular reviews' without explaining pagination behavior (max_idx, synckey), how 'popular' is determined, required authentication, or error handling.

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

Conciseness3/5

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

The description is a single sentence, which is concise but lacks necessary behavioral context. While it is not verbose, it under-specifies the tool's behavior, making it merely adequate.

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?

The tool has 4 parameters with pagination and no output schema. The description does not explain the pagination mechanism, the sorting order of reviews, or potential error conditions. Given no annotations, the description is insufficient for complete understanding.

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. The tool description adds no additional meaning beyond what the schema provides, meeting the baseline for high coverage.

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

Purpose5/5

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

The description clearly states 'Get popular reviews for a specific book', identifying the action (get), resource (popular reviews), and scope (for a specific book). This distinguishes it from sibling tools like get_book_notes_and_highlights or get_bookshelf.

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

Usage Guidelines3/5

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

There is no explicit guidance on when to use this tool versus alternatives. The description only implies usage when popular reviews are needed, but does not mention exclusions or compare to siblings.

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

Deploy Server

Other Tools

Related Tools