Skip to main content
Glama

Readwise MCP Server

by IAmAlexander
get-books.ts3.64 kB
// Runtime imports import { BaseMCPTool } from '../mcp/registry/base-tool.js'; import { ReadwiseAPI } from '../api/readwise-api.js'; import type { Logger } from '../utils/logger-interface.js'; import { validateNumberRange } from '../types/validation.js'; import { isAPIError } from '../types/guards.js'; // Type imports import type { PaginatedResponse, Book, MCPToolResult } from '../types/index.js'; import type { ValidationResult } from '../types/validation.js'; /** * Parameters for the GetBooksTool */ export interface GetBooksParams { /** * Page number to retrieve */ page?: number; /** * Number of items per page */ page_size?: number; } /** * Tool to get books from Readwise API */ export class GetBooksTool extends BaseMCPTool<GetBooksParams, PaginatedResponse<Book>> { /** * Tool name */ name = 'get_books'; /** * Tool description */ description = 'Get a list of books from Readwise'; /** * JSON Schema for the parameters */ parameters = { type: 'object', properties: { page: { type: 'number', description: 'Page number to retrieve' }, page_size: { type: 'number', description: 'Number of items per page (max 100)' } } }; /** * Constructor * @param api - Readwise API client * @param logger - Logger instance */ constructor(private api: ReadwiseAPI, logger: Logger) { super(logger); } /** * Validate the parameters * @param params - The parameters to validate * @returns Validation result */ validate(params: GetBooksParams): ValidationResult { // Nothing to validate if no parameters provided if (!params.page && !params.page_size) { return super.validate(params); } const validations: ValidationResult[] = []; // Only validate page if provided if (params.page !== undefined) { validations.push(validateNumberRange(params, 'page', 1, undefined, 'Page must be a positive number')); } // Only validate page_size if provided if (params.page_size !== undefined) { validations.push(validateNumberRange(params, 'page_size', 1, 100, 'Page size must be a number between 1 and 100')); } // If validations array is empty, return success if (validations.length === 0) { return super.validate(params); } // Check each validation result for (const validation of validations) { if (validation && !validation.valid) { return validation; } } // All validations passed return super.validate(params); } /** * Execute the tool * @param params - The parameters to use for execution * @returns Promise resolving to an object with a result property containing books */ async execute(params: GetBooksParams): Promise<MCPToolResult<PaginatedResponse<Book>>> { try { this.logger.debug('Executing get_books tool', params as any); const books = await this.api.getBooks({ page: params.page, page_size: params.page_size }); this.logger.debug(`Retrieved ${books.results.length} books`); return { result: books }; } catch (error) { this.logger.error('Error executing get_books tool', error as any); if (isAPIError(error)) { throw error; } this.logger.error('Error fetching books from Readwise API', { error } as any); return { result: { count: 0, next: null, previous: null, results: [] }, success: false, error: 'An unexpected error occurred while fetching books' }; } } }

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/IAmAlexander/readwise-mcp'

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