Skip to main content
Glama

Readwise MCP Server

by IAmAlexander
search-prompt.ts4.84 kB
import { BaseMCPPrompt } from '../mcp/registry/base-prompt.js'; import { ReadwiseAPI } from '../api/readwise-api.js'; import { SearchParams } from '../types/index.js'; import { ValidationResult, validateRequired, validateNumberRange } from '../types/validation.js'; import type { Logger } from '../utils/logger-interface.js'; import type { MCPResponse } from '../mcp/types.js'; /** * Parameters for the ReadwiseSearchPrompt */ export interface ReadwiseSearchPromptParams extends SearchParams { /** * Optional context to include in the prompt */ context?: string; } /** * Prompt for searching highlights in Readwise */ export class ReadwiseSearchPrompt extends BaseMCPPrompt<ReadwiseSearchPromptParams, MCPResponse> { /** * The name of the prompt */ readonly name = 'readwise_search'; /** * The description of the prompt */ readonly description = 'Searches and analyzes highlights from Readwise'; /** * The parameters for the prompt */ readonly parameters = { type: 'object', properties: { query: { type: 'string', description: 'Search query to find highlights' }, limit: { type: 'number', description: 'Maximum number of results to return' }, context: { type: 'string', description: 'Additional context to include in the prompt' } }, required: ['query'] }; /** * Create a new ReadwiseSearchPrompt * @param api - The ReadwiseAPI instance to use * @param logger - The logger instance */ constructor(private api: ReadwiseAPI, logger: Logger) { super(logger); } /** * Validate the parameters */ validate(params: ReadwiseSearchPromptParams): ValidationResult { const requiredValidation = validateRequired(params, 'query', 'Search query is required'); if (!requiredValidation.valid) { return requiredValidation; } return validateNumberRange(params, 'limit', 1, undefined, 'Limit must be a positive number'); } /** * Execute the prompt */ async execute(params: ReadwiseSearchPromptParams): Promise<MCPResponse> { this.logger.debug('Executing ReadwiseSearchPrompt', { params } as any); if (!params.query) { this.logger.warn('Missing required search query parameter'); throw new Error('Search query is required'); } try { // Search for highlights in Readwise const searchResults = await this.api.searchHighlights({ query: params.query, limit: params.limit || 10 }); if (searchResults.length === 0) { this.logger.warn('No search results found', { query: params.query } as any); throw new Error(`No results found for search query: "${params.query}". Try a different search term.`); } // Format search results as structured content const formattedResults = searchResults.map((result, index) => { return `${index + 1}. "${result.highlight.text}"${result.highlight.note ? ` - Note: ${result.highlight.note}` : ''}\n Source: ${result.book.title || 'Unknown'} by ${result.book.author || 'Unknown Author'}`; }).join('\n\n'); // Build the message content let messageContent = `Here are search results from your Readwise library for query "${params.query}":\n\n${formattedResults}\n\nThese highlights matched your search criteria. Would you like me to analyze them, summarize key points, or help you find connections between them?`; // Include custom context if provided if (params.context) { messageContent = `${params.context}\n\n${messageContent}`; } this.logger.debug('Successfully generated search results prompt', { query: params.query, resultCount: searchResults.length } as any); // Return MCPResponse return { content: [ { type: 'text', text: messageContent } ] }; } catch (error) { // Log the error details this.logger.error('Error executing ReadwiseSearchPrompt', error as any); if (error instanceof Error) { if (error.message.includes('No results found')) { throw error; } if (error.message.includes('401')) { throw new Error('Authentication failed. Please check your Readwise API key.'); } else if (error.message.includes('429')) { throw new Error('Rate limit exceeded. Please try again later.'); } else if (error.message.includes('5')) { throw new Error('Readwise service error. Please try again later.'); } throw new Error(`Failed to search highlights: ${error.message}`); } throw new Error('An unexpected error occurred while searching highlights.'); } } }

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