Skip to main content
Glama
edricgsh

Readwise Reader MCP Server

by edricgsh

readwise_list_documents

Retrieve documents from Readwise Reader with filtering options for location, category, tags, and date ranges to organize your saved content.

Instructions

List documents from Readwise Reader with optional filtering

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNoFilter by specific document ID
updatedAfterNoFilter documents updated after this date (ISO 8601)
addedAfterNoFilter documents added after this date (ISO 8601). Note: This will fetch all documents first and then filter client-side.
locationNoFilter by document location
categoryNoFilter by document category
tagNoFilter by tag name
pageCursorNoPage cursor for pagination
withHtmlContentNo⚠️ PERFORMANCE WARNING: Include HTML content in the response. This significantly slows down the API. Only use when explicitly requested by the user or when raw HTML is specifically needed for the task.
withFullContentNo⚠️ PERFORMANCE WARNING: Include full converted text content in the response. This significantly slows down the API as it fetches and processes each document's content. Only use when explicitly requested by the user or when document content is specifically needed for analysis/reading. Default: false for performance.

Implementation Reference

  • The handleListDocuments function implements the core logic for the readwise_list_documents tool. It initializes the Readwise client, handles filtering (including client-side for addedAfter), pagination, fetches documents, optionally converts content to text or includes HTML, and formats the response.
    export async function handleListDocuments(args: any) { const client = initializeClient(); const params = args as ListDocumentsParams; // If withFullContent is true, we also need HTML content if (params.withFullContent === true) { params.withHtmlContent = true; } let response; let clientSideFiltered = false; // If addedAfter is specified, we need to fetch all documents and filter client-side if (params.addedAfter) { clientSideFiltered = true; const addedAfterDate = new Date(params.addedAfter); // Create params without addedAfter for the API call const apiParams = { ...params }; delete apiParams.addedAfter; // Fetch all documents if no other pagination is specified if (!apiParams.pageCursor && !apiParams.limit) { const allDocuments: any[] = []; let nextPageCursor: string | undefined; do { const fetchParams = { ...apiParams }; if (nextPageCursor) { fetchParams.pageCursor = nextPageCursor; } const pageResponse = await client.listDocuments(fetchParams); allDocuments.push(...pageResponse.data.results); nextPageCursor = pageResponse.data.nextPageCursor; } while (nextPageCursor); // Filter documents by addedAfter date const filteredDocuments = allDocuments.filter(doc => { if (!doc.saved_at) return false; const savedDate = new Date(doc.saved_at); return savedDate > addedAfterDate; }); response = { data: { count: filteredDocuments.length, nextPageCursor: undefined, results: filteredDocuments }, messages: [] }; } else { // If pagination is specified, just do a regular API call and filter the current page response = await client.listDocuments(apiParams); const filteredDocuments = response.data.results.filter(doc => { if (!doc.saved_at) return false; const savedDate = new Date(doc.saved_at); return savedDate > addedAfterDate; }); response.data.results = filteredDocuments; response.data.count = filteredDocuments.length; } } else { response = await client.listDocuments(params); } // Convert content to LLM-friendly text for documents only if withFullContent is explicitly true const shouldIncludeContent = params.withFullContent === true; // Default to false for performance const documentsWithText = await Promise.all( response.data.results.map(async (doc) => { let content = ''; if (shouldIncludeContent) { // Try to use HTML content first (from Readwise), fallback to URL fetching if (doc.html_content) { // Use HTML content from Readwise for non-jina content types const shouldUseJina = !doc.category || doc.category === 'article' || doc.category === 'pdf'; if (shouldUseJina) { const urlToConvert = doc.source_url || doc.url; if (urlToConvert) { content = await convertUrlToText(urlToConvert, doc.category); } } else { content = extractTextFromHtml(doc.html_content); } } else { // Fallback to URL fetching if no HTML content available const urlToConvert = doc.source_url || doc.url; if (urlToConvert) { content = await convertUrlToText(urlToConvert, doc.category); } } } const result: any = { id: doc.id, url: doc.url, title: doc.title, author: doc.author, source: doc.source, category: doc.category, location: doc.location, tags: doc.tags, site_name: doc.site_name, word_count: doc.word_count, created_at: doc.created_at, updated_at: doc.updated_at, published_date: doc.published_date, summary: doc.summary, image_url: doc.image_url, source_url: doc.source_url, notes: doc.notes, parent_id: doc.parent_id, reading_progress: doc.reading_progress, first_opened_at: doc.first_opened_at, last_opened_at: doc.last_opened_at, saved_at: doc.saved_at, last_moved_at: doc.last_moved_at, }; if (shouldIncludeContent) { result.content = content; // LLM-friendly text content instead of raw HTML } if (params.withHtmlContent && doc.html_content) { result.html_content = doc.html_content; } return result; }) ); let responseText = JSON.stringify({ count: response.data.count, nextPageCursor: response.data.nextPageCursor, documents: documentsWithText }, null, 2); let allMessages = response.messages || []; // Add message about client-side filtering if it was performed if (clientSideFiltered) { allMessages.push({ type: 'info', content: 'Documents were filtered client-side based on the addedAfter date. All documents were fetched from the API first, then filtered by their saved_at date.' }); } if (allMessages.length > 0) { responseText += '\n\nMessages:\n' + allMessages.map(msg => `${msg.type.toUpperCase()}: ${msg.content}`).join('\n'); } return { content: [ { type: 'text', text: responseText, }, ], }; }
  • Defines the tool metadata including name, description, and detailed inputSchema with parameters like addedAfter, withFullContent, etc., for the readwise_list_documents tool.
    { name: 'readwise_list_documents', description: 'List documents from Readwise Reader with optional filtering', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Filter by specific document ID', }, updatedAfter: { type: 'string', description: 'Filter documents updated after this date (ISO 8601)', }, addedAfter: { type: 'string', description: 'Filter documents added after this date (ISO 8601). Note: This will fetch all documents first and then filter client-side.', }, location: { type: 'string', enum: ['new', 'later', 'shortlist', 'archive', 'feed'], description: 'Filter by document location', }, category: { type: 'string', enum: ['article', 'book', 'tweet', 'pdf', 'email', 'youtube', 'podcast'], description: 'Filter by document category', }, tag: { type: 'string', description: 'Filter by tag name', }, pageCursor: { type: 'string', description: 'Page cursor for pagination', }, withHtmlContent: { type: 'boolean', description: '⚠️ PERFORMANCE WARNING: Include HTML content in the response. This significantly slows down the API. Only use when explicitly requested by the user or when raw HTML is specifically needed for the task.', }, withFullContent: { type: 'boolean', description: '⚠️ PERFORMANCE WARNING: Include full converted text content in the response. This significantly slows down the API as it fetches and processes each document\'s content. Only use when explicitly requested by the user or when document content is specifically needed for analysis/reading. Default: false for performance.', }, }, additionalProperties: false, }, },
  • Registers the 'readwise_list_documents' tool name in the switch statement, dispatching to the handleListDocuments function.
    case 'readwise_list_documents': return handleListDocuments(args);

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/edricgsh/Readwise-Reader-MCP'

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